aboutsummaryrefslogtreecommitdiff
path: root/src/transport/gnunet-service-tng.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/gnunet-service-tng.c')
-rw-r--r--src/transport/gnunet-service-tng.c11152
1 files changed, 0 insertions, 11152 deletions
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c
deleted file mode 100644
index 18ec0aa0b..000000000
--- a/src/transport/gnunet-service-tng.c
+++ /dev/null
@@ -1,11152 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2016, 2018, 2019 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/gnunet-service-tng.c
22 * @brief main for gnunet-service-tng
23 * @author Christian Grothoff
24 *
25 * TODO:
26 * Implement next:
27 * - review retransmission logic, right now there is no smartness there!
28 * => congestion control, etc [PERFORMANCE-BASICS]
29 *
30 * Optimizations-Statistics:
31 * - Track ACK losses based on ACK-counter [ROUTING]
32 * - Need to track total bandwidth per VirtualLink and adjust how frequently
33 * we send FC messages based on bandwidth-delay-product (and relation
34 * to the window size!). See OPTIMIZE-FC-BDP.
35 * - Consider more statistics in #check_connection_quality() [FIXME-CONQ-STATISTICS]
36 * - Adapt available_fc_window_size, using larger values for high-bandwidth
37 * and high-latency links *if* we have the RAM [GOODPUT / utilization / stalls]
38 * - Set last_window_consum_limit promise properly based on
39 * latency and bandwidth of the respective connection [GOODPUT / utilization / stalls]
40 *
41 * Optimizations-DV:
42 * - When forwarding DV learn messages, if a peer is reached that
43 * has a *bidirectional* link to the origin beyond 1st hop,
44 * do NOT forward it to peers _other_ than the origin, as
45 * there is clearly a better path directly from the origin to
46 * whatever else we could reach.
47 * - When we passively learned DV (with unconfirmed freshness), we
48 * right now add the path to our list but with a zero path_valid_until
49 * time and only use it for unconfirmed routes. However, we could consider
50 * triggering an explicit validation mechanism ourselves, specifically routing
51 * a challenge-response message over the path [ROUTING]
52 * = if available, try to confirm unconfirmed DV paths when trying to establish
53 * virtual link for a `struct IncomingRequest`. (i.e. if DVH is
54 * unconfirmed, incoming requests cause us to try to validate a passively
55 * learned path (requires new message type!))
56 *
57 * Optimizations-Fragmentation:
58 * - Fragments send over a reliable channel could do without the
59 * AcknowledgementUUIDP altogether, as they won't be acked! [BANDWIDTH]
60 * (-> have 2nd type of acknowledgment message; low priority, as we
61 * do not have an MTU-limited *reliable* communicator) [FIXME-FRAG-REL-UUID]
62 * - if messages are below MTU, consider adding ACKs and other stuff
63 * to the same transmission to avoid tiny messages (requires planning at
64 * receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]
65 *
66 * Optimizations-internals:
67 * - queue_send_msg by API design has to make a copy
68 * of the payload, and route_message on top of that requires a malloc/free.
69 * Change design to approximate "zero" copy better... [CPU]
70 * - could avoid copying body of message into each fragment and keep
71 * fragments as just pointers into the original message and only
72 * fully build fragments just before transmission (optimization, should
73 * reduce CPU and memory use) [CPU, MEMORY]
74 */
75#include "platform.h"
76#include "gnunet_util_lib.h"
77#include "gnunet_statistics_service.h"
78#include "gnunet_transport_monitor_service.h"
79#include "gnunet_peerstore_service.h"
80#include "gnunet_hello_lib.h"
81#include "gnunet_signatures.h"
82#include "transport.h"
83
84/**
85 * Maximum number of FC retransmissions for a runing retransmission task.
86 */
87#define MAX_FC_RETRANSMIT_COUNT 1000
88
89/**
90 * Maximum number of messages we acknowledge together in one
91 * cumulative ACK. Larger values may save a bit of bandwidth.
92 */
93#define MAX_CUMMULATIVE_ACKS 64
94
95/**
96 * What is the 1:n chance that we send a Flow control response when
97 * receiving a flow control message that did not change anything for
98 * us? Basically, this is used in the case where both peers are stuck
99 * on flow control (no window changes), but one might continue sending
100 * flow control messages to the other peer as the first FC message
101 * when things stalled got lost, and then subsequently the other peer
102 * does *usually* not respond as nothing changed. So to ensure that
103 * eventually the FC messages stop, we do send with 1/8th probability
104 * an FC message even if nothing changed. That prevents one peer
105 * being stuck in sending (useless) FC messages "forever".
106 */
107#define FC_NO_CHANGE_REPLY_PROBABILITY 8
108
109/**
110 * What is the size we assume for a read operation in the
111 * absence of an MTU for the purpose of flow control?
112 */
113#define IN_PACKET_SIZE_WITHOUT_MTU 128
114
115/**
116 * Number of slots we keep of historic data for computation of
117 * goodput / message loss ratio.
118 */
119#define GOODPUT_AGING_SLOTS 4
120
121/**
122 * How big is the flow control window size by default;
123 * limits per-neighbour RAM utilization.
124 */
125#define DEFAULT_WINDOW_SIZE (128 * 1024)
126
127/**
128 * For how many incoming connections do we try to create a
129 * virtual link for (at the same time!). This does NOT
130 * limit the number of incoming connections, just the number
131 * for which we are actively trying to find working addresses
132 * in the absence (!) of our own applications wanting the
133 * link to go up.
134 */
135#define MAX_INCOMING_REQUEST 16
136
137/**
138 * Maximum number of peers we select for forwarding DVInit
139 * messages at the same time (excluding initiator).
140 */
141#define MAX_DV_DISCOVERY_SELECTION 16
142
143/**
144 * Window size. How many messages to the same target do we pass
145 * to CORE without a RECV_OK in between? Small values limit
146 * thoughput, large values will increase latency.
147 *
148 * FIXME-OPTIMIZE: find out what good values are experimentally,
149 * maybe set adaptively (i.e. to observed available bandwidth).
150 */
151#define RECV_WINDOW_SIZE 4
152
153/**
154 * Minimum number of hops we should forward DV learn messages
155 * even if they are NOT useful for us in hope of looping
156 * back to the initiator?
157 *
158 * FIXME: allow initiator some control here instead?
159 */
160#define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
161
162/**
163 * Maximum DV distance allowed ever.
164 */
165#define MAX_DV_HOPS_ALLOWED 16
166
167/**
168 * Maximum number of DV learning activities we may
169 * have pending at the same time.
170 */
171#define MAX_DV_LEARN_PENDING 64
172
173/**
174 * Maximum number of DV paths we keep simultaneously to the same target.
175 */
176#define MAX_DV_PATHS_TO_TARGET 3
177
178/**
179 * If a queue delays the next message by more than this number
180 * of seconds we log a warning. Note: this is for testing,
181 * the value chosen here might be too aggressively low!
182 */
183#define DELAY_WARN_THRESHOLD \
184 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
185
186/**
187 * If a DVBox could not be forwarded after this number of
188 * seconds we drop it.
189 */
190#define DV_FORWARD_TIMEOUT \
191 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
192
193/**
194 * Default value for how long we wait for reliability ack.
195 */
196#define DEFAULT_ACK_WAIT_DURATION \
197 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
198
199/**
200 * We only consider queues as "quality" connections when
201 * suppressing the generation of DV initiation messages if
202 * the latency of the queue is below this threshold.
203 */
204#define DV_QUALITY_RTT_THRESHOLD \
205 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
206
207/**
208 * How long do we consider a DV path valid if we see no
209 * further updates on it? Note: the value chosen here might be too low!
210 */
211#define DV_PATH_VALIDITY_TIMEOUT \
212 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
213
214/**
215 * How long do we cache backchannel (struct Backtalker) information
216 * after a backchannel goes inactive?
217 */
218#define BACKCHANNEL_INACTIVITY_TIMEOUT \
219 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
220
221/**
222 * How long before paths expire would we like to (re)discover DV paths? Should
223 * be below #DV_PATH_VALIDITY_TIMEOUT.
224 */
225#define DV_PATH_DISCOVERY_FREQUENCY \
226 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
227
228/**
229 * How long are ephemeral keys valid?
230 */
231#define EPHEMERAL_VALIDITY \
232 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
233
234/**
235 * How long do we keep partially reassembled messages around before giving up?
236 */
237#define REASSEMBLY_EXPIRATION \
238 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
239
240/**
241 * What is the fastest rate at which we send challenges *if* we keep learning
242 * an address (gossip, DHT, etc.)?
243 */
244#define FAST_VALIDATION_CHALLENGE_FREQ \
245 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
246
247/**
248 * What is the slowest rate at which we send challenges?
249 */
250#define MAX_VALIDATION_CHALLENGE_FREQ \
251 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
252
253/**
254 * How long until we forget about historic accumulators and thus
255 * reset the ACK counter? Should exceed the maximum time an
256 * active connection experiences without an ACK.
257 */
258#define ACK_CUMMULATOR_TIMEOUT \
259 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
260
261/**
262 * What is the non-randomized base frequency at which we
263 * would initiate DV learn messages?
264 */
265#define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
266
267/**
268 * How many good connections (confirmed, bi-directional, not DV)
269 * do we need to have to suppress initiating DV learn messages?
270 */
271#define DV_LEARN_QUALITY_THRESHOLD 100
272
273/**
274 * When do we forget an invalid address for sure?
275 */
276#define MAX_ADDRESS_VALID_UNTIL \
277 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
278
279/**
280 * How long do we consider an address valid if we just checked?
281 */
282#define ADDRESS_VALIDATION_LIFETIME \
283 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
284
285/**
286 * What is the maximum frequency at which we do address validation?
287 * A random value between 0 and this value is added when scheduling
288 * the #validation_task (both to ensure we do not validate too often,
289 * and to randomize a bit).
290 */
291#define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
292
293/**
294 * How many network RTTs before an address validation expires should we begin
295 * trying to revalidate? (Note that the RTT used here is the one that we
296 * experienced during the last validation, not necessarily the latest RTT
297 * observed).
298 */
299#define VALIDATION_RTT_BUFFER_FACTOR 3
300
301/**
302 * How many messages can we have pending for a given communicator
303 * process before we start to throttle that communicator?
304 *
305 * Used if a communicator might be CPU-bound and cannot handle the traffic.
306 */
307#define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
308
309/**
310 * How many messages can we have pending for a given queue (queue to
311 * a particular peer via a communicator) process before we start to
312 * throttle that queue?
313 */
314#define QUEUE_LENGTH_LIMIT 32
315
316
317GNUNET_NETWORK_STRUCT_BEGIN
318
319/**
320 * Unique identifier we attach to a message.
321 */
322struct MessageUUIDP
323{
324 /**
325 * Unique value, generated by incrementing the
326 * `message_uuid_ctr` of `struct Neighbour`.
327 */
328 uint64_t uuid GNUNET_PACKED;
329};
330
331
332/**
333 * Unique identifier to map an acknowledgement to a transmission.
334 */
335struct AcknowledgementUUIDP
336{
337 /**
338 * The UUID value.
339 */
340 struct GNUNET_Uuid value;
341};
342
343/**
344 * Outer layer of an encapsulated backchannel message.
345 */
346struct TransportBackchannelEncapsulationMessage
347{
348 /**
349 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
350 */
351 struct GNUNET_MessageHeader header;
352
353 /* Followed by *another* message header which is the message to
354 the communicator */
355
356 /* Followed by a 0-terminated name of the communicator */
357};
358
359
360/**
361 * Body by which a peer confirms that it is using an ephemeral key.
362 */
363struct EphemeralConfirmationPS
364{
365 /**
366 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
367 */
368 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
369
370 /**
371 * How long is this signature over the ephemeral key valid?
372 *
373 * Note that the receiver MUST IGNORE the absolute time, and only interpret
374 * the value as a mononic time and reject "older" values than the last one
375 * observed. This is necessary as we do not want to require synchronized
376 * clocks and may not have a bidirectional communication channel.
377 *
378 * Even with this, there is no real guarantee against replay achieved here,
379 * unless the latest timestamp is persisted. While persistence should be
380 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
381 * communicators must protect against replay attacks when using backchannel
382 * communication!
383 */
384 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
385
386 /**
387 * Target's peer identity.
388 */
389 struct GNUNET_PeerIdentity target;
390
391 /**
392 * Ephemeral key setup by the sender for @e target, used
393 * to encrypt the payload.
394 */
395 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
396};
397
398
399/**
400 * Plaintext of the variable-size payload that is encrypted
401 * within a `struct TransportBackchannelEncapsulationMessage`
402 */
403struct TransportDVBoxPayloadP
404{
405 /**
406 * Sender's peer identity.
407 */
408 struct GNUNET_PeerIdentity sender;
409
410 /**
411 * Signature of the sender over an
412 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
413 */
414 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
415
416 /**
417 * Current monotonic time of the sending transport service. Used to
418 * detect replayed messages. Note that the receiver should remember
419 * a list of the recently seen timestamps and only reject messages
420 * if the timestamp is in the list, or the list is "full" and the
421 * timestamp is smaller than the lowest in the list.
422 *
423 * Like the @e ephemeral_validity, the list of timestamps per peer should be
424 * persisted to guard against replays after restarts.
425 */
426 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
427
428 /* Followed by a `struct GNUNET_MessageHeader` with a message
429 for the target peer */
430};
431
432
433/**
434 * Outer layer of an encapsulated unfragmented application message sent
435 * over an unreliable channel.
436 */
437struct TransportReliabilityBoxMessage
438{
439 /**
440 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
441 */
442 struct GNUNET_MessageHeader header;
443
444 /**
445 * Number of messages still to be sent before a commulative
446 * ACK is requested. Zero if an ACK is requested immediately.
447 * In NBO. Note that the receiver may send the ACK faster
448 * if it believes that is reasonable.
449 */
450 uint32_t ack_countdown GNUNET_PACKED;
451
452 /**
453 * Unique ID of the message used for signalling receipt of
454 * messages sent over possibly unreliable channels. Should
455 * be a random.
456 */
457 struct AcknowledgementUUIDP ack_uuid;
458};
459
460
461/**
462 * Acknowledgement payload.
463 */
464struct TransportCummulativeAckPayloadP
465{
466 /**
467 * How long was the ACK delayed for generating cumulative ACKs?
468 * Used to calculate the correct network RTT by taking the receipt
469 * time of the ack minus the transmission time of the sender minus
470 * this value.
471 */
472 struct GNUNET_TIME_RelativeNBO ack_delay;
473
474 /**
475 * UUID of a message being acknowledged.
476 */
477 struct AcknowledgementUUIDP ack_uuid;
478};
479
480
481/**
482 * Confirmation that the receiver got a
483 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
484 * confirmation may be transmitted over a completely different queue,
485 * so ACKs are identified by a combination of PID of sender and
486 * message UUID, without the queue playing any role!
487 */
488struct TransportReliabilityAckMessage
489{
490 /**
491 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
492 */
493 struct GNUNET_MessageHeader header;
494
495 /**
496 * Counter of ACKs transmitted by the sender to us. Incremented
497 * by one for each ACK, used to detect how many ACKs were lost.
498 */
499 uint32_t ack_counter GNUNET_PACKED;
500
501 /* followed by any number of `struct TransportCummulativeAckPayloadP`
502 messages providing ACKs */
503};
504
505
506/**
507 * Outer layer of an encapsulated fragmented application message.
508 */
509struct TransportFragmentBoxMessage
510{
511 /**
512 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
513 */
514 struct GNUNET_MessageHeader header;
515
516 /**
517 * Offset of this fragment in the overall message.
518 */
519 uint16_t frag_off GNUNET_PACKED;
520
521 /**
522 * Total size of the message that is being fragmented.
523 */
524 uint16_t msg_size GNUNET_PACKED;
525
526 /**
527 * Unique ID of this fragment (and fragment transmission!). Will
528 * change even if a fragment is retransmitted to make each
529 * transmission attempt unique! If a client receives a duplicate
530 * fragment (same @e frag_off for same @a msg_uuid, it must send
531 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
532 */
533 struct AcknowledgementUUIDP ack_uuid;
534
535 /**
536 * Original message ID for of the message that all the fragments
537 * belong to. Must be the same for all fragments.
538 */
539 struct MessageUUIDP msg_uuid;
540};
541
542
543/**
544 * Content signed by the initator during DV learning.
545 *
546 * The signature is required to prevent DDoS attacks. A peer sending out this
547 * message is potentially generating a lot of traffic that will go back to the
548 * initator, as peers receiving this message will try to let the initiator
549 * know that they got the message.
550 *
551 * Without this signature, an attacker could abuse this mechanism for traffic
552 * amplification, sending a lot of traffic to a peer by putting out this type
553 * of message with the victim's peer identity.
554 *
555 * Even with just a signature, traffic amplification would be possible via
556 * replay attacks. The @e monotonic_time limits such replay attacks, as every
557 * potential amplificator will check the @e monotonic_time and only respond
558 * (at most) once per message.
559 */
560struct DvInitPS
561{
562 /**
563 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
564 */
565 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
566
567 /**
568 * Time at the initiator when generating the signature.
569 *
570 * Note that the receiver MUST IGNORE the absolute time, and only interpret
571 * the value as a mononic time and reject "older" values than the last one
572 * observed. This is necessary as we do not want to require synchronized
573 * clocks and may not have a bidirectional communication channel.
574 *
575 * Even with this, there is no real guarantee against replay achieved here,
576 * unless the latest timestamp is persisted. Persistence should be
577 * provided via PEERSTORE if possible.
578 */
579 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
580
581 /**
582 * Challenge value used by the initiator to re-identify the path.
583 */
584 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
585};
586
587
588/**
589 * Content signed by each peer during DV learning.
590 *
591 * This assues the initiator of the DV learning operation that the hop from @e
592 * pred via the signing peer to @e succ actually exists. This makes it
593 * impossible for an adversary to supply the network with bogus routes.
594 *
595 * The @e challenge is included to provide replay protection for the
596 * initiator. This way, the initiator knows that the hop existed after the
597 * original @e challenge was first transmitted, providing a freshness metric.
598 *
599 * Peers other than the initiator that passively learn paths by observing
600 * these messages do NOT benefit from this. Here, an adversary may indeed
601 * replay old messages. Thus, passively learned paths should always be
602 * immediately marked as "potentially stale".
603 */
604struct DvHopPS
605{
606 /**
607 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
608 */
609 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
610
611 /**
612 * Identity of the previous peer on the path.
613 */
614 struct GNUNET_PeerIdentity pred;
615
616 /**
617 * Identity of the next peer on the path.
618 */
619 struct GNUNET_PeerIdentity succ;
620
621 /**
622 * Challenge value used by the initiator to re-identify the path.
623 */
624 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
625};
626
627
628/**
629 * An entry describing a peer on a path in a
630 * `struct TransportDVLearnMessage` message.
631 */
632struct DVPathEntryP
633{
634 /**
635 * Identity of a peer on the path.
636 */
637 struct GNUNET_PeerIdentity hop;
638
639 /**
640 * Signature of this hop over the path, of purpose
641 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
642 */
643 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
644};
645
646
647/**
648 * Internal message used by transport for distance vector learning.
649 * If @e num_hops does not exceed the threshold, peers should append
650 * themselves to the peer list and flood the message (possibly only
651 * to a subset of their neighbours to limit discoverability of the
652 * network topology). To the extend that the @e bidirectional bits
653 * are set, peers may learn the inverse paths even if they did not
654 * initiate.
655 *
656 * Unless received on a bidirectional queue and @e num_hops just
657 * zero, peers that can forward to the initator should always try to
658 * forward to the initiator.
659 */
660struct TransportDVLearnMessage
661{
662 /**
663 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
664 */
665 struct GNUNET_MessageHeader header;
666
667 /**
668 * Number of hops this messages has travelled, in NBO. Zero if
669 * sent by initiator.
670 */
671 uint16_t num_hops GNUNET_PACKED;
672
673 /**
674 * Bitmask of the last 16 hops indicating whether they are confirmed
675 * available (without DV) in both directions or not, in NBO. Used
676 * to possibly instantly learn a path in both directions. Each peer
677 * should shift this value by one to the left, and then set the
678 * lowest bit IF the current sender can be reached from it (without
679 * DV routing).
680 */
681 uint16_t bidirectional GNUNET_PACKED;
682
683 /**
684 * Peers receiving this message and delaying forwarding to other
685 * peers for any reason should increment this value by the non-network
686 * delay created by the peer.
687 */
688 struct GNUNET_TIME_RelativeNBO non_network_delay;
689
690 /**
691 * Time at the initiator when generating the signature.
692 *
693 * Note that the receiver MUST IGNORE the absolute time, and only interpret
694 * the value as a mononic time and reject "older" values than the last one
695 * observed. This is necessary as we do not want to require synchronized
696 * clocks and may not have a bidirectional communication channel.
697 *
698 * Even with this, there is no real guarantee against replay achieved here,
699 * unless the latest timestamp is persisted. Persistence should be
700 * provided via PEERSTORE if possible.
701 */
702 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
703
704 /**
705 * Signature of this hop over the path, of purpose
706 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
707 */
708 struct GNUNET_CRYPTO_EddsaSignature init_sig;
709
710 /**
711 * Identity of the peer that started this learning activity.
712 */
713 struct GNUNET_PeerIdentity initiator;
714
715 /**
716 * Challenge value used by the initiator to re-identify the path.
717 */
718 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
719
720 /* Followed by @e num_hops `struct DVPathEntryP` values,
721 excluding the initiator of the DV trace; the last entry is the
722 current sender; the current peer must not be included. */
723};
724
725
726/**
727 * Outer layer of an encapsulated message send over multiple hops.
728 * The path given only includes the identities of the subsequent
729 * peers, i.e. it will be empty if we are the receiver. Each
730 * forwarding peer should scan the list from the end, and if it can,
731 * forward to the respective peer. The list should then be shortened
732 * by all the entries up to and including that peer. Each hop should
733 * also increment @e total_hops to allow the receiver to get a precise
734 * estimate on the number of hops the message travelled. Senders must
735 * provide a learned path that thus should work, but intermediaries
736 * know of a shortcut, they are allowed to send the message via that
737 * shortcut.
738 *
739 * If a peer finds itself still on the list, it must drop the message.
740 *
741 * The payload of the box can only be decrypted and verified by the
742 * ultimate receiver. Intermediaries do not learn the sender's
743 * identity and the path the message has taken. However, the first
744 * hop does learn the sender as @e total_hops would be zero and thus
745 * the predecessor must be the origin (so this is not really useful
746 * for anonymization).
747 */
748struct TransportDVBoxMessage
749{
750 /**
751 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
752 */
753 struct GNUNET_MessageHeader header;
754
755 /**
756 * Flag if the payload is a control message. In NBO.
757 */
758 unsigned int without_fc;
759
760 /**
761 * Number of total hops this messages travelled. In NBO.
762 * @e origin sets this to zero, to be incremented at
763 * each hop. Peers should limit the @e total_hops value
764 * they accept from other peers.
765 */
766 uint16_t total_hops GNUNET_PACKED;
767
768 /**
769 * Number of hops this messages includes. In NBO. Reduced by one
770 * or more at each hop. Peers should limit the @e num_hops value
771 * they accept from other peers.
772 */
773 uint16_t num_hops GNUNET_PACKED;
774
775 /**
776 * Ephemeral key setup by the sender for target, used to encrypt the
777 * payload. Intermediaries must not change this value.
778 */
779 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
780
781 /**
782 * We use an IV here as the @e ephemeral_key is re-used for
783 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
784 * Intermediaries must not change this value.
785 */
786 struct GNUNET_ShortHashCode iv;
787
788 /**
789 * HMAC over the ciphertext of the encrypted, variable-size body
790 * that follows. Verified via DH of target and @e ephemeral_key.
791 * Intermediaries must not change this value.
792 */
793 struct GNUNET_HashCode hmac;
794
795 /**
796 * Size this msg had initially. This is needed to calculate the hmac at the target.
797 * The header size can not be used for that, because the box size is getting smaller at each hop.
798 */
799 /**
800 * The length of the struct (in bytes, including the length field itself),
801 * in big-endian format.
802 */
803 uint16_t orig_size GNUNET_PACKED;
804
805 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
806 excluding the @e origin and the current peer, the last must be
807 the ultimate target; if @e num_hops is zero, the receiver of this
808 message is the ultimate target. */
809
810 /* Followed by encrypted, variable-size payload, which
811 must begin with a `struct TransportDVBoxPayloadP` */
812
813 /* Followed by the actual message, which itself must not be a
814 a DV_LEARN or DV_BOX message! */
815};
816
817
818/**
819 * Message send to another peer to validate that it can indeed
820 * receive messages at a particular address.
821 */
822struct TransportValidationChallengeMessage
823{
824 /**
825 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
826 */
827 struct GNUNET_MessageHeader header;
828
829 /**
830 * Always zero.
831 */
832 uint32_t reserved GNUNET_PACKED;
833
834 /**
835 * Challenge to be signed by the receiving peer.
836 */
837 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
838
839 /**
840 * Timestamp of the sender, to be copied into the reply to allow
841 * sender to calculate RTT. Must be monotonically increasing!
842 */
843 struct GNUNET_TIME_AbsoluteNBO sender_time;
844};
845
846
847/**
848 * Message signed by a peer to confirm that it can indeed
849 * receive messages at a particular address.
850 */
851struct TransportValidationPS
852{
853 /**
854 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
855 */
856 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
857
858 /**
859 * How long does the sender believe the address on
860 * which the challenge was received to remain valid?
861 */
862 struct GNUNET_TIME_RelativeNBO validity_duration;
863
864 /**
865 * Challenge signed by the receiving peer.
866 */
867 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
868};
869
870
871/**
872 * Message send to a peer to respond to a
873 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
874 */
875struct TransportValidationResponseMessage
876{
877 /**
878 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
879 */
880 struct GNUNET_MessageHeader header;
881
882 /**
883 * Always zero.
884 */
885 uint32_t reserved GNUNET_PACKED;
886
887 /**
888 * The peer's signature matching the
889 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
890 */
891 struct GNUNET_CRYPTO_EddsaSignature signature;
892
893 /**
894 * The challenge that was signed by the receiving peer.
895 */
896 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
897
898 /**
899 * Original timestamp of the sender (was @code{sender_time}),
900 * copied into the reply to allow sender to calculate RTT.
901 */
902 struct GNUNET_TIME_AbsoluteNBO origin_time;
903
904 /**
905 * How long does the sender believe this address to remain
906 * valid?
907 */
908 struct GNUNET_TIME_RelativeNBO validity_duration;
909};
910
911
912/**
913 * Message for Transport-to-Transport Flow control. Specifies the size
914 * of the flow control window, including how much we believe to have
915 * consumed (at transmission time), how much we believe to be allowed
916 * (at transmission time), and how much the other peer is allowed to
917 * send to us, and how much data we already received from the other
918 * peer.
919 */
920struct TransportFlowControlMessage
921{
922 /**
923 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL
924 */
925 struct GNUNET_MessageHeader header;
926
927 /**
928 * Sequence number of the flow control message. Incremented by one
929 * for each message. Starts at zero when a virtual link goes up.
930 * Used to detect one-sided connection drops. On wrap-around, the
931 * flow control counters will be reset as if the connection had
932 * dropped.
933 */
934 uint32_t seq GNUNET_PACKED;
935
936 /**
937 * Flow control window size in bytes, in NBO.
938 * The receiver can send this many bytes at most.
939 */
940 uint64_t inbound_window_size GNUNET_PACKED;
941
942 /**
943 * How many bytes has the sender sent that count for flow control at
944 * this time. Used to allow the receiver to estimate the packet
945 * loss rate.
946 */
947 uint64_t outbound_sent GNUNET_PACKED;
948
949 /**
950 * Latest flow control window size we learned from the other peer,
951 * in bytes, in NBO. We are limited to sending at most this many
952 * bytes to the other peer. May help the other peer detect when
953 * flow control messages were lost and should thus be retransmitted.
954 * In particular, if the delta to @e outbound_sent is too small,
955 * this signals that we are stalled.
956 */
957 uint64_t outbound_window_size GNUNET_PACKED;
958
959 /**
960 * Timestamp of the sender. Must be monotonically increasing!
961 * Used to enable receiver to ignore out-of-order packets in
962 * combination with the @e seq. Note that @e seq will go down
963 * (back to zero) whenever either side believes the connection
964 * was dropped, allowing the peers to detect that they need to
965 * reset the counters for the number of bytes sent!
966 */
967 struct GNUNET_TIME_AbsoluteNBO sender_time;
968};
969
970
971GNUNET_NETWORK_STRUCT_END
972
973
974/**
975 * What type of client is the `struct TransportClient` about?
976 */
977enum ClientType
978{
979 /**
980 * We do not know yet (client is fresh).
981 */
982 CT_NONE = 0,
983
984 /**
985 * Is the CORE service, we need to forward traffic to it.
986 */
987 CT_CORE = 1,
988
989 /**
990 * It is a monitor, forward monitor data.
991 */
992 CT_MONITOR = 2,
993
994 /**
995 * It is a communicator, use for communication.
996 */
997 CT_COMMUNICATOR = 3,
998
999 /**
1000 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
1001 */
1002 CT_APPLICATION = 4
1003};
1004
1005
1006/**
1007 * Which transmission options are allowable for transmission?
1008 * Interpreted bit-wise!
1009 */
1010enum RouteMessageOptions
1011{
1012 /**
1013 * Only confirmed, non-DV direct neighbours.
1014 */
1015 RMO_NONE = 0,
1016
1017 /**
1018 * We are allowed to use DV routing for this @a hdr
1019 */
1020 RMO_DV_ALLOWED = 1,
1021
1022 /**
1023 * We are allowed to use unconfirmed queues or DV routes for this message
1024 */
1025 RMO_UNCONFIRMED_ALLOWED = 2,
1026
1027 /**
1028 * Reliable and unreliable, DV and non-DV are all acceptable.
1029 */
1030 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
1031
1032 /**
1033 * If we have multiple choices, it is OK to send this message
1034 * over multiple channels at the same time to improve loss tolerance.
1035 * (We do at most 2 transmissions.)
1036 */
1037 RMO_REDUNDANT = 4
1038};
1039
1040
1041/**
1042 * When did we launch this DV learning activity?
1043 */
1044struct LearnLaunchEntry
1045{
1046 /**
1047 * Kept (also) in a DLL sorted by launch time.
1048 */
1049 struct LearnLaunchEntry *prev;
1050
1051 /**
1052 * Kept (also) in a DLL sorted by launch time.
1053 */
1054 struct LearnLaunchEntry *next;
1055
1056 /**
1057 * Challenge that uniquely identifies this activity.
1058 */
1059 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
1060
1061 /**
1062 * When did we transmit the DV learn message (used to calculate RTT) and
1063 * determine freshness of paths learned via this operation.
1064 */
1065 struct GNUNET_TIME_Absolute launch_time;
1066};
1067
1068
1069/**
1070 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1071 * (or current) transmission performance.
1072 */
1073struct TransmissionHistoryEntry
1074{
1075 /**
1076 * Number of bytes actually sent in the interval.
1077 */
1078 uint64_t bytes_sent;
1079
1080 /**
1081 * Number of bytes received and acknowledged by the other peer in
1082 * the interval.
1083 */
1084 uint64_t bytes_received;
1085};
1086
1087
1088/**
1089 * Performance data for a transmission possibility.
1090 */
1091struct PerformanceData
1092{
1093 /**
1094 * Weighted average for the RTT.
1095 */
1096 struct GNUNET_TIME_Relative aged_rtt;
1097
1098 /**
1099 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1100 * entries.
1101 */
1102 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1103
1104 /**
1105 * What was the last age when we wrote to @e the? Used to clear
1106 * old entries when the age advances.
1107 */
1108 unsigned int last_age;
1109};
1110
1111
1112/**
1113 * Client connected to the transport service.
1114 */
1115struct TransportClient;
1116
1117/**
1118 * A neighbour that at least one communicator is connected to.
1119 */
1120struct Neighbour;
1121
1122/**
1123 * Entry in our #dv_routes table, representing a (set of) distance
1124 * vector routes to a particular peer.
1125 */
1126struct DistanceVector;
1127
1128/**
1129 * A queue is a message queue provided by a communicator
1130 * via which we can reach a particular neighbour.
1131 */
1132struct Queue;
1133
1134/**
1135 * Message awaiting transmission. See detailed comments below.
1136 */
1137struct PendingMessage;
1138
1139/**
1140 * One possible hop towards a DV target.
1141 */
1142struct DistanceVectorHop;
1143
1144/**
1145 * A virtual link is another reachable peer that is known to CORE. It
1146 * can be either a `struct Neighbour` with at least one confirmed
1147 * `struct Queue`, or a `struct DistanceVector` with at least one
1148 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1149 * data that is per neighbour that is not specific to how the
1150 * connectivity is established.
1151 */
1152struct VirtualLink;
1153
1154
1155/**
1156 * Context from #handle_incoming_msg(). Closure for many
1157 * message handlers below.
1158 */
1159struct CommunicatorMessageContext
1160{
1161 /**
1162 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1163 * flow control to unchoke.
1164 */
1165 struct CommunicatorMessageContext *next;
1166
1167 /**
1168 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1169 * flow control to unchoke.
1170 */
1171 struct CommunicatorMessageContext *prev;
1172
1173 /**
1174 * Which communicator provided us with the message.
1175 */
1176 struct TransportClient *tc;
1177
1178 /**
1179 * Additional information for flow control and about the sender.
1180 */
1181 struct GNUNET_TRANSPORT_IncomingMessage im;
1182
1183 /**
1184 * Number of hops the message has travelled (if DV-routed).
1185 * FIXME: make use of this in ACK handling!
1186 */
1187 uint16_t total_hops;
1188};
1189
1190
1191/**
1192 * Closure for #core_env_sent_cb.
1193 */
1194struct CoreSentContext
1195{
1196 /**
1197 * Kept in a DLL to clear @e vl in case @e vl is lost.
1198 */
1199 struct CoreSentContext *next;
1200
1201 /**
1202 * Kept in a DLL to clear @e vl in case @e vl is lost.
1203 */
1204 struct CoreSentContext *prev;
1205
1206 /**
1207 * Virtual link this is about.
1208 */
1209 struct VirtualLink *vl;
1210
1211 /**
1212 * How big was the message.
1213 */
1214 uint16_t size;
1215
1216 /**
1217 * By how much should we increment @e vl's
1218 * incoming_fc_window_size_used once we are done sending to CORE?
1219 * Use to ensure we do not increment twice if there is more than one
1220 * CORE client.
1221 */
1222 uint16_t isize;
1223};
1224
1225
1226/**
1227 * Information we keep for a message that we are reassembling.
1228 */
1229struct ReassemblyContext
1230{
1231 /**
1232 * Original message ID for of the message that all the fragments
1233 * belong to.
1234 */
1235 struct MessageUUIDP msg_uuid;
1236
1237 /**
1238 * Which neighbour is this context for?
1239 */
1240 struct VirtualLink *virtual_link;
1241
1242 /**
1243 * Entry in the reassembly heap (sorted by expiration).
1244 */
1245 struct GNUNET_CONTAINER_HeapNode *hn;
1246
1247 /**
1248 * Bitfield with @e msg_size bits representing the positions
1249 * where we have received fragments. When we receive a fragment,
1250 * we check the bits in @e bitfield before incrementing @e msg_missing.
1251 *
1252 * Allocated after the reassembled message.
1253 */
1254 uint8_t *bitfield;
1255
1256 /**
1257 * At what time will we give up reassembly of this message?
1258 */
1259 struct GNUNET_TIME_Absolute reassembly_timeout;
1260
1261 /**
1262 * Time we received the last fragment. @e avg_ack_delay must be
1263 * incremented by now - @e last_frag multiplied by @e num_acks.
1264 */
1265 struct GNUNET_TIME_Absolute last_frag;
1266
1267 /**
1268 * How big is the message we are reassembling in total?
1269 */
1270 uint16_t msg_size;
1271
1272 /**
1273 * How many bytes of the message are still missing? Defragmentation
1274 * is complete when @e msg_missing == 0.
1275 */
1276 uint16_t msg_missing;
1277
1278 /* Followed by @e msg_size bytes of the (partially) defragmented original
1279 * message */
1280
1281 /* Followed by @e bitfield data */
1282};
1283
1284
1285/**
1286 * A virtual link is another reachable peer that is known to CORE. It
1287 * can be either a `struct Neighbour` with at least one confirmed
1288 * `struct Queue`, or a `struct DistanceVector` with at least one
1289 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1290 * data that is per neighbour that is not specific to how the
1291 * connectivity is established.
1292 */
1293struct VirtualLink
1294{
1295 /**
1296 * Identity of the peer at the other end of the link.
1297 */
1298 struct GNUNET_PeerIdentity target;
1299
1300 /**
1301 * Map with `struct ReassemblyContext` structs for fragments under
1302 * reassembly. May be NULL if we currently have no fragments from
1303 * this @e pid (lazy initialization).
1304 */
1305 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1306
1307 /**
1308 * Heap with `struct ReassemblyContext` structs for fragments under
1309 * reassembly. May be NULL if we currently have no fragments from
1310 * this @e pid (lazy initialization).
1311 */
1312 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1313
1314 /**
1315 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1316 */
1317 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1318
1319 /**
1320 * Communicators blocked for receiving on @e target as we are waiting
1321 * on the @e core_recv_window to increase.
1322 */
1323 struct CommunicatorMessageContext *cmc_head;
1324
1325 /**
1326 * Communicators blocked for receiving on @e target as we are waiting
1327 * on the @e core_recv_window to increase.
1328 */
1329 struct CommunicatorMessageContext *cmc_tail;
1330
1331 /**
1332 * Head of list of messages pending for this VL.
1333 */
1334 struct PendingMessage *pending_msg_head;
1335
1336 /**
1337 * Tail of list of messages pending for this VL.
1338 */
1339 struct PendingMessage *pending_msg_tail;
1340
1341 /**
1342 * Kept in a DLL to clear @e vl in case @e vl is lost.
1343 */
1344 struct CoreSentContext *csc_tail;
1345
1346 /**
1347 * Kept in a DLL to clear @e vl in case @e vl is lost.
1348 */
1349 struct CoreSentContext *csc_head;
1350
1351 /**
1352 * Task scheduled to possibly notfiy core that this peer is no
1353 * longer counting as confirmed. Runs the #core_visibility_check(),
1354 * which checks that some DV-path or a queue exists that is still
1355 * considered confirmed.
1356 */
1357 struct GNUNET_SCHEDULER_Task *visibility_task;
1358
1359 /**
1360 * Task scheduled to periodically retransmit FC messages (in
1361 * case one got lost).
1362 */
1363 struct GNUNET_SCHEDULER_Task *fc_retransmit_task;
1364
1365 /**
1366 * Number of FC retransmissions for this running task.
1367 */
1368 unsigned int fc_retransmit_count;
1369
1370 /**
1371 * Is this VirtualLink confirmed.
1372 * A unconfirmed VirtualLink might exist, if we got a FC from that target.
1373 */
1374 unsigned int confirmed;
1375
1376 /**
1377 * Neighbour used by this virtual link, NULL if @e dv is used.
1378 */
1379 struct Neighbour *n;
1380
1381 /**
1382 * Distance vector used by this virtual link, NULL if @e n is used.
1383 */
1384 struct DistanceVector *dv;
1385
1386 /**
1387 * Sender timestamp of @e n_challenge, used to generate out-of-order
1388 * challenges (as sender's timestamps must be monotonically
1389 * increasing). FIXME: where do we need this?
1390 */
1391 struct GNUNET_TIME_Absolute n_challenge_time;
1392
1393 /**
1394 * When did we last send a
1395 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message?
1396 * Used to determine whether it is time to re-transmit the message.
1397 */
1398 struct GNUNET_TIME_Absolute last_fc_transmission;
1399
1400 /**
1401 * Sender timestamp of the last
1402 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1403 * received. Note that we do not persist this monotonic time as we
1404 * do not really have to worry about ancient flow control window
1405 * sizes after restarts.
1406 */
1407 struct GNUNET_TIME_Absolute last_fc_timestamp;
1408
1409 /**
1410 * Expected RTT from the last FC transmission. (Zero if the last
1411 * attempt failed, but could theoretically be zero even on success.)
1412 */
1413 struct GNUNET_TIME_Relative last_fc_rtt;
1414
1415 /**
1416 * Used to generate unique UUIDs for messages that are being
1417 * fragmented.
1418 */
1419 uint64_t message_uuid_ctr;
1420
1421 /**
1422 * Memory allocated for this virtual link. Expresses how much RAM
1423 * we are willing to allocate to this virtual link. OPTIMIZE-ME:
1424 * Can be adapted to dedicate more RAM to links that need it, while
1425 * sticking to some overall RAM limit. For now, set to
1426 * #DEFAULT_WINDOW_SIZE.
1427 */
1428 uint64_t available_fc_window_size;
1429
1430 /**
1431 * Memory actually used to buffer packets on this virtual link.
1432 * Expresses how much RAM we are currently using for virtual link.
1433 * Note that once CORE is done with a packet, we decrement the value
1434 * here.
1435 */
1436 uint64_t incoming_fc_window_size_ram;
1437
1438 /**
1439 * Last flow control window size we provided to the other peer, in
1440 * bytes. We are allowing the other peer to send this
1441 * many bytes.
1442 */
1443 uint64_t incoming_fc_window_size;
1444
1445 /**
1446 * How much of the window did the other peer successfully use (and
1447 * we already passed it on to CORE)? Must be below @e
1448 * incoming_fc_window_size. We should effectively signal the
1449 * other peer that the window is this much bigger at the next
1450 * opportunity / challenge.
1451 */
1452 uint64_t incoming_fc_window_size_used;
1453
1454 /**
1455 * What is our current estimate on the message loss rate for the sender?
1456 * Based on the difference between how much the sender sent according
1457 * to the last #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message
1458 * (@e outbound_sent field) and how much we actually received at that
1459 * time (@e incoming_fc_window_size_used). This delta is then
1460 * added onto the @e incoming_fc_window_size when determining the
1461 * @e outbound_window_size we send to the other peer. Initially zero.
1462 * May be negative if we (due to out-of-order delivery) actually received
1463 * more than the sender claims to have sent in its last FC message.
1464 */
1465 int64_t incoming_fc_window_size_loss;
1466
1467 /**
1468 * Our current flow control window size in bytes. We
1469 * are allowed to transmit this many bytes to @a n.
1470 */
1471 uint64_t outbound_fc_window_size;
1472
1473 /**
1474 * How much of our current flow control window size have we
1475 * used (in bytes). Must be below
1476 * @e outbound_fc_window_size.
1477 */
1478 uint64_t outbound_fc_window_size_used;
1479
1480 /**
1481 * What is the most recent FC window the other peer sent us
1482 * in `outbound_window_size`? This is basically the window
1483 * size value the other peer has definitively received from
1484 * us. If it matches @e incoming_fc_window_size, we should
1485 * not send a FC message to increase the FC window. However,
1486 * we may still send an FC message to notify the other peer
1487 * that we received the other peer's FC message.
1488 */
1489 uint64_t last_outbound_window_size_received;
1490
1491 /**
1492 * Generator for the sequence numbers of
1493 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send.
1494 */
1495 uint32_t fc_seq_gen;
1496
1497 /**
1498 * Last sequence number of a
1499 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1500 * received.
1501 */
1502 uint32_t last_fc_seq;
1503
1504 /**
1505 * How many more messages can we send to CORE before we exhaust
1506 * the receive window of CORE for this peer? If this hits zero,
1507 * we must tell communicators to stop providing us more messages
1508 * for this peer. In fact, the window can go negative as we
1509 * have multiple communicators, so per communicator we can go
1510 * down by one into the negative range. Furthermore, we count
1511 * delivery per CORE client, so if we had multiple cores, that
1512 * might also cause a negative window size here (as one message
1513 * would decrement the window by one per CORE client).
1514 */
1515 int core_recv_window;
1516};
1517
1518
1519/**
1520 * Data structure kept when we are waiting for an acknowledgement.
1521 */
1522struct PendingAcknowledgement
1523{
1524 /**
1525 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1526 * is kept in relation to its pending message.
1527 */
1528 struct PendingAcknowledgement *next_pm;
1529
1530 /**
1531 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1532 * is kept in relation to its pending message.
1533 */
1534 struct PendingAcknowledgement *prev_pm;
1535
1536 /**
1537 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1538 * is kept in relation to the queue that was used to transmit the
1539 * @a pm.
1540 */
1541 struct PendingAcknowledgement *next_queue;
1542
1543 /**
1544 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1545 * is kept in relation to the queue that was used to transmit the
1546 * @a pm.
1547 */
1548 struct PendingAcknowledgement *prev_queue;
1549
1550 /**
1551 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1552 * is kept in relation to the DVH that was used to transmit the
1553 * @a pm.
1554 */
1555 struct PendingAcknowledgement *next_dvh;
1556
1557 /**
1558 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1559 * is kept in relation to the DVH that was used to transmit the
1560 * @a pm.
1561 */
1562 struct PendingAcknowledgement *prev_dvh;
1563
1564 /**
1565 * Pointers for the DLL of all pending acknowledgements.
1566 * This list is sorted by @e transmission time. If the list gets too
1567 * long, the oldest entries are discarded.
1568 */
1569 struct PendingAcknowledgement *next_pa;
1570
1571 /**
1572 * Pointers for the DLL of all pending acknowledgements.
1573 * This list is sorted by @e transmission time. If the list gets too
1574 * long, the oldest entries are discarded.
1575 */
1576 struct PendingAcknowledgement *prev_pa;
1577
1578 /**
1579 * Unique identifier for this transmission operation.
1580 */
1581 struct AcknowledgementUUIDP ack_uuid;
1582
1583 /**
1584 * Message that was transmitted, may be NULL if the message was ACKed
1585 * via another channel.
1586 */
1587 struct PendingMessage *pm;
1588
1589 /**
1590 * Distance vector path chosen for this transmission, NULL if transmission
1591 * was to a direct neighbour OR if the path was forgotten in the meantime.
1592 */
1593 struct DistanceVectorHop *dvh;
1594
1595 /**
1596 * Queue used for transmission, NULL if the queue has been destroyed
1597 * (which may happen before we get an acknowledgement).
1598 */
1599 struct Queue *queue;
1600
1601 /**
1602 * Time of the transmission, for RTT calculation.
1603 */
1604 struct GNUNET_TIME_Absolute transmission_time;
1605
1606 /**
1607 * Number of bytes of the original message (to calculate bandwidth).
1608 */
1609 uint16_t message_size;
1610};
1611
1612
1613/**
1614 * One possible hop towards a DV target.
1615 */
1616struct DistanceVectorHop
1617{
1618 /**
1619 * Kept in a MDLL, sorted by @e timeout.
1620 */
1621 struct DistanceVectorHop *next_dv;
1622
1623 /**
1624 * Kept in a MDLL, sorted by @e timeout.
1625 */
1626 struct DistanceVectorHop *prev_dv;
1627
1628 /**
1629 * Kept in a MDLL.
1630 */
1631 struct DistanceVectorHop *next_neighbour;
1632
1633 /**
1634 * Kept in a MDLL.
1635 */
1636 struct DistanceVectorHop *prev_neighbour;
1637
1638 /**
1639 * Head of DLL of PAs that used our @a path.
1640 */
1641 struct PendingAcknowledgement *pa_head;
1642
1643 /**
1644 * Tail of DLL of PAs that used our @a path.
1645 */
1646 struct PendingAcknowledgement *pa_tail;
1647
1648 /**
1649 * What would be the next hop to @e target?
1650 */
1651 struct Neighbour *next_hop;
1652
1653 /**
1654 * Distance vector entry this hop belongs with.
1655 */
1656 struct DistanceVector *dv;
1657
1658 /**
1659 * Array of @e distance hops to the target, excluding @e next_hop.
1660 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1661 * at the end of this struct. Excludes the target itself!
1662 */
1663 const struct GNUNET_PeerIdentity *path;
1664
1665 /**
1666 * At what time do we forget about this path unless we see it again
1667 * while learning?
1668 */
1669 struct GNUNET_TIME_Absolute timeout;
1670
1671 /**
1672 * For how long is the validation of this path considered
1673 * valid?
1674 * Set to ZERO if the path is learned by snooping on DV learn messages
1675 * initiated by other peers, and to the time at which we generated the
1676 * challenge for DV learn operations this peer initiated.
1677 */
1678 struct GNUNET_TIME_Absolute path_valid_until;
1679
1680 /**
1681 * Performance data for this transmission possibility.
1682 */
1683 struct PerformanceData pd;
1684
1685 /**
1686 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1687 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1688 * to `target`).
1689 */
1690 unsigned int distance;
1691};
1692
1693
1694/**
1695 * Entry in our #dv_routes table, representing a (set of) distance
1696 * vector routes to a particular peer.
1697 */
1698struct DistanceVector
1699{
1700 /**
1701 * To which peer is this a route?
1702 */
1703 struct GNUNET_PeerIdentity target;
1704
1705 /**
1706 * Known paths to @e target.
1707 */
1708 struct DistanceVectorHop *dv_head;
1709
1710 /**
1711 * Known paths to @e target.
1712 */
1713 struct DistanceVectorHop *dv_tail;
1714
1715 /**
1716 * Task scheduled to purge expired paths from @e dv_head MDLL.
1717 */
1718 struct GNUNET_SCHEDULER_Task *timeout_task;
1719
1720 /**
1721 * Do we have a confirmed working queue and are thus visible to
1722 * CORE? If so, this is the virtual link, otherwise NULL.
1723 */
1724 struct VirtualLink *vl;
1725
1726 /**
1727 * Signature affirming @e ephemeral_key of type
1728 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1729 */
1730 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1731
1732 /**
1733 * How long is @e sender_sig valid
1734 */
1735 struct GNUNET_TIME_Absolute ephemeral_validity;
1736
1737 /**
1738 * What time was @e sender_sig created
1739 */
1740 struct GNUNET_TIME_Absolute monotime;
1741
1742 /**
1743 * Our ephemeral key.
1744 */
1745 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1746
1747 /**
1748 * Our private ephemeral key.
1749 */
1750 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1751};
1752
1753
1754/**
1755 * Entry identifying transmission in one of our `struct
1756 * Queue` which still awaits an ACK. This is used to
1757 * ensure we do not overwhelm a communicator and limit the number of
1758 * messages outstanding per communicator (say in case communicator is
1759 * CPU bound) and per queue (in case bandwidth allocation exceeds
1760 * what the communicator can actually provide towards a particular
1761 * peer/target).
1762 */
1763struct QueueEntry
1764{
1765 /**
1766 * Kept as a DLL.
1767 */
1768 struct QueueEntry *next;
1769
1770 /**
1771 * Kept as a DLL.
1772 */
1773 struct QueueEntry *prev;
1774
1775 /**
1776 * Queue this entry is queued with.
1777 */
1778 struct Queue *queue;
1779
1780 /**
1781 * Pending message this entry is for, or NULL for none.
1782 */
1783 struct PendingMessage *pm;
1784
1785 /**
1786 * Message ID used for this message with the queue used for transmission.
1787 */
1788 uint64_t mid;
1789};
1790
1791
1792/**
1793 * A queue is a message queue provided by a communicator
1794 * via which we can reach a particular neighbour.
1795 */
1796struct Queue
1797{
1798 /**
1799 * Kept in a MDLL.
1800 */
1801 struct Queue *next_neighbour;
1802
1803 /**
1804 * Kept in a MDLL.
1805 */
1806 struct Queue *prev_neighbour;
1807
1808 /**
1809 * Kept in a MDLL.
1810 */
1811 struct Queue *prev_client;
1812
1813 /**
1814 * Kept in a MDLL.
1815 */
1816 struct Queue *next_client;
1817
1818 /**
1819 * Head of DLL of PAs that used this queue.
1820 */
1821 struct PendingAcknowledgement *pa_head;
1822
1823 /**
1824 * Tail of DLL of PAs that used this queue.
1825 */
1826 struct PendingAcknowledgement *pa_tail;
1827
1828 /**
1829 * Head of DLL of unacked transmission requests.
1830 */
1831 struct QueueEntry *queue_head;
1832
1833 /**
1834 * End of DLL of unacked transmission requests.
1835 */
1836 struct QueueEntry *queue_tail;
1837
1838 /**
1839 * Which neighbour is this queue for?
1840 */
1841 struct Neighbour *neighbour;
1842
1843 /**
1844 * Which communicator offers this queue?
1845 */
1846 struct TransportClient *tc;
1847
1848 /**
1849 * Address served by the queue.
1850 */
1851 const char *address;
1852
1853 /**
1854 * Is this queue of unlimited length.
1855 */
1856 unsigned int unlimited_length;
1857
1858 /**
1859 * Task scheduled for the time when this queue can (likely) transmit the
1860 * next message.
1861 */
1862 struct GNUNET_SCHEDULER_Task *transmit_task;
1863
1864 /**
1865 * How long do *we* consider this @e address to be valid? In the past or
1866 * zero if we have not yet validated it. Can be updated based on
1867 * challenge-response validations (via address validation logic), or when we
1868 * receive ACKs that we can definitively map to transmissions via this
1869 * queue.
1870 */
1871 struct GNUNET_TIME_Absolute validated_until;
1872
1873 /**
1874 * Performance data for this queue.
1875 */
1876 struct PerformanceData pd;
1877
1878 /**
1879 * Message ID generator for transmissions on this queue to the
1880 * communicator.
1881 */
1882 uint64_t mid_gen;
1883
1884 /**
1885 * Unique identifier of this queue with the communicator.
1886 */
1887 uint32_t qid;
1888
1889 /**
1890 * Maximum transmission unit supported by this queue.
1891 */
1892 uint32_t mtu;
1893
1894 /**
1895 * Messages pending.
1896 */
1897 uint32_t num_msg_pending;
1898
1899 /**
1900 * Bytes pending.
1901 */
1902 uint32_t num_bytes_pending;
1903
1904 /**
1905 * Length of the DLL starting at @e queue_head.
1906 */
1907 unsigned int queue_length;
1908
1909 /**
1910 * Capacity of the queue.
1911 */
1912 uint64_t q_capacity;
1913
1914 /**
1915 * Queue priority
1916 */
1917 uint32_t priority;
1918
1919 /**
1920 * Network type offered by this queue.
1921 */
1922 enum GNUNET_NetworkType nt;
1923
1924 /**
1925 * Connection status for this queue.
1926 */
1927 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1928
1929 /**
1930 * Set to #GNUNET_YES if this queue is idle waiting for some
1931 * virtual link to give it a pending message.
1932 */
1933 int idle;
1934};
1935
1936
1937
1938
1939
1940/**
1941 * A neighbour that at least one communicator is connected to.
1942 */
1943struct Neighbour
1944{
1945 /**
1946 * Which peer is this about?
1947 */
1948 struct GNUNET_PeerIdentity pid;
1949
1950 /**
1951 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1952 * purged if this neighbour goes down.
1953 */
1954 struct DistanceVectorHop *dv_head;
1955
1956 /**
1957 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1958 * purged if this neighbour goes down.
1959 */
1960 struct DistanceVectorHop *dv_tail;
1961
1962 /**
1963 * Head of DLL of queues to this peer.
1964 */
1965 struct Queue *queue_head;
1966
1967 /**
1968 * Tail of DLL of queues to this peer.
1969 */
1970 struct Queue *queue_tail;
1971
1972 /**
1973 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1974 * the PEERSTORE, or NULL.
1975 */
1976 struct GNUNET_PEERSTORE_IterateContext *get;
1977
1978 /**
1979 * Handle to a PEERSTORE store operation to store this @e pid's @e
1980 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1981 */
1982 struct GNUNET_PEERSTORE_StoreContext *sc;
1983
1984 /**
1985 * Do we have a confirmed working queue and are thus visible to
1986 * CORE? If so, this is the virtual link, otherwise NULL.
1987 */
1988 struct VirtualLink *vl;
1989
1990 /**
1991 * Latest DVLearn monotonic time seen from this peer. Initialized only
1992 * if @e dl_monotime_available is #GNUNET_YES.
1993 */
1994 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1995
1996 /**
1997 * Do we have the latest value for @e last_dv_learn_monotime from
1998 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1999 */
2000 int dv_monotime_available;
2001};
2002
2003
2004/**
2005 * Another peer attempted to talk to us, we should try to establish
2006 * a connection in the other direction.
2007 */
2008struct IncomingRequest
2009{
2010 /**
2011 * Kept in a DLL.
2012 */
2013 struct IncomingRequest *next;
2014
2015 /**
2016 * Kept in a DLL.
2017 */
2018 struct IncomingRequest *prev;
2019
2020 /**
2021 * Handle for watching the peerstore for HELLOs for this peer.
2022 */
2023 struct GNUNET_PEERSTORE_WatchContext *wc;
2024
2025 /**
2026 * Which peer is this about?
2027 */
2028 struct GNUNET_PeerIdentity pid;
2029};
2030
2031
2032/**
2033 * A peer that an application (client) would like us to talk to directly.
2034 */
2035struct PeerRequest
2036{
2037 /**
2038 * Which peer is this about?
2039 */
2040 struct GNUNET_PeerIdentity pid;
2041
2042 /**
2043 * Client responsible for the request.
2044 */
2045 struct TransportClient *tc;
2046
2047 /**
2048 * Handle for watching the peerstore for HELLOs for this peer.
2049 */
2050 struct GNUNET_PEERSTORE_WatchContext *wc;
2051
2052 /**
2053 * What kind of performance preference does this @e tc have?
2054 *
2055 * TODO: use this!
2056 */
2057 enum GNUNET_MQ_PriorityPreferences pk;
2058
2059 /**
2060 * How much bandwidth would this @e tc like to see?
2061 */
2062 struct GNUNET_BANDWIDTH_Value32NBO bw;
2063};
2064
2065
2066/**
2067 * Types of different pending messages.
2068 */
2069enum PendingMessageType
2070{
2071 /**
2072 * Ordinary message received from the CORE service.
2073 */
2074 PMT_CORE = 0,
2075
2076 /**
2077 * Fragment box.
2078 */
2079 PMT_FRAGMENT_BOX = 1,
2080
2081 /**
2082 * Reliability box.
2083 */
2084 PMT_RELIABILITY_BOX = 2,
2085
2086 /**
2087 * Pending message created during #forward_dv_box().
2088 */
2089 PMT_DV_BOX = 3
2090};
2091
2092
2093/**
2094 * Transmission request that is awaiting delivery. The original
2095 * transmission requests from CORE may be too big for some queues.
2096 * In this case, a *tree* of fragments is created. At each
2097 * level of the tree, fragments are kept in a DLL ordered by which
2098 * fragment should be sent next (at the head). The tree is searched
2099 * top-down, with the original message at the root.
2100 *
2101 * To select a node for transmission, first it is checked if the
2102 * current node's message fits with the MTU. If it does not, we
2103 * either calculate the next fragment (based on @e frag_off) from the
2104 * current node, or, if all fragments have already been created,
2105 * descend to the @e head_frag. Even though the node was already
2106 * fragmented, the fragment may be too big if the fragment was
2107 * generated for a queue with a larger MTU. In this case, the node
2108 * may be fragmented again, thus creating a tree.
2109 *
2110 * When acknowledgements for fragments are received, the tree
2111 * must be pruned, removing those parts that were already
2112 * acknowledged. When fragments are sent over a reliable
2113 * channel, they can be immediately removed.
2114 *
2115 * If a message is ever fragmented, then the original "full" message
2116 * is never again transmitted (even if it fits below the MTU), and
2117 * only (remaining) fragments are sent.
2118 */
2119struct PendingMessage
2120{
2121 /**
2122 * Kept in a MDLL of messages for this @a vl.
2123 */
2124 struct PendingMessage *next_vl;
2125
2126 /**
2127 * Kept in a MDLL of messages for this @a vl.
2128 */
2129 struct PendingMessage *prev_vl;
2130
2131 /**
2132 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2133 */
2134 struct PendingMessage *next_client;
2135
2136 /**
2137 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2138 */
2139 struct PendingMessage *prev_client;
2140
2141 /**
2142 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2143 * #PMT_FRAGMENT_BOx)
2144 */
2145 struct PendingMessage *next_frag;
2146
2147 /**
2148 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2149 * #PMT_FRAGMENT_BOX)
2150 */
2151 struct PendingMessage *prev_frag;
2152
2153 /**
2154 * Head of DLL of PAs for this pending message.
2155 */
2156 struct PendingAcknowledgement *pa_head;
2157
2158 /**
2159 * Tail of DLL of PAs for this pending message.
2160 */
2161 struct PendingAcknowledgement *pa_tail;
2162
2163 /**
2164 * This message, reliability *or* DV-boxed. Only possibly available
2165 * if @e pmt is #PMT_CORE.
2166 */
2167 struct PendingMessage *bpm;
2168
2169 /**
2170 * Target of the request (always the ultimate destination!).
2171 */
2172 struct VirtualLink *vl;
2173
2174 /**
2175 * Set to non-NULL value if this message is currently being given to a
2176 * communicator and we are awaiting that communicator's acknowledgement.
2177 * Note that we must not retransmit a pending message while we're still
2178 * in the process of giving it to a communicator. If a pending message
2179 * is free'd while this entry is non-NULL, the @e qe reference to us
2180 * should simply be set to NULL.
2181 */
2182 struct QueueEntry *qe;
2183
2184 /**
2185 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
2186 */
2187 struct TransportClient *client;
2188
2189 /**
2190 * Head of a MDLL of fragments created for this core message.
2191 */
2192 struct PendingMessage *head_frag;
2193
2194 /**
2195 * Tail of a MDLL of fragments created for this core message.
2196 */
2197 struct PendingMessage *tail_frag;
2198
2199 /**
2200 * Our parent in the fragmentation tree.
2201 */
2202 struct PendingMessage *frag_parent;
2203
2204 /**
2205 * At what time should we give up on the transmission (and no longer retry)?
2206 */
2207 struct GNUNET_TIME_Absolute timeout;
2208
2209 /**
2210 * What is the earliest time for us to retry transmission of this message?
2211 */
2212 struct GNUNET_TIME_Absolute next_attempt;
2213
2214 /**
2215 * UUID to use for this message (used for reassembly of fragments, only
2216 * initialized if @e msg_uuid_set is #GNUNET_YES).
2217 */
2218 struct MessageUUIDP msg_uuid;
2219
2220 /**
2221 * UUID we use to identify this message in our logs.
2222 * Generated by incrementing the "logging_uuid_gen".
2223 */
2224 unsigned long long logging_uuid;
2225
2226 /**
2227 * Type of the pending message.
2228 */
2229 enum PendingMessageType pmt;
2230
2231 /**
2232 * Preferences for this message.
2233 * TODO: actually use this!
2234 */
2235 enum GNUNET_MQ_PriorityPreferences prefs;
2236
2237 /**
2238 * If pmt is of type PMT_DV_BOX we store the used path here.
2239 */
2240 struct DistanceVectorHop *used_dvh;
2241
2242 /**
2243 * Size of the original message.
2244 */
2245 uint16_t bytes_msg;
2246
2247 /**
2248 * Offset at which we should generate the next fragment.
2249 */
2250 uint16_t frag_off;
2251
2252 /**
2253 * #GNUNET_YES once @e msg_uuid was initialized
2254 */
2255 int16_t msg_uuid_set;
2256
2257 /* Followed by @e bytes_msg to transmit */
2258};
2259
2260
2261/**
2262 * Acknowledgement payload.
2263 */
2264struct TransportCummulativeAckPayload
2265{
2266 /**
2267 * When did we receive the message we are ACKing? Used to calculate
2268 * the delay we introduced by cummulating ACKs.
2269 */
2270 struct GNUNET_TIME_Absolute receive_time;
2271
2272 /**
2273 * UUID of a message being acknowledged.
2274 */
2275 struct AcknowledgementUUIDP ack_uuid;
2276};
2277
2278
2279/**
2280 * Data structure in which we track acknowledgements still to
2281 * be sent to the
2282 */
2283struct AcknowledgementCummulator
2284{
2285 /**
2286 * Target peer for which we are accumulating ACKs here.
2287 */
2288 struct GNUNET_PeerIdentity target;
2289
2290 /**
2291 * ACK data being accumulated. Only @e num_acks slots are valid.
2292 */
2293 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2294
2295 /**
2296 * Task scheduled either to transmit the cumulative ACK message,
2297 * or to clean up this data structure after extended periods of
2298 * inactivity (if @e num_acks is zero).
2299 */
2300 struct GNUNET_SCHEDULER_Task *task;
2301
2302 /**
2303 * When is @e task run (only used if @e num_acks is non-zero)?
2304 */
2305 struct GNUNET_TIME_Absolute min_transmission_time;
2306
2307 /**
2308 * Counter to produce the `ack_counter` in the `struct
2309 * TransportReliabilityAckMessage`. Allows the receiver to detect
2310 * lost ACK messages. Incremented by @e num_acks upon transmission.
2311 */
2312 uint32_t ack_counter;
2313
2314 /**
2315 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2316 */
2317 unsigned int num_acks;
2318};
2319
2320
2321/**
2322 * One of the addresses of this peer.
2323 */
2324struct AddressListEntry
2325{
2326 /**
2327 * Kept in a DLL.
2328 */
2329 struct AddressListEntry *next;
2330
2331 /**
2332 * Kept in a DLL.
2333 */
2334 struct AddressListEntry *prev;
2335
2336 /**
2337 * Which communicator provides this address?
2338 */
2339 struct TransportClient *tc;
2340
2341 /**
2342 * The actual address.
2343 */
2344 const char *address;
2345
2346 /**
2347 * Current context for storing this address in the peerstore.
2348 */
2349 struct GNUNET_PEERSTORE_StoreContext *sc;
2350
2351 /**
2352 * Task to periodically do @e st operation.
2353 */
2354 struct GNUNET_SCHEDULER_Task *st;
2355
2356 /**
2357 * What is a typical lifetime the communicator expects this
2358 * address to have? (Always from now.)
2359 */
2360 struct GNUNET_TIME_Relative expiration;
2361
2362 /**
2363 * Address identifier used by the communicator.
2364 */
2365 uint32_t aid;
2366
2367 /**
2368 * Network type offered by this address.
2369 */
2370 enum GNUNET_NetworkType nt;
2371};
2372
2373
2374/**
2375 * Client connected to the transport service.
2376 */
2377struct TransportClient
2378{
2379 /**
2380 * Kept in a DLL.
2381 */
2382 struct TransportClient *next;
2383
2384 /**
2385 * Kept in a DLL.
2386 */
2387 struct TransportClient *prev;
2388
2389 /**
2390 * Handle to the client.
2391 */
2392 struct GNUNET_SERVICE_Client *client;
2393
2394 /**
2395 * Message queue to the client.
2396 */
2397 struct GNUNET_MQ_Handle *mq;
2398
2399 /**
2400 * What type of client is this?
2401 */
2402 enum ClientType type;
2403
2404 union
2405 {
2406 /**
2407 * Information for @e type #CT_CORE.
2408 */
2409 struct
2410 {
2411 /**
2412 * Head of list of messages pending for this client, sorted by
2413 * transmission time ("next_attempt" + possibly internal prioritization).
2414 */
2415 struct PendingMessage *pending_msg_head;
2416
2417 /**
2418 * Tail of list of messages pending for this client.
2419 */
2420 struct PendingMessage *pending_msg_tail;
2421 } core;
2422
2423 /**
2424 * Information for @e type #CT_MONITOR.
2425 */
2426 struct
2427 {
2428 /**
2429 * Peer identity to monitor the addresses of.
2430 * Zero to monitor all neighbours. Valid if
2431 * @e type is #CT_MONITOR.
2432 */
2433 struct GNUNET_PeerIdentity peer;
2434
2435 /**
2436 * Is this a one-shot monitor?
2437 */
2438 int one_shot;
2439 } monitor;
2440
2441
2442 /**
2443 * Information for @e type #CT_COMMUNICATOR.
2444 */
2445 struct
2446 {
2447 /**
2448 * If @e type is #CT_COMMUNICATOR, this communicator
2449 * supports communicating using these addresses.
2450 */
2451 char *address_prefix;
2452
2453 /**
2454 * Head of DLL of queues offered by this communicator.
2455 */
2456 struct Queue *queue_head;
2457
2458 /**
2459 * Tail of DLL of queues offered by this communicator.
2460 */
2461 struct Queue *queue_tail;
2462
2463 /**
2464 * Head of list of the addresses of this peer offered by this
2465 * communicator.
2466 */
2467 struct AddressListEntry *addr_head;
2468
2469 /**
2470 * Tail of list of the addresses of this peer offered by this
2471 * communicator.
2472 */
2473 struct AddressListEntry *addr_tail;
2474
2475 /**
2476 * Number of queue entries in all queues to this communicator. Used
2477 * throttle sending to a communicator if we see that the communicator
2478 * is globally unable to keep up.
2479 */
2480 unsigned int total_queue_length;
2481
2482 /**
2483 * Characteristics of this communicator.
2484 */
2485 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2486 } communicator;
2487
2488 /**
2489 * Information for @e type #CT_APPLICATION
2490 */
2491 struct
2492 {
2493 /**
2494 * Map of requests for peers the given client application would like to
2495 * see connections for. Maps from PIDs to `struct PeerRequest`.
2496 */
2497 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2498 } application;
2499 } details;
2500};
2501
2502
2503/**
2504 * State we keep for validation activities. Each of these
2505 * is both in the #validation_heap and the #validation_map.
2506 */
2507struct ValidationState
2508{
2509 /**
2510 * For which peer is @a address to be validated (or possibly valid)?
2511 * Serves as key in the #validation_map.
2512 */
2513 struct GNUNET_PeerIdentity pid;
2514
2515 /**
2516 * How long did the peer claim this @e address to be valid? Capped at
2517 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2518 * were told about the address and the value claimed by the other peer at
2519 * that time. May be updated similarly when validation succeeds.
2520 */
2521 struct GNUNET_TIME_Absolute valid_until;
2522
2523 /**
2524 * How long do *we* consider this @e address to be valid?
2525 * In the past or zero if we have not yet validated it.
2526 */
2527 struct GNUNET_TIME_Absolute validated_until;
2528
2529 /**
2530 * When did we FIRST use the current @e challenge in a message?
2531 * Used to sanity-check @code{origin_time} in the response when
2532 * calculating the RTT. If the @code{origin_time} is not in
2533 * the expected range, the response is discarded as malicious.
2534 */
2535 struct GNUNET_TIME_Absolute first_challenge_use;
2536
2537 /**
2538 * When did we LAST use the current @e challenge in a message?
2539 * Used to sanity-check @code{origin_time} in the response when
2540 * calculating the RTT. If the @code{origin_time} is not in
2541 * the expected range, the response is discarded as malicious.
2542 */
2543 struct GNUNET_TIME_Absolute last_challenge_use;
2544
2545 /**
2546 * Next time we will send the @e challenge to the peer, if this time is past
2547 * @e valid_until, this validation state is released at this time. If the
2548 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2549 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2550 * to re-validate before the validity actually expires.
2551 */
2552 struct GNUNET_TIME_Absolute next_challenge;
2553
2554 /**
2555 * Current backoff factor we're applying for sending the @a challenge.
2556 * Reset to 0 if the @a challenge is confirmed upon validation.
2557 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2558 * existing value if we receive an unvalidated address again over
2559 * another channel (and thus should consider the information "fresh").
2560 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2561 */
2562 struct GNUNET_TIME_Relative challenge_backoff;
2563
2564 /**
2565 * Initially set to "forever". Once @e validated_until is set, this value is
2566 * set to the RTT that tells us how long it took to receive the validation.
2567 */
2568 struct GNUNET_TIME_Relative validation_rtt;
2569
2570 /**
2571 * The challenge we sent to the peer to get it to validate the address. Note
2572 * that we rotate the challenge whenever we update @e validated_until to
2573 * avoid attacks where a peer simply replays an old challenge in the future.
2574 * (We must not rotate more often as otherwise we may discard valid answers
2575 * due to packet losses, latency and reorderings on the network).
2576 */
2577 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
2578
2579 /**
2580 * Claimed address of the peer.
2581 */
2582 char *address;
2583
2584 /**
2585 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2586 * heap is used to figure out when the next validation activity should be
2587 * run.
2588 */
2589 struct GNUNET_CONTAINER_HeapNode *hn;
2590
2591 /**
2592 * Handle to a PEERSTORE store operation for this @e address. NULL if
2593 * no PEERSTORE operation is pending.
2594 */
2595 struct GNUNET_PEERSTORE_StoreContext *sc;
2596
2597 /**
2598 * Self-imposed limit on the previous flow control window. (May be zero,
2599 * if we never used data from the previous window or are establishing the
2600 * connection for the first time).
2601 */
2602 uint32_t last_window_consum_limit;
2603
2604 /**
2605 * We are technically ready to send the challenge, but we are waiting for
2606 * the respective queue to become available for transmission.
2607 */
2608 int awaiting_queue;
2609};
2610
2611
2612/**
2613 * A Backtalker is a peer sending us backchannel messages. We use this
2614 * struct to detect monotonic time violations, cache ephemeral key
2615 * material (to avoid repeatedly checking signatures), and to synchronize
2616 * monotonic time with the PEERSTORE.
2617 */
2618struct Backtalker
2619{
2620 /**
2621 * Peer this is about.
2622 */
2623 struct GNUNET_PeerIdentity pid;
2624
2625 /**
2626 * Last (valid) monotonic time received from this sender.
2627 */
2628 struct GNUNET_TIME_Absolute monotonic_time;
2629
2630 /**
2631 * When will this entry time out?
2632 */
2633 struct GNUNET_TIME_Absolute timeout;
2634
2635 /**
2636 * Last (valid) ephemeral key received from this sender.
2637 */
2638 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2639
2640 /**
2641 * Task associated with this backtalker. Can be for timeout,
2642 * or other asynchronous operations.
2643 */
2644 struct GNUNET_SCHEDULER_Task *task;
2645
2646 /**
2647 * Communicator context waiting on this backchannel's @e get, or NULL.
2648 */
2649 struct CommunicatorMessageContext *cmc;
2650
2651 /**
2652 * Handle for an operation to fetch @e monotonic_time information from the
2653 * PEERSTORE, or NULL.
2654 */
2655 struct GNUNET_PEERSTORE_IterateContext *get;
2656
2657 /**
2658 * Handle to a PEERSTORE store operation for this @e pid's @e
2659 * monotonic_time. NULL if no PEERSTORE operation is pending.
2660 */
2661 struct GNUNET_PEERSTORE_StoreContext *sc;
2662
2663 /**
2664 * Number of bytes of the original message body that follows after this
2665 * struct.
2666 */
2667 size_t body_size;
2668};
2669
2670
2671/**
2672 * Head of linked list of all clients to this service.
2673 */
2674static struct TransportClient *clients_head;
2675
2676/**
2677 * Tail of linked list of all clients to this service.
2678 */
2679static struct TransportClient *clients_tail;
2680
2681/**
2682 * Statistics handle.
2683 */
2684static struct GNUNET_STATISTICS_Handle *GST_stats;
2685
2686/**
2687 * Configuration handle.
2688 */
2689static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2690
2691/**
2692 * Our public key.
2693 */
2694static struct GNUNET_PeerIdentity GST_my_identity;
2695
2696/**
2697 * Our private key.
2698 */
2699static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2700
2701/**
2702 * Map from PIDs to `struct Neighbour` entries. A peer is
2703 * a neighbour if we have an MQ to it from some communicator.
2704 */
2705static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2706
2707/**
2708 * Map from PIDs to `struct Backtalker` entries. A peer is
2709 * a backtalker if it recently send us backchannel messages.
2710 */
2711static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2712
2713/**
2714 * Map from PIDs to `struct AcknowledgementCummulator`s.
2715 * Here we track the cumulative ACKs for transmission.
2716 */
2717static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2718
2719/**
2720 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2721 * a `struct PendingAcknowledgement`.
2722 */
2723static struct GNUNET_CONTAINER_MultiUuidmap *pending_acks;
2724
2725/**
2726 * Map from PIDs to `struct DistanceVector` entries describing
2727 * known paths to the peer.
2728 */
2729static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2730
2731/**
2732 * Map from PIDs to `struct ValidationState` entries describing
2733 * addresses we are aware of and their validity state.
2734 */
2735static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2736
2737/**
2738 * Map from PIDs to `struct VirtualLink` entries describing
2739 * links CORE knows to exist.
2740 */
2741static struct GNUNET_CONTAINER_MultiPeerMap *links;
2742
2743/**
2744 * Map from challenges to `struct LearnLaunchEntry` values.
2745 */
2746static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2747
2748/**
2749 * Head of a DLL sorted by launch time.
2750 */
2751static struct LearnLaunchEntry *lle_head = NULL;
2752
2753/**
2754 * Tail of a DLL sorted by launch time.
2755 */
2756static struct LearnLaunchEntry *lle_tail = NULL;
2757
2758/**
2759 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2760 * sorting addresses we are aware of by when we should next try to (re)validate
2761 * (or expire) them.
2762 */
2763static struct GNUNET_CONTAINER_Heap *validation_heap;
2764
2765/**
2766 * Database for peer's HELLOs.
2767 */
2768static struct GNUNET_PEERSTORE_Handle *peerstore;
2769
2770/**
2771 * Task run to initiate DV learning.
2772 */
2773static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2774
2775/**
2776 * Task to run address validation.
2777 */
2778static struct GNUNET_SCHEDULER_Task *validation_task;
2779
2780/**
2781 * The most recent PA we have created, head of DLL.
2782 * The length of the DLL is kept in #pa_count.
2783 */
2784static struct PendingAcknowledgement *pa_head;
2785
2786/**
2787 * The oldest PA we have created, tail of DLL.
2788 * The length of the DLL is kept in #pa_count.
2789 */
2790static struct PendingAcknowledgement *pa_tail;
2791
2792/**
2793 * List of incoming connections where we are trying
2794 * to get a connection back established. Length
2795 * kept in #ir_total.
2796 */
2797static struct IncomingRequest *ir_head;
2798
2799/**
2800 * Tail of DLL starting at #ir_head.
2801 */
2802static struct IncomingRequest *ir_tail;
2803
2804/**
2805 * Length of the DLL starting at #ir_head.
2806 */
2807static unsigned int ir_total;
2808
2809/**
2810 * Generator of `logging_uuid` in `struct PendingMessage`.
2811 */
2812static unsigned long long logging_uuid_gen;
2813
2814/**
2815 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2816 * limit the size of the data structure.
2817 */
2818static unsigned int pa_count;
2819
2820/**
2821 * Monotonic time we use for HELLOs generated at this time. TODO: we
2822 * should increase this value from time to time (i.e. whenever a
2823 * `struct AddressListEntry` actually expires), but IF we do this, we
2824 * must also update *all* (remaining) addresses in the PEERSTORE at
2825 * that time! (So for now only increased when the peer is restarted,
2826 * which hopefully roughly matches whenever our addresses change.)
2827 */
2828static struct GNUNET_TIME_Absolute hello_mono_time;
2829
2830/**
2831 * Indication if we have received a shutdown signal
2832 * and are in the process of cleaning up.
2833 */
2834static int in_shutdown;
2835
2836/**
2837 * Get an offset into the transmission history buffer for `struct
2838 * PerformanceData`. Note that the caller must perform the required
2839 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2840 * array!
2841 *
2842 * An 'age' lasts 15 minute slots.
2843 *
2844 * @return current age of the world
2845 */
2846static unsigned int
2847get_age ()
2848{
2849 struct GNUNET_TIME_Absolute now;
2850
2851 now = GNUNET_TIME_absolute_get ();
2852 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2853}
2854
2855
2856/**
2857 * Release @a ir data structure.
2858 *
2859 * @param ir data structure to release
2860 */
2861static void
2862free_incoming_request (struct IncomingRequest *ir)
2863{
2864 GNUNET_CONTAINER_DLL_remove (ir_head, ir_tail, ir);
2865 GNUNET_assert (ir_total > 0);
2866 ir_total--;
2867 GNUNET_PEERSTORE_watch_cancel (ir->wc);
2868 ir->wc = NULL;
2869 GNUNET_free (ir);
2870}
2871
2872
2873/**
2874 * Release @a pa data structure.
2875 *
2876 * @param pa data structure to release
2877 */
2878static void
2879free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2880{
2881 struct Queue *q = pa->queue;
2882 struct PendingMessage *pm = pa->pm;
2883 struct DistanceVectorHop *dvh = pa->dvh;
2884
2885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2886 "free_pending_acknowledgement\n");
2887 if (NULL != q)
2888 {
2889 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2890 pa->queue = NULL;
2891 }
2892 if (NULL != pm)
2893 {
2894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2895 "remove pa from message\n");
2896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2897 "remove pa from message %llu\n",
2898 pm->logging_uuid);
2899 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2900 "remove pa from message %u\n",
2901 pm->pmt);
2902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2903 "remove pa from message %s\n",
2904 GNUNET_uuid2s (&pa->ack_uuid.value));
2905 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2906 pa->pm = NULL;
2907 }
2908 if (NULL != dvh)
2909 {
2910 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2911 pa->queue = NULL;
2912 }
2913 GNUNET_assert (GNUNET_YES ==
2914 GNUNET_CONTAINER_multiuuidmap_remove (pending_acks,
2915 &pa->ack_uuid.value,
2916 pa));
2917 GNUNET_free (pa);
2918}
2919
2920
2921/**
2922 * Free fragment tree below @e root, excluding @e root itself.
2923 * FIXME: this does NOT seem to have the intended semantics
2924 * based on how this is called. Seems we generally DO expect
2925 * @a root to be free'ed itself as well!
2926 *
2927 * @param root root of the tree to free
2928 */
2929static void
2930free_fragment_tree (struct PendingMessage *root)
2931{
2932 struct PendingMessage *frag;
2933
2934 while (NULL != (frag = root->head_frag))
2935 {
2936 struct PendingAcknowledgement *pa;
2937
2938 free_fragment_tree (frag);
2939 while (NULL != (pa = frag->pa_head))
2940 {
2941 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
2942 pa->pm = NULL;
2943 }
2944 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2945 if (NULL != frag->qe)
2946 {
2947 GNUNET_assert (frag == frag->qe->pm);
2948 frag->qe->pm = NULL;
2949 GNUNET_CONTAINER_DLL_remove (frag->qe->queue->queue_head,
2950 frag->qe->queue->queue_tail,
2951 frag->qe);
2952 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2953 "Removing QueueEntry MID %llu from queue\n",
2954 frag->qe->mid);
2955 GNUNET_free (frag->qe);
2956 }
2957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2958 "Free frag %p\n",
2959 frag);
2960 GNUNET_free (frag);
2961 }
2962}
2963
2964
2965/**
2966 * Release memory associated with @a pm and remove @a pm from associated
2967 * data structures. @a pm must be a top-level pending message and not
2968 * a fragment in the tree. The entire tree is freed (if applicable).
2969 *
2970 * @param pm the pending message to free
2971 */
2972static void
2973free_pending_message (struct PendingMessage *pm)
2974{
2975 struct TransportClient *tc = pm->client;
2976 struct VirtualLink *vl = pm->vl;
2977 struct PendingAcknowledgement *pa;
2978
2979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2980 "Freeing pm %p\n",
2981 pm);
2982 if (NULL != tc)
2983 {
2984 GNUNET_CONTAINER_MDLL_remove (client,
2985 tc->details.core.pending_msg_head,
2986 tc->details.core.pending_msg_tail,
2987 pm);
2988 }
2989 if ((NULL != vl) && (NULL == pm->frag_parent))
2990 {
2991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2992 "Removing pm %lu\n",
2993 pm->logging_uuid);
2994 GNUNET_CONTAINER_MDLL_remove (vl,
2995 vl->pending_msg_head,
2996 vl->pending_msg_tail,
2997 pm);
2998 }
2999 while (NULL != (pa = pm->pa_head))
3000 {
3001 if (NULL == pa)
3002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3003 "free pending pa null\n");
3004 if (NULL == pm->pa_tail)
3005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3006 "free pending pa_tail null\n");
3007 if (NULL == pa->prev_pa)
3008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3009 "free pending pa prev null\n");
3010 if (NULL == pa->next_pa)
3011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3012 "free pending pa next null\n");
3013 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3014 pa->pm = NULL;
3015 }
3016
3017 free_fragment_tree (pm);
3018 if (NULL != pm->qe)
3019 {
3020 GNUNET_assert (pm == pm->qe->pm);
3021 pm->qe->pm = NULL;
3022 GNUNET_CONTAINER_DLL_remove (pm->qe->queue->queue_head,
3023 pm->qe->queue->queue_tail,
3024 pm->qe);
3025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3026 "Removing QueueEntry MID %llu from queue\n",
3027 pm->qe->mid);
3028 GNUNET_free (pm->qe);
3029 }
3030 if (NULL != pm->bpm)
3031 {
3032 free_fragment_tree (pm->bpm);
3033 GNUNET_free (pm->bpm);
3034 }
3035 if (NULL == pm)
3036 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3037 "free pending pm null\n");
3038 GNUNET_free (pm);
3039}
3040
3041
3042/**
3043 * Free @a rc
3044 *
3045 * @param rc data structure to free
3046 */
3047static void
3048free_reassembly_context (struct ReassemblyContext *rc)
3049{
3050 struct VirtualLink *vl = rc->virtual_link;
3051
3052 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
3053 GNUNET_assert (GNUNET_OK ==
3054 GNUNET_CONTAINER_multihashmap32_remove (vl->reassembly_map,
3055 rc->msg_uuid.uuid,
3056 rc));
3057 GNUNET_free (rc);
3058}
3059
3060
3061/**
3062 * Task run to clean up reassembly context of a neighbour that have expired.
3063 *
3064 * @param cls a `struct Neighbour`
3065 */
3066static void
3067reassembly_cleanup_task (void *cls)
3068{
3069 struct VirtualLink *vl = cls;
3070 struct ReassemblyContext *rc;
3071
3072 vl->reassembly_timeout_task = NULL;
3073 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (vl->reassembly_heap)))
3074 {
3075 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
3076 .rel_value_us)
3077 {
3078 free_reassembly_context (rc);
3079 continue;
3080 }
3081 GNUNET_assert (NULL == vl->reassembly_timeout_task);
3082 vl->reassembly_timeout_task =
3083 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
3084 &reassembly_cleanup_task,
3085 vl);
3086 return;
3087 }
3088}
3089
3090
3091/**
3092 * function called to #free_reassembly_context().
3093 *
3094 * @param cls NULL
3095 * @param key unused
3096 * @param value a `struct ReassemblyContext` to free
3097 * @return #GNUNET_OK (continue iteration)
3098 */
3099static int
3100free_reassembly_cb (void *cls, uint32_t key, void *value)
3101{
3102 struct ReassemblyContext *rc = value;
3103
3104 (void) cls;
3105 (void) key;
3106 free_reassembly_context (rc);
3107 return GNUNET_OK;
3108}
3109
3110
3111/**
3112 * Free virtual link.
3113 *
3114 * @param vl link data to free
3115 */
3116static void
3117free_virtual_link (struct VirtualLink *vl)
3118{
3119 struct PendingMessage *pm;
3120 struct CoreSentContext *csc;
3121
3122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3123 "free virtual link %p\n",
3124 vl);
3125
3126 if (NULL != vl->reassembly_map)
3127 {
3128 GNUNET_CONTAINER_multihashmap32_iterate (vl->reassembly_map,
3129 &free_reassembly_cb,
3130 NULL);
3131 GNUNET_CONTAINER_multihashmap32_destroy (vl->reassembly_map);
3132 vl->reassembly_map = NULL;
3133 GNUNET_CONTAINER_heap_destroy (vl->reassembly_heap);
3134 vl->reassembly_heap = NULL;
3135 }
3136 if (NULL != vl->reassembly_timeout_task)
3137 {
3138 GNUNET_SCHEDULER_cancel (vl->reassembly_timeout_task);
3139 vl->reassembly_timeout_task = NULL;
3140 }
3141 while (NULL != (pm = vl->pending_msg_head))
3142 free_pending_message (pm);
3143 GNUNET_assert (GNUNET_YES ==
3144 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl));
3145 if (NULL != vl->visibility_task)
3146 {
3147 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3148 vl->visibility_task = NULL;
3149 }
3150 if (NULL != vl->fc_retransmit_task)
3151 {
3152 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
3153 vl->fc_retransmit_task = NULL;
3154 }
3155 while (NULL != (csc = vl->csc_head))
3156 {
3157 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc);
3158 GNUNET_assert (vl == csc->vl);
3159 csc->vl = NULL;
3160 }
3161 GNUNET_break (NULL == vl->n);
3162 GNUNET_break (NULL == vl->dv);
3163 GNUNET_free (vl);
3164}
3165
3166
3167/**
3168 * Free validation state.
3169 *
3170 * @param vs validation state to free
3171 */
3172static void
3173free_validation_state (struct ValidationState *vs)
3174{
3175 GNUNET_assert (
3176 GNUNET_YES ==
3177 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs));
3178 GNUNET_CONTAINER_heap_remove_node (vs->hn);
3179 vs->hn = NULL;
3180 if (NULL != vs->sc)
3181 {
3182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3183 "store cancel\n");
3184 GNUNET_PEERSTORE_store_cancel (vs->sc);
3185 vs->sc = NULL;
3186 }
3187 GNUNET_free (vs->address);
3188 GNUNET_free (vs);
3189}
3190
3191
3192/**
3193 * Lookup neighbour for peer @a pid.
3194 *
3195 * @param pid neighbour to look for
3196 * @return NULL if we do not have this peer as a neighbour
3197 */
3198static struct Neighbour *
3199lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
3200{
3201 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
3202}
3203
3204
3205/**
3206 * Lookup virtual link for peer @a pid.
3207 *
3208 * @param pid virtual link to look for
3209 * @return NULL if we do not have this peer as a virtual link
3210 */
3211static struct VirtualLink *
3212lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3213{
3214 return GNUNET_CONTAINER_multipeermap_get (links, pid);
3215}
3216
3217
3218/**
3219 * Details about what to notify monitors about.
3220 */
3221struct MonitorEvent
3222{
3223 /**
3224 * @deprecated To be discussed if we keep these...
3225 */
3226 struct GNUNET_TIME_Absolute last_validation;
3227 struct GNUNET_TIME_Absolute valid_until;
3228 struct GNUNET_TIME_Absolute next_validation;
3229
3230 /**
3231 * Current round-trip time estimate.
3232 */
3233 struct GNUNET_TIME_Relative rtt;
3234
3235 /**
3236 * Connection status.
3237 */
3238 enum GNUNET_TRANSPORT_ConnectionStatus cs;
3239
3240 /**
3241 * Messages pending.
3242 */
3243 uint32_t num_msg_pending;
3244
3245 /**
3246 * Bytes pending.
3247 */
3248 uint32_t num_bytes_pending;
3249};
3250
3251
3252/**
3253 * Free a @dvh. Callers MAY want to check if this was the last path to the
3254 * `target`, and if so call #free_dv_route to also free the associated DV
3255 * entry in #dv_routes (if not, the associated scheduler job should eventually
3256 * take care of it).
3257 *
3258 * @param dvh hop to free
3259 */
3260static void
3261free_distance_vector_hop (struct DistanceVectorHop *dvh)
3262{
3263 struct Neighbour *n = dvh->next_hop;
3264 struct DistanceVector *dv = dvh->dv;
3265 struct PendingAcknowledgement *pa;
3266
3267 while (NULL != (pa = dvh->pa_head))
3268 {
3269 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3270 pa->dvh = NULL;
3271 }
3272 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3273 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
3274 GNUNET_free (dvh);
3275}
3276
3277
3278/**
3279 * Task run to check whether the hops of the @a cls still
3280 * are validated, or if we need to core about disconnection.
3281 *
3282 * @param cls a `struct VirtualLink`
3283 */
3284static void
3285check_link_down (void *cls);
3286
3287
3288/**
3289 * Send message to CORE clients that we lost a connection.
3290 *
3291 * @param pid peer the connection was for
3292 */
3293static void
3294cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3295{
3296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3297 "Informing CORE clients about disconnect from %s\n",
3298 GNUNET_i2s (pid));
3299 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3300 {
3301 struct GNUNET_MQ_Envelope *env;
3302 struct DisconnectInfoMessage *dim;
3303
3304 if (CT_CORE != tc->type)
3305 continue;
3306 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3307 dim->peer = *pid;
3308 GNUNET_MQ_send (tc->mq, env);
3309 }
3310}
3311
3312
3313/**
3314 * Free entry in #dv_routes. First frees all hops to the target, and
3315 * if there are no entries left, frees @a dv as well.
3316 *
3317 * @param dv route to free
3318 */
3319static void
3320free_dv_route (struct DistanceVector *dv)
3321{
3322 struct DistanceVectorHop *dvh;
3323
3324 while (NULL != (dvh = dv->dv_head))
3325 free_distance_vector_hop (dvh);
3326 if (NULL == dv->dv_head)
3327 {
3328 struct VirtualLink *vl;
3329
3330 GNUNET_assert (
3331 GNUNET_YES ==
3332 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
3333 if (NULL != (vl = dv->vl))
3334 {
3335 GNUNET_assert (dv == vl->dv);
3336 vl->dv = NULL;
3337 if (NULL == vl->n)
3338 {
3339 cores_send_disconnect_info (&dv->target);
3340 free_virtual_link (vl);
3341 }
3342 else
3343 {
3344 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3345 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3346 }
3347 dv->vl = NULL;
3348 }
3349
3350 if (NULL != dv->timeout_task)
3351 {
3352 GNUNET_SCHEDULER_cancel (dv->timeout_task);
3353 dv->timeout_task = NULL;
3354 }
3355 GNUNET_free (dv);
3356 }
3357}
3358
3359
3360/**
3361 * Notify monitor @a tc about an event. That @a tc
3362 * cares about the event has already been checked.
3363 *
3364 * Send @a tc information in @a me about a @a peer's status with
3365 * respect to some @a address to all monitors that care.
3366 *
3367 * @param tc monitor to inform
3368 * @param peer peer the information is about
3369 * @param address address the information is about
3370 * @param nt network type associated with @a address
3371 * @param me detailed information to transmit
3372 */
3373static void
3374notify_monitor (struct TransportClient *tc,
3375 const struct GNUNET_PeerIdentity *peer,
3376 const char *address,
3377 enum GNUNET_NetworkType nt,
3378 const struct MonitorEvent *me)
3379{
3380 struct GNUNET_MQ_Envelope *env;
3381 struct GNUNET_TRANSPORT_MonitorData *md;
3382 size_t addr_len = strlen (address) + 1;
3383
3384 env = GNUNET_MQ_msg_extra (md,
3385 addr_len,
3386 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
3387 md->nt = htonl ((uint32_t) nt);
3388 md->peer = *peer;
3389 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
3390 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
3391 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
3392 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
3393 md->cs = htonl ((uint32_t) me->cs);
3394 md->num_msg_pending = htonl (me->num_msg_pending);
3395 md->num_bytes_pending = htonl (me->num_bytes_pending);
3396 memcpy (&md[1], address, addr_len);
3397 GNUNET_MQ_send (tc->mq, env);
3398}
3399
3400
3401/**
3402 * Send information in @a me about a @a peer's status with respect
3403 * to some @a address to all monitors that care.
3404 *
3405 * @param peer peer the information is about
3406 * @param address address the information is about
3407 * @param nt network type associated with @a address
3408 * @param me detailed information to transmit
3409 */
3410static void
3411notify_monitors (const struct GNUNET_PeerIdentity *peer,
3412 const char *address,
3413 enum GNUNET_NetworkType nt,
3414 const struct MonitorEvent *me)
3415{
3416 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3417 {
3418 if (CT_MONITOR != tc->type)
3419 continue;
3420 if (tc->details.monitor.one_shot)
3421 continue;
3422 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
3423 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
3424 continue;
3425 notify_monitor (tc, peer, address, nt, me);
3426 }
3427}
3428
3429
3430/**
3431 * Called whenever a client connects. Allocates our
3432 * data structures associated with that client.
3433 *
3434 * @param cls closure, NULL
3435 * @param client identification of the client
3436 * @param mq message queue for the client
3437 * @return our `struct TransportClient`
3438 */
3439static void *
3440client_connect_cb (void *cls,
3441 struct GNUNET_SERVICE_Client *client,
3442 struct GNUNET_MQ_Handle *mq)
3443{
3444 struct TransportClient *tc;
3445
3446 (void) cls;
3447 tc = GNUNET_new (struct TransportClient);
3448 tc->client = client;
3449 tc->mq = mq;
3450 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
3451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3452 "Client %p of type %u connected\n",
3453 tc,
3454 tc->type);
3455 return tc;
3456}
3457
3458
3459/**
3460 * Release memory used by @a neighbour.
3461 *
3462 * @param neighbour neighbour entry to free
3463 */
3464static void
3465free_neighbour (struct Neighbour *neighbour)
3466{
3467 struct DistanceVectorHop *dvh;
3468 struct VirtualLink *vl;
3469
3470 GNUNET_assert (NULL == neighbour->queue_head);
3471 GNUNET_assert (GNUNET_YES ==
3472 GNUNET_CONTAINER_multipeermap_remove (neighbours,
3473 &neighbour->pid,
3474 neighbour));
3475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3476 "Freeing neighbour\n");
3477 while (NULL != (dvh = neighbour->dv_head))
3478 {
3479 struct DistanceVector *dv = dvh->dv;
3480
3481 free_distance_vector_hop (dvh);
3482 if (NULL == dv->dv_head)
3483 free_dv_route (dv);
3484 }
3485 if (NULL != neighbour->get)
3486 {
3487 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
3488 neighbour->get = NULL;
3489 }
3490 if (NULL != neighbour->sc)
3491 {
3492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3493 "store cancel\n");
3494 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
3495 neighbour->sc = NULL;
3496 }
3497 if (NULL != (vl = neighbour->vl))
3498 {
3499 GNUNET_assert (neighbour == vl->n);
3500 vl->n = NULL;
3501 if (NULL == vl->dv)
3502 {
3503 cores_send_disconnect_info (&vl->target);
3504 free_virtual_link (vl);
3505 }
3506 else
3507 {
3508 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3509 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3510 }
3511 neighbour->vl = NULL;
3512 }
3513 GNUNET_free (neighbour);
3514}
3515
3516
3517/**
3518 * Send message to CORE clients that we lost a connection.
3519 *
3520 * @param tc client to inform (must be CORE client)
3521 * @param pid peer the connection is for
3522 */
3523static void
3524core_send_connect_info (struct TransportClient *tc,
3525 const struct GNUNET_PeerIdentity *pid)
3526{
3527 struct GNUNET_MQ_Envelope *env;
3528 struct ConnectInfoMessage *cim;
3529
3530 GNUNET_assert (CT_CORE == tc->type);
3531 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3532 cim->id = *pid;
3533 GNUNET_MQ_send (tc->mq, env);
3534}
3535
3536
3537/**
3538 * Send message to CORE clients that we gained a connection
3539 *
3540 * @param pid peer the queue was for
3541 */
3542static void
3543cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3544{
3545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3546 "Informing CORE clients about connection to %s\n",
3547 GNUNET_i2s (pid));
3548 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3549 {
3550 if (CT_CORE != tc->type)
3551 continue;
3552 core_send_connect_info (tc, pid);
3553 }
3554}
3555
3556
3557/**
3558 * We believe we are ready to transmit a message on a queue. Gives the
3559 * message to the communicator for transmission (updating the tracker,
3560 * and re-scheduling itself if applicable).
3561 *
3562 * @param cls the `struct Queue` to process transmissions for
3563 */
3564static void
3565transmit_on_queue (void *cls);
3566
3567
3568/**
3569 * Check if the communicator has another queue with higher prio ready for sending.
3570 */
3571static unsigned int
3572check_for_queue_with_higher_prio (struct Queue *queue, struct Queue *queue_head)
3573{
3574 for (struct Queue *s = queue_head; NULL != s;
3575 s = s->next_client)
3576 {
3577 if (s->tc->details.communicator.address_prefix !=
3578 queue->tc->details.communicator.address_prefix)
3579 {
3580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3581 "queue address %s qid %u compare with queue: address %s qid %u\n",
3582 queue->address,
3583 queue->qid,
3584 s->address,
3585 s->qid);
3586 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
3587 (QUEUE_LENGTH_LIMIT > s->queue_length) )
3588 return GNUNET_YES;
3589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3590 "Lower prio\n");
3591 }
3592 }
3593 return GNUNET_NO;
3594}
3595
3596
3597/**
3598 * Called whenever something changed that might effect when we
3599 * try to do the next transmission on @a queue using #transmit_on_queue().
3600 *
3601 * @param queue the queue to do scheduling for
3602 * @param p task priority to use, if @a queue is scheduled
3603 */
3604static void
3605schedule_transmit_on_queue (struct GNUNET_TIME_Relative delay,
3606 struct Queue *queue,
3607 enum GNUNET_SCHEDULER_Priority p)
3608{
3609 if (check_for_queue_with_higher_prio (queue,
3610 queue->tc->details.communicator.
3611 queue_head))
3612 return;
3613
3614 if (queue->tc->details.communicator.total_queue_length >=
3615 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3616 {
3617 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3618 "Transmission throttled due to communicator queue limit\n");
3619 GNUNET_STATISTICS_update (
3620 GST_stats,
3621 "# Transmission throttled due to communicator queue limit",
3622 1,
3623 GNUNET_NO);
3624 queue->idle = GNUNET_NO;
3625 return;
3626 }
3627 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3628 {
3629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3630 "Transmission throttled due to communicator queue length limit\n");
3631 GNUNET_STATISTICS_update (GST_stats,
3632 "# Transmission throttled due to queue queue limit",
3633 1,
3634 GNUNET_NO);
3635 queue->idle = GNUNET_NO;
3636 return;
3637 }
3638 if (0 == queue->q_capacity)
3639 {
3640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3641 "Transmission throttled due to communicator message queue qid %u has capacity %lu.\n",
3642 queue->qid,
3643 queue->q_capacity);
3644 GNUNET_STATISTICS_update (GST_stats,
3645 "# Transmission throttled due to message queue capacity",
3646 1,
3647 GNUNET_NO);
3648 queue->idle = GNUNET_NO;
3649 return;
3650 }
3651 /* queue might indeed be ready, schedule it */
3652 if (NULL != queue->transmit_task)
3653 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3654 queue->transmit_task =
3655 GNUNET_SCHEDULER_add_delayed_with_priority (delay, p, &transmit_on_queue,
3656 queue);
3657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3658 "Considering transmission on queue `%s' QID %llu to %s\n",
3659 queue->address,
3660 (unsigned long long) queue->qid,
3661 GNUNET_i2s (&queue->neighbour->pid));
3662}
3663
3664
3665/**
3666 * Task run to check whether the hops of the @a cls still
3667 * are validated, or if we need to core about disconnection.
3668 *
3669 * @param cls a `struct VirtualLink`
3670 */
3671static void
3672check_link_down (void *cls)
3673{
3674 struct VirtualLink *vl = cls;
3675 struct DistanceVector *dv = vl->dv;
3676 struct Neighbour *n = vl->n;
3677 struct GNUNET_TIME_Absolute dvh_timeout;
3678 struct GNUNET_TIME_Absolute q_timeout;
3679
3680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3681 "Checking if link is down\n");
3682 vl->visibility_task = NULL;
3683 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3684 if (NULL != dv)
3685 {
3686 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3687 pos = pos->next_dv)
3688 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
3689 pos->path_valid_until);
3690 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3691 {
3692 vl->dv->vl = NULL;
3693 vl->dv = NULL;
3694 }
3695 }
3696 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3697 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3698 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3699 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
3700 {
3701 vl->n->vl = NULL;
3702 vl->n = NULL;
3703 }
3704 if ((NULL == vl->n) && (NULL == vl->dv))
3705 {
3706 cores_send_disconnect_info (&vl->target);
3707 free_virtual_link (vl);
3708 return;
3709 }
3710 vl->visibility_task =
3711 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3712 &check_link_down,
3713 vl);
3714}
3715
3716
3717/**
3718 * Free @a queue.
3719 *
3720 * @param queue the queue to free
3721 */
3722static void
3723free_queue (struct Queue *queue)
3724{
3725 struct Neighbour *neighbour = queue->neighbour;
3726 struct TransportClient *tc = queue->tc;
3727 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
3728 .rtt = GNUNET_TIME_UNIT_FOREVER_REL };
3729 struct QueueEntry *qe;
3730 int maxxed;
3731 struct PendingAcknowledgement *pa;
3732 struct VirtualLink *vl;
3733
3734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3735 "Cleaning up queue %u\n", queue->qid);
3736 if (NULL != queue->transmit_task)
3737 {
3738 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3739 queue->transmit_task = NULL;
3740 }
3741 while (NULL != (pa = queue->pa_head))
3742 {
3743 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3744 pa->queue = NULL;
3745 }
3746
3747 GNUNET_CONTAINER_MDLL_remove (neighbour,
3748 neighbour->queue_head,
3749 neighbour->queue_tail,
3750 queue);
3751 GNUNET_CONTAINER_MDLL_remove (client,
3752 tc->details.communicator.queue_head,
3753 tc->details.communicator.queue_tail,
3754 queue);
3755 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT <=
3756 tc->details.communicator.
3757 total_queue_length);
3758 while (NULL != (qe = queue->queue_head))
3759 {
3760 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3761 queue->queue_length--;
3762 tc->details.communicator.total_queue_length--;
3763 if (NULL != qe->pm)
3764 {
3765 GNUNET_assert (qe == qe->pm->qe);
3766 qe->pm->qe = NULL;
3767 }
3768 GNUNET_free (qe);
3769 }
3770 GNUNET_assert (0 == queue->queue_length);
3771 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT >
3772 tc->details.communicator.total_queue_length))
3773 {
3774 /* Communicator dropped below threshold, resume all _other_ queues */
3775 GNUNET_STATISTICS_update (
3776 GST_stats,
3777 "# Transmission throttled due to communicator queue limit",
3778 -1,
3779 GNUNET_NO);
3780 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3781 s = s->next_client)
3782 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
3783 s,
3784 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
3785 }
3786 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3787 GNUNET_free (queue);
3788
3789 vl = lookup_virtual_link (&neighbour->pid);
3790 if ((NULL != vl) && (GNUNET_YES == vl->confirmed) && (neighbour == vl->n))
3791 {
3792 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3793 check_link_down (vl);
3794 }
3795 if (NULL == neighbour->queue_head)
3796 {
3797 free_neighbour (neighbour);
3798 }
3799}
3800
3801
3802/**
3803 * Free @a ale
3804 *
3805 * @param ale address list entry to free
3806 */
3807static void
3808free_address_list_entry (struct AddressListEntry *ale)
3809{
3810 struct TransportClient *tc = ale->tc;
3811
3812 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3813 tc->details.communicator.addr_tail,
3814 ale);
3815 if (NULL != ale->sc)
3816 {
3817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3818 "store cancel\n");
3819 GNUNET_PEERSTORE_store_cancel (ale->sc);
3820 ale->sc = NULL;
3821 }
3822 if (NULL != ale->st)
3823 {
3824 GNUNET_SCHEDULER_cancel (ale->st);
3825 ale->st = NULL;
3826 }
3827 GNUNET_free (ale);
3828}
3829
3830
3831/**
3832 * Stop the peer request in @a value.
3833 *
3834 * @param cls a `struct TransportClient` that no longer makes the request
3835 * @param pid the peer's identity
3836 * @param value a `struct PeerRequest`
3837 * @return #GNUNET_YES (always)
3838 */
3839static int
3840stop_peer_request (void *cls,
3841 const struct GNUNET_PeerIdentity *pid,
3842 void *value)
3843{
3844 struct TransportClient *tc = cls;
3845 struct PeerRequest *pr = value;
3846
3847 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3848 pr->wc = NULL;
3849 GNUNET_assert (
3850 GNUNET_YES ==
3851 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3852 pid,
3853 pr));
3854 GNUNET_free (pr);
3855
3856 return GNUNET_OK;
3857}
3858
3859
3860static void
3861do_shutdown (void *cls);
3862
3863/**
3864 * Called whenever a client is disconnected. Frees our
3865 * resources associated with that client.
3866 *
3867 * @param cls closure, NULL
3868 * @param client identification of the client
3869 * @param app_ctx our `struct TransportClient`
3870 */
3871static void
3872client_disconnect_cb (void *cls,
3873 struct GNUNET_SERVICE_Client *client,
3874 void *app_ctx)
3875{
3876 struct TransportClient *tc = app_ctx;
3877
3878 (void) cls;
3879 (void) client;
3880 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3881 switch (tc->type)
3882 {
3883 case CT_NONE:
3884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3885 "Unknown Client %p disconnected, cleaning up.\n",
3886 tc);
3887 break;
3888
3889 case CT_CORE: {
3890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3891 "CORE Client %p disconnected, cleaning up.\n",
3892 tc);
3893
3894 struct PendingMessage *pm;
3895
3896 while (NULL != (pm = tc->details.core.pending_msg_head))
3897 {
3898 GNUNET_CONTAINER_MDLL_remove (client,
3899 tc->details.core.pending_msg_head,
3900 tc->details.core.pending_msg_tail,
3901 pm);
3902 pm->client = NULL;
3903 }
3904 }
3905 break;
3906
3907 case CT_MONITOR:
3908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3909 "MONITOR Client %p disconnected, cleaning up.\n",
3910 tc);
3911
3912 break;
3913
3914 case CT_COMMUNICATOR: {
3915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3916 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
3917 tc);
3918
3919 struct Queue *q;
3920 struct AddressListEntry *ale;
3921
3922 while (NULL != (q = tc->details.communicator.queue_head))
3923 free_queue (q);
3924 while (NULL != (ale = tc->details.communicator.addr_head))
3925 free_address_list_entry (ale);
3926 GNUNET_free (tc->details.communicator.address_prefix);
3927 }
3928 break;
3929
3930 case CT_APPLICATION:
3931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3932 "APPLICATION Client %p disconnected, cleaning up.\n",
3933 tc);
3934
3935 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3936 &stop_peer_request,
3937 tc);
3938 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3939 break;
3940 }
3941 GNUNET_free (tc);
3942 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
3943 {
3944 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3945 "Our last client disconnected\n");
3946 do_shutdown (cls);
3947 }
3948}
3949
3950
3951/**
3952 * Iterator telling new CORE client about all existing
3953 * connections to peers.
3954 *
3955 * @param cls the new `struct TransportClient`
3956 * @param pid a connected peer
3957 * @param value the `struct Neighbour` with more information
3958 * @return #GNUNET_OK (continue to iterate)
3959 */
3960static int
3961notify_client_connect_info (void *cls,
3962 const struct GNUNET_PeerIdentity *pid,
3963 void *value)
3964{
3965 struct TransportClient *tc = cls;
3966
3967 (void) value;
3968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3969 "Telling new CORE client about existing connection to %s\n",
3970 GNUNET_i2s (pid));
3971 core_send_connect_info (tc, pid);
3972 return GNUNET_OK;
3973}
3974
3975
3976/**
3977 * Initialize a "CORE" client. We got a start message from this
3978 * client, so add it to the list of clients for broadcasting of
3979 * inbound messages.
3980 *
3981 * @param cls the client
3982 * @param start the start message that was sent
3983 */
3984static void
3985handle_client_start (void *cls, const struct StartMessage *start)
3986{
3987 struct TransportClient *tc = cls;
3988 uint32_t options;
3989
3990 options = ntohl (start->options);
3991 if ((0 != (1 & options)) &&
3992 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3993 {
3994 /* client thinks this is a different peer, reject */
3995 GNUNET_break (0);
3996 GNUNET_SERVICE_client_drop (tc->client);
3997 return;
3998 }
3999 if (CT_NONE != tc->type)
4000 {
4001 GNUNET_break (0);
4002 GNUNET_SERVICE_client_drop (tc->client);
4003 return;
4004 }
4005 tc->type = CT_CORE;
4006 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4007 "New CORE client with PID %s registered\n",
4008 GNUNET_i2s (&start->self));
4009 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
4010 &notify_client_connect_info,
4011 tc);
4012 GNUNET_SERVICE_client_continue (tc->client);
4013}
4014
4015
4016/**
4017 * Client asked for transmission to a peer. Process the request.
4018 *
4019 * @param cls the client
4020 * @param obm the send message that was sent
4021 */
4022static int
4023check_client_send (void *cls, const struct OutboundMessage *obm)
4024{
4025 struct TransportClient *tc = cls;
4026 uint16_t size;
4027 const struct GNUNET_MessageHeader *obmm;
4028
4029 if (CT_CORE != tc->type)
4030 {
4031 GNUNET_break (0);
4032 return GNUNET_SYSERR;
4033 }
4034 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
4035 if (size < sizeof(struct GNUNET_MessageHeader))
4036 {
4037 GNUNET_break (0);
4038 return GNUNET_SYSERR;
4039 }
4040 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4041 if (size != ntohs (obmm->size))
4042 {
4043 GNUNET_break (0);
4044 return GNUNET_SYSERR;
4045 }
4046 return GNUNET_OK;
4047}
4048
4049
4050/**
4051 * Send a response to the @a pm that we have processed a "send"
4052 * request. Sends a confirmation to the "core" client responsible for
4053 * the original request and free's @a pm.
4054 *
4055 * @param pm handle to the original pending message
4056 */
4057static void
4058client_send_response (struct PendingMessage *pm)
4059{
4060 struct TransportClient *tc = pm->client;
4061 struct VirtualLink *vl = pm->vl;
4062
4063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4064 "client send response\n");
4065 if (NULL != tc)
4066 {
4067 struct GNUNET_MQ_Envelope *env;
4068 struct SendOkMessage *so_msg;
4069
4070 env = GNUNET_MQ_msg (so_msg, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
4071 so_msg->peer = vl->target;
4072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4073 "Confirming transmission of <%llu> to %s\n",
4074 pm->logging_uuid,
4075 GNUNET_i2s (&vl->target));
4076 GNUNET_MQ_send (tc->mq, env);
4077 }
4078 free_pending_message (pm);
4079}
4080
4081
4082/**
4083 * Pick @a hops_array_length random DV paths satisfying @a options
4084 *
4085 * @param dv data structure to pick paths from
4086 * @param options constraints to satisfy
4087 * @param hops_array[out] set to the result
4088 * @param hops_array_length length of the @a hops_array
4089 * @return number of entries set in @a hops_array
4090 */
4091static unsigned int
4092pick_random_dv_hops (const struct DistanceVector *dv,
4093 enum RouteMessageOptions options,
4094 struct DistanceVectorHop **hops_array,
4095 unsigned int hops_array_length)
4096{
4097 uint64_t choices[hops_array_length];
4098 uint64_t num_dv;
4099 unsigned int dv_count;
4100
4101 /* Pick random vectors, but weighted by distance, giving more weight
4102 to shorter vectors */
4103 num_dv = 0;
4104 dv_count = 0;
4105 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4106 pos = pos->next_dv)
4107 {
4108 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4109 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4110 .rel_value_us == 0))
4111 continue; /* pos unconfirmed and confirmed required */
4112 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
4113 dv_count++;
4114 }
4115 if (0 == dv_count)
4116 return 0;
4117 if (dv_count <= hops_array_length)
4118 {
4119 dv_count = 0;
4120 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4121 pos = pos->next_dv)
4122 hops_array[dv_count++] = pos;
4123 return dv_count;
4124 }
4125 for (unsigned int i = 0; i < hops_array_length; i++)
4126 {
4127 int ok = GNUNET_NO;
4128 while (GNUNET_NO == ok)
4129 {
4130 choices[i] =
4131 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
4132 ok = GNUNET_YES;
4133 for (unsigned int j = 0; j < i; j++)
4134 if (choices[i] == choices[j])
4135 {
4136 ok = GNUNET_NO;
4137 break;
4138 }
4139 }
4140 }
4141 dv_count = 0;
4142 num_dv = 0;
4143 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4144 pos = pos->next_dv)
4145 {
4146 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
4147
4148 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4149 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4150 .rel_value_us == 0))
4151 continue; /* pos unconfirmed and confirmed required */
4152 for (unsigned int i = 0; i < hops_array_length; i++)
4153 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
4154 hops_array[dv_count++] = pos;
4155 num_dv += delta;
4156 }
4157 return dv_count;
4158}
4159
4160
4161/**
4162 * Communicator started. Test message is well-formed.
4163 *
4164 * @param cls the client
4165 * @param cam the send message that was sent
4166 */
4167static int
4168check_communicator_available (
4169 void *cls,
4170 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4171{
4172 struct TransportClient *tc = cls;
4173 uint16_t size;
4174
4175 if (CT_NONE != tc->type)
4176 {
4177 GNUNET_break (0);
4178 return GNUNET_SYSERR;
4179 }
4180 tc->type = CT_COMMUNICATOR;
4181 size = ntohs (cam->header.size) - sizeof(*cam);
4182 if (0 == size)
4183 return GNUNET_OK; /* receive-only communicator */
4184 GNUNET_MQ_check_zero_termination (cam);
4185 return GNUNET_OK;
4186}
4187
4188
4189/**
4190 * Send ACK to communicator (if requested) and free @a cmc.
4191 *
4192 * @param cmc context for which we are done handling the message
4193 */
4194static void
4195finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4196{
4197 if (0 != ntohl (cmc->im.fc_on))
4198 {
4199 /* send ACK when done to communicator for flow control! */
4200 struct GNUNET_MQ_Envelope *env;
4201 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4202
4203 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4204 ack->reserved = htonl (0);
4205 ack->fc_id = cmc->im.fc_id;
4206 ack->sender = cmc->im.sender;
4207 GNUNET_MQ_send (cmc->tc->mq, env);
4208 }
4209 GNUNET_SERVICE_client_continue (cmc->tc->client);
4210 GNUNET_free (cmc);
4211}
4212
4213
4214/**
4215 * Client confirms that it is done handling message(s) to a particular
4216 * peer. We may now provide more messages to CORE for this peer.
4217 *
4218 * Notifies the respective queues that more messages can now be received.
4219 *
4220 * @param cls the client
4221 * @param rom the message that was sent
4222 */
4223static void
4224handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
4225{
4226 struct TransportClient *tc = cls;
4227 struct VirtualLink *vl;
4228 uint32_t delta;
4229 struct CommunicatorMessageContext *cmc;
4230
4231 if (CT_CORE != tc->type)
4232 {
4233 GNUNET_break (0);
4234 GNUNET_SERVICE_client_drop (tc->client);
4235 return;
4236 }
4237 vl = lookup_virtual_link (&rom->peer);
4238 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4239 {
4240 GNUNET_STATISTICS_update (GST_stats,
4241 "# RECV_OK dropped: virtual link unknown",
4242 1,
4243 GNUNET_NO);
4244 GNUNET_SERVICE_client_continue (tc->client);
4245 return;
4246 }
4247 delta = ntohl (rom->increase_window_delta);
4248 vl->core_recv_window += delta;
4249 if (vl->core_recv_window <= 0)
4250 return;
4251 /* resume communicators */
4252 while (NULL != (cmc = vl->cmc_tail))
4253 {
4254 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4255 finish_cmc_handling (cmc);
4256 }
4257}
4258
4259
4260/**
4261 * Communicator started. Process the request.
4262 *
4263 * @param cls the client
4264 * @param cam the send message that was sent
4265 */
4266static void
4267handle_communicator_available (
4268 void *cls,
4269 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4270{
4271 struct TransportClient *tc = cls;
4272 uint16_t size;
4273
4274 size = ntohs (cam->header.size) - sizeof(*cam);
4275 if (0 == size)
4276 {
4277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4278 "Receive-only communicator connected\n");
4279 return; /* receive-only communicator */
4280 }
4281 tc->details.communicator.address_prefix =
4282 GNUNET_strdup ((const char *) &cam[1]);
4283 tc->details.communicator.cc =
4284 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
4285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4286 "Communicator with prefix `%s' connected\n",
4287 tc->details.communicator.address_prefix);
4288 GNUNET_SERVICE_client_continue (tc->client);
4289}
4290
4291
4292/**
4293 * Communicator requests backchannel transmission. Check the request.
4294 *
4295 * @param cls the client
4296 * @param cb the send message that was sent
4297 * @return #GNUNET_OK if message is well-formed
4298 */
4299static int
4300check_communicator_backchannel (
4301 void *cls,
4302 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4303{
4304 const struct GNUNET_MessageHeader *inbox;
4305 const char *is;
4306 uint16_t msize;
4307 uint16_t isize;
4308
4309 (void) cls;
4310 msize = ntohs (cb->header.size) - sizeof(*cb);
4311 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4312 isize = ntohs (inbox->size);
4313 if (isize >= msize)
4314 {
4315 GNUNET_break (0);
4316 return GNUNET_SYSERR;
4317 }
4318 is = (const char *) inbox;
4319 is += isize;
4320 msize -= isize;
4321 GNUNET_assert (0 < msize);
4322 if ('\0' != is[msize - 1])
4323 {
4324 GNUNET_break (0);
4325 return GNUNET_SYSERR;
4326 }
4327 return GNUNET_OK;
4328}
4329
4330
4331/**
4332 * Ensure ephemeral keys in our @a dv are current. If no current one exists,
4333 * set it up.
4334 *
4335 * @param dv[in,out] virtual link to update ephemeral for
4336 */
4337static void
4338update_ephemeral (struct DistanceVector *dv)
4339{
4340 struct EphemeralConfirmationPS ec;
4341
4342 if (0 !=
4343 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
4344 return;
4345 dv->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4346 dv->ephemeral_validity =
4347 GNUNET_TIME_absolute_add (dv->monotime, EPHEMERAL_VALIDITY);
4348 GNUNET_CRYPTO_ecdhe_key_create (&dv->private_key);
4349 GNUNET_CRYPTO_ecdhe_key_get_public (&dv->private_key, &dv->ephemeral_key);
4350 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4351 ec.target = dv->target;
4352 ec.ephemeral_key = dv->ephemeral_key;
4353 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4354 ec.purpose.size = htonl (sizeof(ec));
4355 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4356 &ec,
4357 &dv->sender_sig);
4358}
4359
4360
4361/**
4362 * Send the message @a payload on @a queue.
4363 *
4364 * @param queue the queue to use for transmission
4365 * @param pm pending message to update once transmission is done, may be NULL!
4366 * @param payload the payload to send (encapsulated in a
4367 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4368 * @param payload_size number of bytes in @a payload
4369 */
4370static void
4371queue_send_msg (struct Queue *queue,
4372 struct PendingMessage *pm,
4373 const void *payload,
4374 size_t payload_size)
4375{
4376 struct Neighbour *n = queue->neighbour;
4377 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4378 struct GNUNET_MQ_Envelope *env;
4379
4380 GNUNET_log (
4381 GNUNET_ERROR_TYPE_DEBUG,
4382 "Queueing %u bytes of payload for transmission <%llu> on queue %llu to %s\n",
4383 (unsigned int) payload_size,
4384 (NULL == pm) ? 0 : pm->logging_uuid,
4385 (unsigned long long) queue->qid,
4386 GNUNET_i2s (&queue->neighbour->pid));
4387 env = GNUNET_MQ_msg_extra (smt,
4388 payload_size,
4389 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4390 smt->qid = queue->qid;
4391 smt->mid = queue->mid_gen;
4392 smt->receiver = n->pid;
4393 memcpy (&smt[1], payload, payload_size);
4394 {
4395 /* Pass the env to the communicator of queue for transmission. */
4396 struct QueueEntry *qe;
4397
4398 qe = GNUNET_new (struct QueueEntry);
4399 qe->mid = queue->mid_gen++;
4400 qe->queue = queue;
4401 if (NULL != pm)
4402 {
4403 qe->pm = pm;
4404 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
4405 // GNUNET_assert (NULL == pm->qe);
4406 /*if (NULL != pm->qe)
4407 {
4408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4409 "Retransmitting message <%llu> remove pm from qe with MID: %llu \n",
4410 pm->logging_uuid,
4411 (unsigned long long) pm->qe->mid);
4412 pm->qe->pm = NULL;
4413 }*/
4414 pm->qe = qe;
4415 }
4416 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4417 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4418 queue->queue_length++;
4419 queue->tc->details.communicator.total_queue_length++;
4420 if (0 == queue->q_capacity)
4421 return;
4422 if (GNUNET_NO == queue->unlimited_length)
4423 queue->q_capacity--;
4424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4425 "Queue %s with qid %u has capacity %lu\n",
4426 queue->address,
4427 queue->qid,
4428 queue->q_capacity);
4429 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4430 queue->tc->details.communicator.total_queue_length)
4431 queue->idle = GNUNET_NO;
4432 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4433 queue->idle = GNUNET_NO;
4434 if (0 == queue->q_capacity)
4435 queue->idle = GNUNET_NO;
4436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4437 "Sending message MID %llu of type %u (%u) and size %u with MQ %p\n",
4438 smt->mid,
4439 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
4440 ntohs (smt->header.size),
4441 payload_size,
4442 queue->tc->mq);
4443 GNUNET_MQ_send (queue->tc->mq, env);
4444 }
4445}
4446
4447
4448/**
4449 * Pick a queue of @a n under constraints @a options and schedule
4450 * transmission of @a hdr.
4451 *
4452 * @param n neighbour to send to
4453 * @param hdr message to send as payload
4454 * @param options whether queues must be confirmed or not,
4455 * and whether we may pick multiple (2) queues
4456 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4457 */
4458static struct GNUNET_TIME_Relative
4459route_via_neighbour (const struct Neighbour *n,
4460 const struct GNUNET_MessageHeader *hdr,
4461 enum RouteMessageOptions options)
4462{
4463 struct GNUNET_TIME_Absolute now;
4464 unsigned int candidates;
4465 unsigned int sel1;
4466 unsigned int sel2;
4467 struct GNUNET_TIME_Relative rtt;
4468
4469 /* Pick one or two 'random' queues from n (under constraints of options) */
4470 now = GNUNET_TIME_absolute_get ();
4471 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4472 weight in the future; weight could be assigned by observed
4473 bandwidth (note: not sure if we should do this for this type
4474 of control traffic though). */
4475 candidates = 0;
4476 for (struct Queue *pos = n->queue_head; NULL != pos;
4477 pos = pos->next_neighbour)
4478 {
4479 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4480 (pos->validated_until.abs_value_us > now.abs_value_us))
4481 candidates++;
4482 }
4483 if (0 == candidates)
4484 {
4485 /* This can happen rarely if the last confirmed queue timed
4486 out just as we were beginning to process this message. */
4487 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4488 "Could not route message of type %u to %s: no valid queue\n",
4489 ntohs (hdr->type),
4490 GNUNET_i2s (&n->pid));
4491 GNUNET_STATISTICS_update (GST_stats,
4492 "# route selection failed (all no valid queue)",
4493 1,
4494 GNUNET_NO);
4495 return GNUNET_TIME_UNIT_FOREVER_REL;
4496 }
4497
4498 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4499 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4500 if (0 == (options & RMO_REDUNDANT))
4501 sel2 = candidates; /* picks none! */
4502 else
4503 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4504 candidates = 0;
4505 for (struct Queue *pos = n->queue_head; NULL != pos;
4506 pos = pos->next_neighbour)
4507 {
4508 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4509 (pos->validated_until.abs_value_us > now.abs_value_us))
4510 {
4511 if ((sel1 == candidates) || (sel2 == candidates))
4512 {
4513 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4514 "Routing message of type %u to %s using %s (#%u)\n",
4515 ntohs (hdr->type),
4516 GNUNET_i2s (&n->pid),
4517 pos->address,
4518 (sel1 == candidates) ? 1 : 2);
4519 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
4520 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4521 }
4522 candidates++;
4523 }
4524 }
4525 return rtt;
4526}
4527
4528
4529/**
4530 * Structure of the key material used to encrypt backchannel messages.
4531 */
4532struct DVKeyState
4533{
4534 /**
4535 * State of our block cipher.
4536 */
4537 gcry_cipher_hd_t cipher;
4538
4539 /**
4540 * Actual key material.
4541 */
4542 struct
4543 {
4544 /**
4545 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4546 */
4547 struct GNUNET_CRYPTO_AuthKey hmac_key;
4548
4549 /**
4550 * Symmetric key to use for encryption.
4551 */
4552 char aes_key[256 / 8];
4553
4554 /**
4555 * Counter value to use during setup.
4556 */
4557 char aes_ctr[128 / 8];
4558 } material;
4559};
4560
4561
4562/**
4563 * Given the key material in @a km and the initialization vector
4564 * @a iv, setup the key material for the backchannel in @a key.
4565 *
4566 * @param km raw master secret
4567 * @param iv initialization vector
4568 * @param key[out] symmetric cipher and HMAC state to generate
4569 */
4570static void
4571dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4572 const struct GNUNET_ShortHashCode *iv,
4573 struct DVKeyState *key)
4574{
4575 /* must match #dh_key_derive_eph_pub */
4576 GNUNET_assert (GNUNET_YES ==
4577 GNUNET_CRYPTO_kdf (&key->material,
4578 sizeof(key->material),
4579 "transport-backchannel-key",
4580 strlen ("transport-backchannel-key"),
4581 km,
4582 sizeof(*km),
4583 iv,
4584 sizeof(*iv),
4585 NULL));
4586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4587 "Deriving backchannel key based on KM %s and IV %s\n",
4588 GNUNET_h2s (km),
4589 GNUNET_sh2s (iv));
4590 GNUNET_assert (0 == gcry_cipher_open (&key->cipher,
4591 GCRY_CIPHER_AES256 /* low level: go for speed */,
4592 GCRY_CIPHER_MODE_CTR,
4593 0 /* flags */));
4594 GNUNET_assert (0 == gcry_cipher_setkey (key->cipher,
4595 &key->material.aes_key,
4596 sizeof(key->material.aes_key)));
4597 gcry_cipher_setctr (key->cipher,
4598 &key->material.aes_ctr,
4599 sizeof(key->material.aes_ctr));
4600}
4601
4602
4603/**
4604 * Derive backchannel encryption key material from @a priv_ephemeral
4605 * and @a target and @a iv.
4606 *
4607 * @param priv_ephemeral ephemeral private key to use
4608 * @param target the target peer to encrypt to
4609 * @param iv unique IV to use
4610 * @param key[out] set to the key material
4611 */
4612static void
4613dh_key_derive_eph_pid (
4614 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4615 const struct GNUNET_PeerIdentity *target,
4616 const struct GNUNET_ShortHashCode *iv,
4617 struct DVKeyState *key)
4618{
4619 struct GNUNET_HashCode km;
4620
4621 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4622 &target->public_key,
4623 &km));
4624 dv_setup_key_state_from_km (&km, iv, key);
4625}
4626
4627
4628/**
4629 * Derive backchannel encryption key material from #GST_my_private_key
4630 * and @a pub_ephemeral and @a iv.
4631 *
4632 * @param priv_ephemeral ephemeral private key to use
4633 * @param target the target peer to encrypt to
4634 * @param iv unique IV to use
4635 * @param key[out] set to the key material
4636 */
4637static void
4638dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4639 const struct GNUNET_ShortHashCode *iv,
4640 struct DVKeyState *key)
4641{
4642 struct GNUNET_HashCode km;
4643
4644 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4645 pub_ephemeral,
4646 &km));
4647 dv_setup_key_state_from_km (&km, iv, key);
4648}
4649
4650
4651/**
4652 * Do HMAC calculation for backchannel messages over @a data using key
4653 * material from @a key.
4654 *
4655 * @param key key material (from DH)
4656 * @param hmac[out] set to the HMAC
4657 * @param data data to perform HMAC calculation over
4658 * @param data_size number of bytes in @a data
4659 */
4660static void
4661dv_hmac (const struct DVKeyState *key,
4662 struct GNUNET_HashCode *hmac,
4663 const void *data,
4664 size_t data_size)
4665{
4666 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4667}
4668
4669
4670/**
4671 * Perform backchannel encryption using symmetric secret in @a key
4672 * to encrypt data from @a in to @a dst.
4673 *
4674 * @param key[in,out] key material to use
4675 * @param dst where to write the result
4676 * @param in input data to encrypt (plaintext)
4677 * @param in_size number of bytes of input in @a in and available at @a dst
4678 */
4679static void
4680dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
4681{
4682 GNUNET_assert (0 ==
4683 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4684}
4685
4686
4687/**
4688 * Perform backchannel encryption using symmetric secret in @a key
4689 * to encrypt data from @a in to @a dst.
4690 *
4691 * @param key[in,out] key material to use
4692 * @param ciph cipher text to decrypt
4693 * @param out[out] output data to generate (plaintext)
4694 * @param out_size number of bytes of input in @a ciph and available in @a out
4695 */
4696static void
4697dv_decrypt (struct DVKeyState *key,
4698 void *out,
4699 const void *ciph,
4700 size_t out_size)
4701{
4702 GNUNET_assert (
4703 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4704}
4705
4706
4707/**
4708 * Clean up key material in @a key.
4709 *
4710 * @param key key material to clean up (memory must not be free'd!)
4711 */
4712static void
4713dv_key_clean (struct DVKeyState *key)
4714{
4715 gcry_cipher_close (key->cipher);
4716 GNUNET_CRYPTO_zero_keys (&key->material, sizeof(key->material));
4717}
4718
4719
4720/**
4721 * Function to call to further operate on the now DV encapsulated
4722 * message @a hdr, forwarding it via @a next_hop under respect of
4723 * @a options.
4724 *
4725 * @param cls closure
4726 * @param next_hop next hop of the DV path
4727 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
4728 * @param options options of the original message
4729 */
4730typedef void (*DVMessageHandler) (void *cls,
4731 struct Neighbour *next_hop,
4732 const struct GNUNET_MessageHeader *hdr,
4733 enum RouteMessageOptions options);
4734
4735/**
4736 * Pick a path of @a dv under constraints @a options and schedule
4737 * transmission of @a hdr.
4738 *
4739 * @param target neighbour to ultimately send to
4740 * @param num_dvhs length of the @a dvhs array
4741 * @param dvhs array of hops to send the message to
4742 * @param hdr message to send as payload
4743 * @param use function to call with the encapsulated message
4744 * @param use_cls closure for @a use
4745 * @param options whether path must be confirmed or not, to be passed to @a use
4746 * @param shall this TransportDVBoxMessage be forwarded without flow control.
4747 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4748 */
4749static struct GNUNET_TIME_Relative
4750encapsulate_for_dv (struct DistanceVector *dv,
4751 unsigned int num_dvhs,
4752 struct DistanceVectorHop **dvhs,
4753 const struct GNUNET_MessageHeader *hdr,
4754 DVMessageHandler use,
4755 void *use_cls,
4756 enum RouteMessageOptions options,
4757 enum GNUNET_GenericReturnValue without_fc)
4758{
4759 struct TransportDVBoxMessage box_hdr;
4760 struct TransportDVBoxPayloadP payload_hdr;
4761 uint16_t enc_body_size = ntohs (hdr->size);
4762 char enc[sizeof(struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
4763 struct TransportDVBoxPayloadP *enc_payload_hdr =
4764 (struct TransportDVBoxPayloadP *) enc;
4765 struct DVKeyState *key;
4766 struct GNUNET_TIME_Relative rtt;
4767
4768 key = GNUNET_new (struct DVKeyState);
4769 /* Encrypt payload */
4770 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
4771 box_hdr.total_hops = htons (0);
4772 box_hdr.without_fc = htons (without_fc);
4773 update_ephemeral (dv);
4774 box_hdr.ephemeral_key = dv->ephemeral_key;
4775 payload_hdr.sender_sig = dv->sender_sig;
4776
4777 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4778 &box_hdr.iv,
4779 sizeof(box_hdr.iv));
4780 dh_key_derive_eph_pid (&dv->private_key, &dv->target, &box_hdr.iv, key);
4781 payload_hdr.sender = GST_my_identity;
4782 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4783 dv_encrypt (key, &payload_hdr, enc_payload_hdr, sizeof(payload_hdr));
4784 dv_encrypt (key,
4785 hdr,
4786 &enc[sizeof(struct TransportDVBoxPayloadP)],
4787 enc_body_size);
4788 dv_hmac (key, &box_hdr.hmac, enc, sizeof(enc));
4789 dv_key_clean (key);
4790 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4791 /* For each selected path, take the pre-computed header and body
4792 and add the path in the middle of the message; then send it. */
4793 for (unsigned int i = 0; i < num_dvhs; i++)
4794 {
4795 struct DistanceVectorHop *dvh = dvhs[i];
4796 unsigned int num_hops = dvh->distance + 1;
4797 char buf[sizeof(struct TransportDVBoxMessage)
4798 + sizeof(struct GNUNET_PeerIdentity) * num_hops
4799 + sizeof(struct TransportDVBoxPayloadP)
4800 + enc_body_size] GNUNET_ALIGN;
4801 struct GNUNET_PeerIdentity *dhops;
4802
4803 box_hdr.header.size = htons (sizeof(buf));
4804 box_hdr.orig_size = htons (sizeof(buf));
4805 box_hdr.num_hops = htons (num_hops);
4806 memcpy (buf, &box_hdr, sizeof(box_hdr));
4807 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
4808 memcpy (dhops,
4809 dvh->path,
4810 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
4811 dhops[dvh->distance] = dv->target;
4812 if (GNUNET_EXTRA_LOGGING > 0)
4813 {
4814 char *path;
4815
4816 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
4817 for (unsigned int j = 0; j < num_hops; j++)
4818 {
4819 char *tmp;
4820
4821 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
4822 GNUNET_free (path);
4823 path = tmp;
4824 }
4825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4826 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
4827 ntohs (hdr->type),
4828 GNUNET_i2s (&dv->target),
4829 i + 1,
4830 num_dvhs,
4831 path);
4832 GNUNET_free (path);
4833 }
4834 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
4835 memcpy (&dhops[num_hops], enc, sizeof(enc));
4836 use (use_cls,
4837 dvh->next_hop,
4838 (const struct GNUNET_MessageHeader *) buf,
4839 options);
4840 GNUNET_free (key);
4841 }
4842 return rtt;
4843}
4844
4845
4846/**
4847 * Wrapper around #route_via_neighbour() that matches the
4848 * #DVMessageHandler structure.
4849 *
4850 * @param cls unused
4851 * @param next_hop where to send next
4852 * @param hdr header of the message to send
4853 * @param options message options for queue selection
4854 */
4855static void
4856send_dv_to_neighbour (void *cls,
4857 struct Neighbour *next_hop,
4858 const struct GNUNET_MessageHeader *hdr,
4859 enum RouteMessageOptions options)
4860{
4861 (void) cls;
4862 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
4863}
4864
4865
4866/**
4867 * We need to transmit @a hdr to @a target. If necessary, this may
4868 * involve DV routing. This function routes without applying flow
4869 * control or congestion control and should only be used for control
4870 * traffic.
4871 *
4872 * @param target peer to receive @a hdr
4873 * @param hdr header of the message to route and #GNUNET_free()
4874 * @param options which transmission channels are allowed
4875 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4876 */
4877static struct GNUNET_TIME_Relative
4878route_control_message_without_fc (struct VirtualLink *vl,
4879// route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4880 const struct GNUNET_MessageHeader *hdr,
4881 enum RouteMessageOptions options)
4882{
4883 // struct VirtualLink *vl;
4884 struct Neighbour *n;
4885 struct DistanceVector *dv;
4886 struct GNUNET_TIME_Relative rtt1;
4887 struct GNUNET_TIME_Relative rtt2;
4888 const struct GNUNET_PeerIdentity *target = &vl->target;
4889
4890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4891 "Trying to route message of type %u to %s without fc\n",
4892 ntohs (hdr->type),
4893 GNUNET_i2s (target));
4894
4895 // TODO Do this elsewhere. vl should be given as parameter to method.
4896 // vl = lookup_virtual_link (target);
4897 GNUNET_assert (NULL != vl && GNUNET_YES == vl->confirmed);
4898 if (NULL == vl)
4899 return GNUNET_TIME_UNIT_FOREVER_REL;
4900 n = vl->n;
4901 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4902 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4903 {
4904 /* if confirmed is required, and we do not have anything
4905 confirmed, drop respective options */
4906 if (NULL == n)
4907 n = lookup_neighbour (target);
4908 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4909 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4910 }
4911 if ((NULL == n) && (NULL == dv))
4912 {
4913 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4914 "Cannot route message of type %u to %s: no route\n",
4915 ntohs (hdr->type),
4916 GNUNET_i2s (target));
4917 GNUNET_STATISTICS_update (GST_stats,
4918 "# Messages dropped in routing: no acceptable method",
4919 1,
4920 GNUNET_NO);
4921 return GNUNET_TIME_UNIT_FOREVER_REL;
4922 }
4923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4924 "Routing message of type %u to %s with options %X\n",
4925 ntohs (hdr->type),
4926 GNUNET_i2s (target),
4927 (unsigned int) options);
4928 /* If both dv and n are possible and we must choose:
4929 flip a coin for the choice between the two; for now 50/50 */
4930 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4931 {
4932 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4933 n = NULL;
4934 else
4935 dv = NULL;
4936 }
4937 if ((NULL != n) && (NULL != dv))
4938 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4939 enough for redundancy, so clear the flag. */
4940 rtt1 = GNUNET_TIME_UNIT_FOREVER_REL;
4941 rtt2 = GNUNET_TIME_UNIT_FOREVER_REL;
4942 if (NULL != n)
4943 {
4944 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4945 "Try to route message of type %u to %s without fc via neighbour\n",
4946 ntohs (hdr->type),
4947 GNUNET_i2s (target));
4948 rtt1 = route_via_neighbour (n, hdr, options);
4949 }
4950 if (NULL != dv)
4951 {
4952 struct DistanceVectorHop *hops[2];
4953 unsigned int res;
4954
4955 res = pick_random_dv_hops (dv,
4956 options,
4957 hops,
4958 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4959 if (0 == res)
4960 {
4961 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4962 "Failed to route message, could not determine DV path\n");
4963 return rtt1;
4964 }
4965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4966 "encapsulate_for_dv 1\n");
4967 rtt2 = encapsulate_for_dv (dv,
4968 res,
4969 hops,
4970 hdr,
4971 &send_dv_to_neighbour,
4972 NULL,
4973 options & (~RMO_REDUNDANT),
4974 GNUNET_YES);
4975 }
4976 return GNUNET_TIME_relative_min (rtt1, rtt2);
4977}
4978
4979
4980static void
4981consider_sending_fc (void *cls);
4982
4983/**
4984 * Something changed on the virtual link with respect to flow
4985 * control. Consider retransmitting the FC window size.
4986 *
4987 * @param cls a `struct VirtualLink` to work with
4988 */
4989static void
4990task_consider_sending_fc (void *cls)
4991{
4992 struct VirtualLink *vl = cls;
4993 vl->fc_retransmit_task = NULL;
4994 consider_sending_fc (cls);
4995}
4996
4997
4998/**
4999 * Something changed on the virtual link with respect to flow
5000 * control. Consider retransmitting the FC window size.
5001 *
5002 * @param cls a `struct VirtualLink` to work with
5003 */
5004static void
5005consider_sending_fc (void *cls)
5006{
5007 struct VirtualLink *vl = cls;
5008 struct GNUNET_TIME_Absolute monotime;
5009 struct TransportFlowControlMessage fc;
5010 struct GNUNET_TIME_Relative duration;
5011 struct GNUNET_TIME_Relative rtt;
5012
5013 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission);
5014 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
5015 it always! */
5016 /* For example, we should probably ONLY do this if a bit more than
5017 an RTT has passed, or if the window changed "significantly" since
5018 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
5019 need an estimate for the bandwidth-delay-product for the entire
5020 VL, as that determines "significantly". We have the delay, but
5021 the bandwidth statistics need to be added for the VL!*/(void) duration;
5022
5023 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5024 "Sending FC seq %u to %s with new window %llu\n",
5025 (unsigned int) vl->fc_seq_gen,
5026 GNUNET_i2s (&vl->target),
5027 (unsigned long long) vl->incoming_fc_window_size);
5028 monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
5029 vl->last_fc_transmission = monotime;
5030 fc.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL);
5031 fc.header.size = htons (sizeof(fc));
5032 fc.seq = htonl (vl->fc_seq_gen++);
5033 fc.inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size);
5034 fc.outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
5035 fc.outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
5036 fc.sender_time = GNUNET_TIME_absolute_hton (monotime);
5037 rtt = route_control_message_without_fc (vl, &fc.header, RMO_DV_ALLOWED);
5038 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
5039 {
5040 rtt = GNUNET_TIME_UNIT_SECONDS;
5041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5042 "FC retransmission to %s failed, will retry in %s\n",
5043 GNUNET_i2s (&vl->target),
5044 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
5045 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
5046 }
5047 else
5048 {
5049 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
5050 vl->last_fc_rtt = rtt;
5051 }
5052 if (NULL != vl->fc_retransmit_task)
5053 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
5054 if (MAX_FC_RETRANSMIT_COUNT == vl->fc_retransmit_count)
5055 {
5056 rtt = GNUNET_TIME_UNIT_MINUTES;
5057 vl->fc_retransmit_count = 0;
5058 }
5059 vl->fc_retransmit_task =
5060 GNUNET_SCHEDULER_add_delayed (rtt, &task_consider_sending_fc, vl);
5061 vl->fc_retransmit_count++;
5062}
5063
5064
5065/**
5066 * There is a message at the head of the pending messages for @a vl
5067 * which may be ready for transmission. Check if a queue is ready to
5068 * take it.
5069 *
5070 * This function must (1) check for flow control to ensure that we can
5071 * right now send to @a vl, (2) check that the pending message in the
5072 * queue is actually eligible, (3) determine if any applicable queue
5073 * (direct neighbour or DVH path) is ready to accept messages, and
5074 * (4) prioritize based on the preferences associated with the
5075 * pending message.
5076 *
5077 * So yeah, easy.
5078 *
5079 * @param vl virtual link where we should check for transmission
5080 */
5081static void
5082check_vl_transmission (struct VirtualLink *vl)
5083{
5084 struct Neighbour *n = vl->n;
5085 struct DistanceVector *dv = vl->dv;
5086 struct GNUNET_TIME_Absolute now;
5087 struct VirtualLink *vl_next_hop;
5088 int elig;
5089
5090 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5091 "check_vl_transmission to target %s\n",
5092 GNUNET_i2s (&vl->target));
5093 /* Check that we have an eligible pending message!
5094 (cheaper than having #transmit_on_queue() find out!) */
5095 elig = GNUNET_NO;
5096 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
5097 pm = pm->next_vl)
5098 {
5099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5100 "check_vl_transmission loop\n");
5101 if (NULL != pm->qe)
5102 continue; /* not eligible, is in a queue! */
5103 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
5104 vl->outbound_fc_window_size)
5105 {
5106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5107 "Stalled message %lu transmission on VL %s due to flow control: %llu < %llu\n",
5108 pm->logging_uuid,
5109 GNUNET_i2s (&vl->target),
5110 (unsigned long long) vl->outbound_fc_window_size,
5111 (unsigned long long) (pm->bytes_msg
5112 + vl->outbound_fc_window_size_used));
5113 consider_sending_fc (vl);
5114 return; /* We have a message, but flow control says "nope" */
5115 }
5116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5117 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
5118 GNUNET_i2s (&vl->target));
5119 /* Notify queues at direct neighbours that we are interested */
5120 now = GNUNET_TIME_absolute_get ();
5121 if (NULL != n)
5122 {
5123 for (struct Queue *queue = n->queue_head; NULL != queue;
5124 queue = queue->next_neighbour)
5125 {
5126 if ((GNUNET_YES == queue->idle) &&
5127 (queue->validated_until.abs_value_us > now.abs_value_us))
5128 {
5129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5130 "Direct neighbour %s not stalled\n",
5131 GNUNET_i2s (&n->pid));
5132 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5133 queue,
5134 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
5135 elig = GNUNET_YES;
5136 }
5137 else
5138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5139 "Neighbour Queue QID: %u (%u) busy or invalid\n",
5140 queue->qid,
5141 queue->idle);
5142 }
5143 }
5144 /* Notify queues via DV that we are interested */
5145 if (NULL != dv)
5146 {
5147 /* Do DV with lower scheduler priority, which effectively means that
5148 IF a neighbour exists and is available, we prefer it. */
5149 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5150 pos = pos->next_dv)
5151 {
5152 struct Neighbour *nh = pos->next_hop;
5153
5154
5155 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
5156 continue; /* skip this one: path not validated */
5157 else
5158 {
5159 vl_next_hop = lookup_virtual_link (&nh->pid);
5160 if (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
5161 vl_next_hop->outbound_fc_window_size)
5162 {
5163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5164 "Stalled message %lu transmission on next hop %s due to flow control: %llu < %llu\n",
5165 pm->logging_uuid,
5166 GNUNET_i2s (&vl_next_hop->target),
5167 (unsigned long
5168 long) vl_next_hop->outbound_fc_window_size,
5169 (unsigned long long) (pm->bytes_msg
5170 + vl_next_hop->
5171 outbound_fc_window_size_used));
5172 consider_sending_fc (vl_next_hop);
5173 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
5174 }
5175 for (struct Queue *queue = nh->queue_head; NULL != queue;
5176 queue = queue->next_neighbour)
5177 if ((GNUNET_YES == queue->idle) &&
5178 (queue->validated_until.abs_value_us > now.abs_value_us))
5179 {
5180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5181 "Next hop neighbour %s not stalled\n",
5182 GNUNET_i2s (&nh->pid));
5183 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5184 queue,
5185 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
5186 elig = GNUNET_YES;
5187 }
5188 else
5189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5190 "DV Queue QID: %u (%u) busy or invalid\n",
5191 queue->qid,
5192 queue->idle);
5193 }
5194 }
5195 }
5196 if (GNUNET_YES == elig)
5197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5198 "Eligible message %lu of size %llu to %s: %llu/%llu\n",
5199 pm->logging_uuid,
5200 pm->bytes_msg,
5201 GNUNET_i2s (&vl->target),
5202 (unsigned long long) vl->outbound_fc_window_size,
5203 (unsigned long long) (pm->bytes_msg
5204 + vl->outbound_fc_window_size_used));
5205 break;
5206 }
5207}
5208
5209
5210/**
5211 * Client asked for transmission to a peer. Process the request.
5212 *
5213 * @param cls the client
5214 * @param obm the send message that was sent
5215 */
5216static void
5217handle_client_send (void *cls, const struct OutboundMessage *obm)
5218{
5219 struct TransportClient *tc = cls;
5220 struct PendingMessage *pm;
5221 const struct GNUNET_MessageHeader *obmm;
5222 uint32_t bytes_msg;
5223 struct VirtualLink *vl;
5224 enum GNUNET_MQ_PriorityPreferences pp;
5225
5226 GNUNET_assert (CT_CORE == tc->type);
5227 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5228 bytes_msg = ntohs (obmm->size);
5229 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
5230 vl = lookup_virtual_link (&obm->peer);
5231 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5232 {
5233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5234 "Don't have %s as a neighbour (anymore).\n",
5235 GNUNET_i2s (&obm->peer));
5236 /* Failure: don't have this peer as a neighbour (anymore).
5237 Might have gone down asynchronously, so this is NOT
5238 a protocol violation by CORE. Still count the event,
5239 as this should be rare. */
5240 GNUNET_SERVICE_client_continue (tc->client);
5241 GNUNET_STATISTICS_update (GST_stats,
5242 "# messages dropped (neighbour unknown)",
5243 1,
5244 GNUNET_NO);
5245 return;
5246 }
5247
5248 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
5249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5250 "1 created pm %p storing vl %p\n",
5251 pm,
5252 vl);
5253 pm->logging_uuid = logging_uuid_gen++;
5254 pm->prefs = pp;
5255 pm->client = tc;
5256 pm->vl = vl;
5257 pm->bytes_msg = bytes_msg;
5258 memcpy (&pm[1], obmm, bytes_msg);
5259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5260 "Sending %u bytes as <%llu> to %s\n",
5261 bytes_msg,
5262 pm->logging_uuid,
5263 GNUNET_i2s (&obm->peer));
5264 GNUNET_CONTAINER_MDLL_insert (client,
5265 tc->details.core.pending_msg_head,
5266 tc->details.core.pending_msg_tail,
5267 pm);
5268 GNUNET_CONTAINER_MDLL_insert (vl,
5269 vl->pending_msg_head,
5270 vl->pending_msg_tail,
5271 pm);
5272 check_vl_transmission (vl);
5273 GNUNET_SERVICE_client_continue (tc->client);
5274}
5275
5276
5277/**
5278 * Communicator requests backchannel transmission. Process the request.
5279 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
5280 * (which for now has exactly the same format, only a different message type)
5281 * and passes it on for routing.
5282 *
5283 * @param cls the client
5284 * @param cb the send message that was sent
5285 */
5286static void
5287handle_communicator_backchannel (
5288 void *cls,
5289 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
5290{
5291 struct Neighbour *n;
5292 struct VirtualLink *vl;
5293 struct TransportClient *tc = cls;
5294 const struct GNUNET_MessageHeader *inbox =
5295 (const struct GNUNET_MessageHeader *) &cb[1];
5296 uint16_t isize = ntohs (inbox->size);
5297 const char *is = ((const char *) &cb[1]) + isize;
5298 size_t slen = strlen (is) + 1;
5299 char
5300 mbuf[slen + isize
5301 + sizeof(struct
5302 TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
5303 struct TransportBackchannelEncapsulationMessage *be =
5304 (struct TransportBackchannelEncapsulationMessage *) mbuf;
5305
5306 /* 0-termination of 'is' was checked already in
5307 #check_communicator_backchannel() */
5308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5309 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
5310 GNUNET_i2s (&cb->pid),
5311 is,
5312 ntohs (inbox->type),
5313 ntohs (inbox->size));
5314 /* encapsulate and encrypt message */
5315 be->header.type =
5316 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
5317 be->header.size = htons (sizeof(mbuf));
5318 memcpy (&be[1], inbox, isize);
5319 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
5320 + isize],
5321 is,
5322 strlen (is) + 1);
5323 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
5324 vl = lookup_virtual_link (&cb->pid);
5325 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
5326 {
5327 route_control_message_without_fc (vl, &be->header, RMO_DV_ALLOWED);
5328 }
5329 else
5330 {
5331 /* Use route via neighbour */
5332 n = lookup_neighbour (&cb->pid);
5333 if (NULL != n)
5334 route_via_neighbour (
5335 n,
5336 &be->header,
5337 RMO_NONE);
5338 }
5339 GNUNET_SERVICE_client_continue (tc->client);
5340}
5341
5342
5343/**
5344 * Address of our peer added. Test message is well-formed.
5345 *
5346 * @param cls the client
5347 * @param aam the send message that was sent
5348 * @return #GNUNET_OK if message is well-formed
5349 */
5350static int
5351check_add_address (void *cls,
5352 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5353{
5354 struct TransportClient *tc = cls;
5355
5356 if (CT_COMMUNICATOR != tc->type)
5357 {
5358 GNUNET_break (0);
5359 return GNUNET_SYSERR;
5360 }
5361 GNUNET_MQ_check_zero_termination (aam);
5362 return GNUNET_OK;
5363}
5364
5365
5366/**
5367 * Ask peerstore to store our address.
5368 *
5369 * @param cls an `struct AddressListEntry *`
5370 */
5371static void
5372store_pi (void *cls);
5373
5374
5375/**
5376 * Function called when peerstore is done storing our address.
5377 *
5378 * @param cls a `struct AddressListEntry`
5379 * @param success #GNUNET_YES if peerstore was successful
5380 */
5381static void
5382peerstore_store_own_cb (void *cls, int success)
5383{
5384 struct AddressListEntry *ale = cls;
5385
5386 ale->sc = NULL;
5387 if (GNUNET_YES != success)
5388 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5389 "Failed to store our own address `%s' in peerstore!\n",
5390 ale->address);
5391 else
5392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5393 "Successfully stored our own address `%s' in peerstore!\n",
5394 ale->address);
5395 /* refresh period is 1/4 of expiration time, that should be plenty
5396 without being excessive. */
5397 ale->st =
5398 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
5399 4ULL),
5400 &store_pi,
5401 ale);
5402}
5403
5404
5405/**
5406 * Ask peerstore to store our address.
5407 *
5408 * @param cls an `struct AddressListEntry *`
5409 */
5410static void
5411store_pi (void *cls)
5412{
5413 struct AddressListEntry *ale = cls;
5414 void *addr;
5415 size_t addr_len;
5416 struct GNUNET_TIME_Absolute expiration;
5417
5418 ale->st = NULL;
5419 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
5420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5421 "Storing our address `%s' in peerstore until %s!\n",
5422 ale->address,
5423 GNUNET_STRINGS_absolute_time_to_string (expiration));
5424 GNUNET_HELLO_sign_address (ale->address,
5425 ale->nt,
5426 hello_mono_time,
5427 GST_my_private_key,
5428 &addr,
5429 &addr_len);
5430 ale->sc = GNUNET_PEERSTORE_store (peerstore,
5431 "transport",
5432 &GST_my_identity,
5433 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
5434 addr,
5435 addr_len,
5436 expiration,
5437 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5438 &peerstore_store_own_cb,
5439 ale);
5440 GNUNET_free (addr);
5441 if (NULL == ale->sc)
5442 {
5443 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5444 "Failed to store our address `%s' with peerstore\n",
5445 ale->address);
5446 ale->st =
5447 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
5448 }
5449}
5450
5451
5452/**
5453 * Address of our peer added. Process the request.
5454 *
5455 * @param cls the client
5456 * @param aam the send message that was sent
5457 */
5458static void
5459handle_add_address (void *cls,
5460 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5461{
5462 struct TransportClient *tc = cls;
5463 struct AddressListEntry *ale;
5464 size_t slen;
5465
5466 /* 0-termination of &aam[1] was checked in #check_add_address */
5467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5468 "Communicator added address `%s'!\n",
5469 (const char *) &aam[1]);
5470 slen = ntohs (aam->header.size) - sizeof(*aam);
5471 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
5472 ale->tc = tc;
5473 ale->address = (const char *) &ale[1];
5474 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
5475 ale->aid = aam->aid;
5476 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
5477 memcpy (&ale[1], &aam[1], slen);
5478 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5479 tc->details.communicator.addr_tail,
5480 ale);
5481 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5482 GNUNET_SERVICE_client_continue (tc->client);
5483}
5484
5485
5486/**
5487 * Address of our peer deleted. Process the request.
5488 *
5489 * @param cls the client
5490 * @param dam the send message that was sent
5491 */
5492static void
5493handle_del_address (void *cls,
5494 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5495{
5496 struct TransportClient *tc = cls;
5497 struct AddressListEntry *alen;
5498
5499 if (CT_COMMUNICATOR != tc->type)
5500 {
5501 GNUNET_break (0);
5502 GNUNET_SERVICE_client_drop (tc->client);
5503 return;
5504 }
5505 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5506 NULL != ale;
5507 ale = alen)
5508 {
5509 alen = ale->next;
5510 if (dam->aid != ale->aid)
5511 continue;
5512 GNUNET_assert (ale->tc == tc);
5513 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5514 "Communicator deleted address `%s'!\n",
5515 ale->address);
5516 free_address_list_entry (ale);
5517 GNUNET_SERVICE_client_continue (tc->client);
5518 return;
5519 }
5520 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5521 "Communicator removed address we did not even have.\n");
5522 GNUNET_SERVICE_client_continue (tc->client);
5523 // GNUNET_SERVICE_client_drop (tc->client);
5524}
5525
5526
5527/**
5528 * Given an inbound message @a msg from a communicator @a cmc,
5529 * demultiplex it based on the type calling the right handler.
5530 *
5531 * @param cmc context for demultiplexing
5532 * @param msg message to demultiplex
5533 */
5534static void
5535demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5536 const struct GNUNET_MessageHeader *msg);
5537
5538
5539/**
5540 * Function called when we are done giving a message of a certain
5541 * size to CORE and should thus decrement the number of bytes of
5542 * RAM reserved for that peer's MQ.
5543 *
5544 * @param cls a `struct CoreSentContext`
5545 */
5546static void
5547core_env_sent_cb (void *cls)
5548{
5549 struct CoreSentContext *ctx = cls;
5550 struct VirtualLink *vl = ctx->vl;
5551
5552 if (NULL == vl)
5553 {
5554 /* lost the link in the meantime, ignore */
5555 GNUNET_free (ctx);
5556 return;
5557 }
5558 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
5559 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
5560 vl->incoming_fc_window_size_ram -= ctx->size;
5561 vl->incoming_fc_window_size_used += ctx->isize;
5562 consider_sending_fc (vl);
5563 GNUNET_free (ctx);
5564}
5565
5566
5567/**
5568 * Communicator gave us an unencapsulated message to pass as-is to
5569 * CORE. Process the request.
5570 *
5571 * @param cls a `struct CommunicatorMessageContext` (must call
5572 * #finish_cmc_handling() when done)
5573 * @param mh the message that was received
5574 */
5575static void
5576handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
5577{
5578 struct CommunicatorMessageContext *cmc = cls;
5579 struct VirtualLink *vl;
5580 uint16_t size = ntohs (mh->size);
5581 int have_core;
5582
5583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5584 "Handling raw message of type %u with %u bytes\n",
5585 (unsigned int) ntohs (mh->type),
5586 (unsigned int) ntohs (mh->size));
5587
5588 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
5589 (size < sizeof(struct GNUNET_MessageHeader)))
5590 {
5591 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5592
5593 GNUNET_break (0);
5594 finish_cmc_handling (cmc);
5595 GNUNET_SERVICE_client_drop (client);
5596 return;
5597 }
5598 vl = lookup_virtual_link (&cmc->im.sender);
5599 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5600 {
5601 /* FIXME: sender is giving us messages for CORE but we don't have
5602 the link up yet! I *suspect* this can happen right now (i.e.
5603 sender has verified us, but we didn't verify sender), but if
5604 we pass this on, CORE would be confused (link down, messages
5605 arrive). We should investigate more if this happens often,
5606 or in a persistent manner, and possibly do "something" about
5607 it. Thus logging as error for now. */
5608 GNUNET_break_op (0);
5609 GNUNET_STATISTICS_update (GST_stats,
5610 "# CORE messages dropped (virtual link still down)",
5611 1,
5612 GNUNET_NO);
5613
5614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5615 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
5616 (unsigned int) ntohs (mh->type),
5617 (unsigned int) ntohs (mh->size));
5618 finish_cmc_handling (cmc);
5619 return;
5620 }
5621 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
5622 {
5623 GNUNET_STATISTICS_update (GST_stats,
5624 "# CORE messages dropped (FC arithmetic overflow)",
5625 1,
5626 GNUNET_NO);
5627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5628 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
5629 (unsigned int) ntohs (mh->type),
5630 (unsigned int) ntohs (mh->size));
5631 finish_cmc_handling (cmc);
5632 return;
5633 }
5634 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
5635 {
5636 GNUNET_STATISTICS_update (GST_stats,
5637 "# CORE messages dropped (FC window overflow)",
5638 1,
5639 GNUNET_NO);
5640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5641 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
5642 (unsigned int) ntohs (mh->type),
5643 (unsigned int) ntohs (mh->size));
5644 finish_cmc_handling (cmc);
5645 return;
5646 }
5647
5648 /* Forward to all CORE clients */
5649 have_core = GNUNET_NO;
5650 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
5651 {
5652 struct GNUNET_MQ_Envelope *env;
5653 struct InboundMessage *im;
5654 struct CoreSentContext *ctx;
5655
5656 if (CT_CORE != tc->type)
5657 continue;
5658 vl->incoming_fc_window_size_ram += size;
5659 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
5660 ctx = GNUNET_new (struct CoreSentContext);
5661 ctx->vl = vl;
5662 ctx->size = size;
5663 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
5664 have_core = GNUNET_YES;
5665 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
5666 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
5667 im->peer = cmc->im.sender;
5668 memcpy (&im[1], mh, size);
5669 GNUNET_MQ_send (tc->mq, env);
5670 vl->core_recv_window--;
5671 }
5672 if (GNUNET_NO == have_core)
5673 {
5674 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5675 "Dropped message to CORE: no CORE client connected!\n");
5676 /* Nevertheless, count window as used, as it is from the
5677 perspective of the other peer! */
5678 vl->incoming_fc_window_size_used += size;
5679 /* TODO-M1 */
5680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5681 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
5682 (unsigned int) ntohs (mh->type),
5683 (unsigned int) ntohs (mh->size));
5684 finish_cmc_handling (cmc);
5685 return;
5686 }
5687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5688 "Delivered message from %s of type %u to CORE\n",
5689 GNUNET_i2s (&cmc->im.sender),
5690 ntohs (mh->type));
5691 if (vl->core_recv_window > 0)
5692 {
5693 finish_cmc_handling (cmc);
5694 return;
5695 }
5696 /* Wait with calling #finish_cmc_handling(cmc) until the message
5697 was processed by CORE MQs (for CORE flow control)! */
5698 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
5699}
5700
5701
5702/**
5703 * Communicator gave us a fragment box. Check the message.
5704 *
5705 * @param cls a `struct CommunicatorMessageContext`
5706 * @param fb the send message that was sent
5707 * @return #GNUNET_YES if message is well-formed
5708 */
5709static int
5710check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5711{
5712 uint16_t size = ntohs (fb->header.size);
5713 uint16_t bsize = size - sizeof(*fb);
5714
5715 (void) cls;
5716 if (0 == bsize)
5717 {
5718 GNUNET_break_op (0);
5719 return GNUNET_SYSERR;
5720 }
5721 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
5722 {
5723 GNUNET_break_op (0);
5724 return GNUNET_SYSERR;
5725 }
5726 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
5727 {
5728 GNUNET_break_op (0);
5729 return GNUNET_SYSERR;
5730 }
5731 return GNUNET_YES;
5732}
5733
5734
5735/**
5736 * Clean up an idle cumulative acknowledgement data structure.
5737 *
5738 * @param cls a `struct AcknowledgementCummulator *`
5739 */
5740static void
5741destroy_ack_cummulator (void *cls)
5742{
5743 struct AcknowledgementCummulator *ac = cls;
5744
5745 ac->task = NULL;
5746 GNUNET_assert (0 == ac->num_acks);
5747 GNUNET_assert (
5748 GNUNET_YES ==
5749 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
5750 GNUNET_free (ac);
5751}
5752
5753
5754/**
5755 * Do the transmission of a cumulative acknowledgement now.
5756 *
5757 * @param cls a `struct AcknowledgementCummulator *`
5758 */
5759static void
5760transmit_cummulative_ack_cb (void *cls)
5761{
5762 struct Neighbour *n;
5763 struct VirtualLink *vl;
5764 struct AcknowledgementCummulator *ac = cls;
5765 char buf[sizeof(struct TransportReliabilityAckMessage)
5766 + ac->num_acks
5767 * sizeof(struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
5768 struct TransportReliabilityAckMessage *ack =
5769 (struct TransportReliabilityAckMessage *) buf;
5770 struct TransportCummulativeAckPayloadP *ap;
5771
5772 ac->task = NULL;
5773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5774 "Sending ACK with %u components to %s\n",
5775 ac->num_acks,
5776 GNUNET_i2s (&ac->target));
5777 GNUNET_assert (0 < ac->num_acks);
5778 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5779 ack->header.size =
5780 htons (sizeof(*ack)
5781 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
5782 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
5783 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5784 for (unsigned int i = 0; i < ac->num_acks; i++)
5785 {
5786 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5787 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5788 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5789 }
5790 /*route_control_message_without_fc (
5791 &ac->target,
5792 &ack->header,
5793 RMO_DV_ALLOWED);*/
5794 vl = lookup_virtual_link (&ac->target);
5795 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
5796 {
5797 route_control_message_without_fc (
5798 vl,
5799 &ack->header,
5800 RMO_DV_ALLOWED);
5801 }
5802 else
5803 {
5804 /* Use route via neighbour */
5805 n = lookup_neighbour (&ac->target);
5806 if (NULL != n)
5807 route_via_neighbour (
5808 n,
5809 &ack->header,
5810 RMO_NONE);
5811 }
5812 ac->num_acks = 0;
5813 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5814 &destroy_ack_cummulator,
5815 ac);
5816}
5817
5818
5819/**
5820 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5821 * transmission by at most @a ack_delay.
5822 *
5823 * @param pid target peer
5824 * @param ack_uuid UUID to ack
5825 * @param max_delay how long can the ACK wait
5826 */
5827static void
5828cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5829 const struct AcknowledgementUUIDP *ack_uuid,
5830 struct GNUNET_TIME_Absolute max_delay)
5831{
5832 struct AcknowledgementCummulator *ac;
5833
5834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5835 "Scheduling ACK %s for transmission to %s\n",
5836 GNUNET_uuid2s (&ack_uuid->value),
5837 GNUNET_i2s (pid));
5838 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5839 if (NULL == ac)
5840 {
5841 ac = GNUNET_new (struct AcknowledgementCummulator);
5842 ac->target = *pid;
5843 ac->min_transmission_time = max_delay;
5844 GNUNET_assert (GNUNET_YES ==
5845 GNUNET_CONTAINER_multipeermap_put (
5846 ack_cummulators,
5847 &ac->target,
5848 ac,
5849 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5850 }
5851 else
5852 {
5853 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5854 {
5855 /* must run immediately, ack buffer full! */
5856 transmit_cummulative_ack_cb (ac);
5857 }
5858 GNUNET_SCHEDULER_cancel (ac->task);
5859 ac->min_transmission_time =
5860 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5861 }
5862 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5863 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5864 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5865 ac->num_acks++;
5866 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5867 &transmit_cummulative_ack_cb,
5868 ac);
5869}
5870
5871
5872/**
5873 * Closure for #find_by_message_uuid.
5874 */
5875struct FindByMessageUuidContext
5876{
5877 /**
5878 * UUID to look for.
5879 */
5880 struct MessageUUIDP message_uuid;
5881
5882 /**
5883 * Set to the reassembly context if found.
5884 */
5885 struct ReassemblyContext *rc;
5886};
5887
5888
5889/**
5890 * Iterator called to find a reassembly context by the message UUID in the
5891 * multihashmap32.
5892 *
5893 * @param cls a `struct FindByMessageUuidContext`
5894 * @param key a key (unused)
5895 * @param value a `struct ReassemblyContext`
5896 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5897 */
5898static int
5899find_by_message_uuid (void *cls, uint32_t key, void *value)
5900{
5901 struct FindByMessageUuidContext *fc = cls;
5902 struct ReassemblyContext *rc = value;
5903
5904 (void) key;
5905 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5906 {
5907 fc->rc = rc;
5908 return GNUNET_NO;
5909 }
5910 return GNUNET_YES;
5911}
5912
5913
5914/**
5915 * Communicator gave us a fragment. Process the request.
5916 *
5917 * @param cls a `struct CommunicatorMessageContext` (must call
5918 * #finish_cmc_handling() when done)
5919 * @param fb the message that was received
5920 */
5921static void
5922handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5923{
5924 struct CommunicatorMessageContext *cmc = cls;
5925 struct VirtualLink *vl;
5926 struct ReassemblyContext *rc;
5927 const struct GNUNET_MessageHeader *msg;
5928 uint16_t msize;
5929 uint16_t fsize;
5930 uint16_t frag_off;
5931 char *target;
5932 struct GNUNET_TIME_Relative cdelay;
5933 struct FindByMessageUuidContext fc;
5934
5935 vl = lookup_virtual_link (&cmc->im.sender);
5936 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5937 {
5938 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5939
5940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5941 "No virtual link for %s to handle fragment\n",
5942 GNUNET_i2s (&cmc->im.sender));
5943 GNUNET_break (0);
5944 finish_cmc_handling (cmc);
5945 GNUNET_SERVICE_client_drop (client);
5946 return;
5947 }
5948 if (NULL == vl->reassembly_map)
5949 {
5950 vl->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5951 vl->reassembly_heap =
5952 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5953 vl->reassembly_timeout_task =
5954 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5955 &reassembly_cleanup_task,
5956 vl);
5957 }
5958 msize = ntohs (fb->msg_size);
5959 fc.message_uuid = fb->msg_uuid;
5960 fc.rc = NULL;
5961 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (vl->reassembly_map,
5962 fb->msg_uuid.uuid,
5963 &find_by_message_uuid,
5964 &fc);
5965 fsize = ntohs (fb->header.size) - sizeof(*fb);
5966 if (NULL == (rc = fc.rc))
5967 {
5968 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
5969 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
5970 rc->msg_uuid = fb->msg_uuid;
5971 rc->virtual_link = vl;
5972 rc->msg_size = msize;
5973 rc->reassembly_timeout =
5974 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5975 rc->last_frag = GNUNET_TIME_absolute_get ();
5976 rc->hn = GNUNET_CONTAINER_heap_insert (vl->reassembly_heap,
5977 rc,
5978 rc->reassembly_timeout.abs_value_us);
5979 GNUNET_assert (GNUNET_OK ==
5980 GNUNET_CONTAINER_multihashmap32_put (
5981 vl->reassembly_map,
5982 rc->msg_uuid.uuid,
5983 rc,
5984 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5985 target = (char *) &rc[1];
5986 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5987 if (fsize != rc->msg_size)
5988 rc->msg_missing = rc->msg_size;
5989 else
5990 rc->msg_missing = 0;
5991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5992 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %u\n",
5993 fsize,
5994 ntohs (fb->frag_off),
5995 msize,
5996 rc->msg_missing,
5997 GNUNET_i2s (&cmc->im.sender),
5998 (unsigned int) fb->msg_uuid.uuid);
5999 }
6000 else
6001 {
6002 target = (char *) &rc[1];
6003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6004 "Received fragment at offset %u/%u from %s for message %u\n",
6005 ntohs (fb->frag_off),
6006 msize,
6007 GNUNET_i2s (&cmc->im.sender),
6008 (unsigned int) fb->msg_uuid.uuid);
6009 }
6010 if (msize != rc->msg_size)
6011 {
6012 GNUNET_break (0);
6013 finish_cmc_handling (cmc);
6014 return;
6015 }
6016
6017 /* reassemble */
6018 if (0 == fsize)
6019 {
6020 GNUNET_break (0);
6021 finish_cmc_handling (cmc);
6022 return;
6023 }
6024 frag_off = ntohs (fb->frag_off);
6025 if (frag_off + fsize > msize)
6026 {
6027 /* Fragment (plus fragment size) exceeds message size! */
6028 GNUNET_break_op (0);
6029 finish_cmc_handling (cmc);
6030 return;
6031 }
6032 memcpy (&target[frag_off], &fb[1], fsize);
6033 /* update bitfield and msg_missing */
6034 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
6035 {
6036 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
6037 {
6038 rc->bitfield[i / 8] |= (1 << (i % 8));
6039 rc->msg_missing--;
6040 }
6041 }
6042
6043 /* Compute cumulative ACK */
6044 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
6045 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
6046 if (0 == rc->msg_missing)
6047 cdelay = GNUNET_TIME_UNIT_ZERO;
6048 cummulative_ack (&cmc->im.sender,
6049 &fb->ack_uuid,
6050 GNUNET_TIME_relative_to_absolute (cdelay));
6051 rc->last_frag = GNUNET_TIME_absolute_get ();
6052 /* is reassembly complete? */
6053 if (0 != rc->msg_missing)
6054 {
6055 finish_cmc_handling (cmc);
6056 return;
6057 }
6058 /* reassembly is complete, verify result */
6059 msg = (const struct GNUNET_MessageHeader *) &rc[1];
6060 if (ntohs (msg->size) != rc->msg_size)
6061 {
6062 GNUNET_break (0);
6063 free_reassembly_context (rc);
6064 finish_cmc_handling (cmc);
6065 return;
6066 }
6067 /* successful reassembly */
6068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6069 "Fragment reassembly complete for message %u\n",
6070 (unsigned int) fb->msg_uuid.uuid);
6071 /* FIXME: check that the resulting msg is NOT a
6072 DV Box or Reliability Box, as that is NOT allowed! */
6073 demultiplex_with_cmc (cmc, msg);
6074 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
6075 en-route and we forget that we finished this reassembly immediately!
6076 -> keep around until timeout?
6077 -> shorten timeout based on ACK? */
6078 free_reassembly_context (rc);
6079}
6080
6081
6082/**
6083 * Communicator gave us a reliability box. Check the message.
6084 *
6085 * @param cls a `struct CommunicatorMessageContext`
6086 * @param rb the send message that was sent
6087 * @return #GNUNET_YES if message is well-formed
6088 */
6089static int
6090check_reliability_box (void *cls,
6091 const struct TransportReliabilityBoxMessage *rb)
6092{
6093 (void) cls;
6094 const struct GNUNET_MessageHeader *inbox = (const struct
6095 GNUNET_MessageHeader *) &rb[1];
6096
6097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6098 "check_send_msg with size %u: inner msg type %u and size %u (%u %u)\n",
6099 ntohs (rb->header.size),
6100 ntohs (inbox->type),
6101 ntohs (inbox->size),
6102 sizeof (struct TransportReliabilityBoxMessage),
6103 sizeof (struct GNUNET_MessageHeader));
6104 GNUNET_MQ_check_boxed_message (rb);
6105 return GNUNET_YES;
6106}
6107
6108
6109/**
6110 * Communicator gave us a reliability box. Process the request.
6111 *
6112 * @param cls a `struct CommunicatorMessageContext` (must call
6113 * #finish_cmc_handling() when done)
6114 * @param rb the message that was received
6115 */
6116static void
6117handle_reliability_box (void *cls,
6118 const struct TransportReliabilityBoxMessage *rb)
6119{
6120 struct CommunicatorMessageContext *cmc = cls;
6121 const struct GNUNET_MessageHeader *inbox =
6122 (const struct GNUNET_MessageHeader *) &rb[1];
6123 struct GNUNET_TIME_Relative rtt;
6124
6125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6126 "Received reliability box from %s with UUID %s of type %u\n",
6127 GNUNET_i2s (&cmc->im.sender),
6128 GNUNET_uuid2s (&rb->ack_uuid.value),
6129 (unsigned int) ntohs (inbox->type));
6130 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
6131 do not really have an RTT for the
6132 * incoming* queue (should we have
6133 the sender add it to the rb message?) */
6134 cummulative_ack (
6135 &cmc->im.sender,
6136 &rb->ack_uuid,
6137 (0 == ntohl (rb->ack_countdown))
6138 ? GNUNET_TIME_UNIT_ZERO_ABS
6139 : GNUNET_TIME_relative_to_absolute (
6140 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
6141 /* continue with inner message */
6142 /* FIXME: check that inbox is NOT a DV Box, fragment or another
6143 reliability box (not allowed!) */
6144 demultiplex_with_cmc (cmc, inbox);
6145}
6146
6147
6148/**
6149 * Check if we have advanced to another age since the last time. If
6150 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
6151 * the current age)
6152 *
6153 * @param pd[in,out] data to update
6154 * @param age current age
6155 */
6156static void
6157update_pd_age (struct PerformanceData *pd, unsigned int age)
6158{
6159 unsigned int sage;
6160
6161 if (age == pd->last_age)
6162 return; /* nothing to do */
6163 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
6164 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
6165 {
6166 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
6167
6168 the->bytes_sent = 0;
6169 the->bytes_received = 0;
6170 }
6171 pd->last_age = age;
6172}
6173
6174
6175/**
6176 * Update @a pd based on the latest @a rtt and the number of bytes
6177 * that were confirmed to be successfully transmitted.
6178 *
6179 * @param pd[in,out] data to update
6180 * @param rtt latest round-trip time
6181 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
6182 */
6183static void
6184update_performance_data (struct PerformanceData *pd,
6185 struct GNUNET_TIME_Relative rtt,
6186 uint16_t bytes_transmitted_ok)
6187{
6188 uint64_t nval = rtt.rel_value_us;
6189 uint64_t oval = pd->aged_rtt.rel_value_us;
6190 unsigned int age = get_age ();
6191 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
6192
6193 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
6194 pd->aged_rtt = rtt;
6195 else
6196 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
6197 update_pd_age (pd, age);
6198 the->bytes_received += bytes_transmitted_ok;
6199}
6200
6201
6202/**
6203 * We have successfully transmitted data via @a q, update metrics.
6204 *
6205 * @param q queue to update
6206 * @param rtt round trip time observed
6207 * @param bytes_transmitted_ok number of bytes successfully transmitted
6208 */
6209static void
6210update_queue_performance (struct Queue *q,
6211 struct GNUNET_TIME_Relative rtt,
6212 uint16_t bytes_transmitted_ok)
6213{
6214 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
6215}
6216
6217
6218/**
6219 * We have successfully transmitted data via @a dvh, update metrics.
6220 *
6221 * @param dvh distance vector path data to update
6222 * @param rtt round trip time observed
6223 * @param bytes_transmitted_ok number of bytes successfully transmitted
6224 */
6225static void
6226update_dvh_performance (struct DistanceVectorHop *dvh,
6227 struct GNUNET_TIME_Relative rtt,
6228 uint16_t bytes_transmitted_ok)
6229{
6230 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
6231}
6232
6233
6234/**
6235 * We have completed transmission of @a pm, remove it from
6236 * the transmission queues (and if it is a fragment, continue
6237 * up the tree as necessary).
6238 *
6239 * @param pm pending message that was transmitted
6240 */
6241static void
6242completed_pending_message (struct PendingMessage *pm)
6243{
6244 struct PendingMessage *pos;
6245
6246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6247 "Complete transmission of message %llu %u\n",
6248 pm->logging_uuid,
6249 pm->pmt);
6250 switch (pm->pmt)
6251 {
6252 case PMT_CORE:
6253 case PMT_RELIABILITY_BOX:
6254 /* Full message sent, we are done */
6255 client_send_response (pm);
6256 return;
6257
6258 case PMT_FRAGMENT_BOX:
6259 /* Fragment sent over reliable channel */
6260 pos = pm->frag_parent;
6261 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6262 free_pending_message (pm);
6263 /* check if subtree is done */
6264 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
6265 (NULL != pos->frag_parent))
6266 {
6267 pm = pos;
6268 pos = pm->frag_parent;
6269 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
6270 {
6271 client_send_response (pm);
6272 return;
6273 }
6274 else if (PMT_DV_BOX == pm->pmt)
6275 {
6276 client_send_response (pos);
6277 return;
6278 }
6279 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6280 free_pending_message (pm);
6281 }
6282
6283 /* Was this the last applicable fragment? */
6284 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent) &&
6285 (pos->frag_off == pos->bytes_msg))
6286 client_send_response (pos);
6287 return;
6288
6289 case PMT_DV_BOX:
6290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6291 "Completed transmission of message %llu (DV Box)\n",
6292 pm->logging_uuid);
6293 if (NULL != pm->frag_parent)
6294 {
6295 if (NULL != pm->bpm)
6296 {
6297 GNUNET_free (pm->bpm);
6298 }
6299 client_send_response (pm->frag_parent);
6300 }
6301 else
6302 client_send_response (pm);
6303 return;
6304 }
6305}
6306
6307
6308/**
6309 * The @a pa was acknowledged, process the acknowledgement.
6310 *
6311 * @param pa the pending acknowledgement that was satisfied
6312 * @param ack_delay artificial delay from cumulative acks created by the
6313 * other peer
6314 */
6315static void
6316handle_acknowledged (struct PendingAcknowledgement *pa,
6317 struct GNUNET_TIME_Relative ack_delay)
6318{
6319 struct GNUNET_TIME_Relative delay;
6320
6321 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
6322 if (delay.rel_value_us > ack_delay.rel_value_us)
6323 delay = GNUNET_TIME_UNIT_ZERO;
6324 else
6325 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
6326 if (NULL != pa->queue)
6327 update_queue_performance (pa->queue, delay, pa->message_size);
6328 if (NULL != pa->dvh)
6329 update_dvh_performance (pa->dvh, delay, pa->message_size);
6330 if (NULL != pa->pm)
6331 completed_pending_message (pa->pm);
6332 free_pending_acknowledgement (pa);
6333}
6334
6335
6336/**
6337 * Communicator gave us a reliability ack. Check it is well-formed.
6338 *
6339 * @param cls a `struct CommunicatorMessageContext` (unused)
6340 * @param ra the message that was received
6341 * @return #GNUNET_Ok if @a ra is well-formed
6342 */
6343static int
6344check_reliability_ack (void *cls,
6345 const struct TransportReliabilityAckMessage *ra)
6346{
6347 unsigned int n_acks;
6348
6349 (void) cls;
6350 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6351 / sizeof(struct TransportCummulativeAckPayloadP);
6352 if (0 == n_acks)
6353 {
6354 GNUNET_break_op (0);
6355 return GNUNET_SYSERR;
6356 }
6357 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
6358 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
6359 {
6360 GNUNET_break_op (0);
6361 return GNUNET_SYSERR;
6362 }
6363 return GNUNET_OK;
6364}
6365
6366
6367/**
6368 * Communicator gave us a reliability ack. Process the request.
6369 *
6370 * @param cls a `struct CommunicatorMessageContext` (must call
6371 * #finish_cmc_handling() when done)
6372 * @param ra the message that was received
6373 */
6374static void
6375handle_reliability_ack (void *cls,
6376 const struct TransportReliabilityAckMessage *ra)
6377{
6378 struct CommunicatorMessageContext *cmc = cls;
6379 const struct TransportCummulativeAckPayloadP *ack;
6380 unsigned int n_acks;
6381 uint32_t ack_counter;
6382
6383 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6384 / sizeof(struct TransportCummulativeAckPayloadP);
6385 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
6386 for (unsigned int i = 0; i < n_acks; i++)
6387 {
6388 struct PendingAcknowledgement *pa =
6389 GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
6390 if (NULL == pa)
6391 {
6392 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6393 "Received ACK from %s with UUID %s which is unknown to us!\n",
6394 GNUNET_i2s (&cmc->im.sender),
6395 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6396 GNUNET_STATISTICS_update (
6397 GST_stats,
6398 "# FRAGMENT_ACKS dropped, no matching pending message",
6399 1,
6400 GNUNET_NO);
6401 continue;
6402 }
6403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6404 "Received ACK from %s with UUID %s\n",
6405 GNUNET_i2s (&cmc->im.sender),
6406 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6407 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
6408 }
6409
6410 ack_counter = htonl (ra->ack_counter);
6411 (void) ack_counter; /* silence compiler warning for now */
6412 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
6413 // (DV and/or Neighbour?)
6414 finish_cmc_handling (cmc);
6415}
6416
6417
6418/**
6419 * Communicator gave us a backchannel encapsulation. Check the message.
6420 *
6421 * @param cls a `struct CommunicatorMessageContext`
6422 * @param be the send message that was sent
6423 * @return #GNUNET_YES if message is well-formed
6424 */
6425static int
6426check_backchannel_encapsulation (
6427 void *cls,
6428 const struct TransportBackchannelEncapsulationMessage *be)
6429{
6430 uint16_t size = ntohs (be->header.size) - sizeof(*be);
6431 const struct GNUNET_MessageHeader *inbox =
6432 (const struct GNUNET_MessageHeader *) &be[1];
6433 const char *is;
6434 uint16_t isize;
6435
6436 (void) cls;
6437 if (ntohs (inbox->size) >= size)
6438 {
6439 GNUNET_break_op (0);
6440 return GNUNET_SYSERR;
6441 }
6442 isize = ntohs (inbox->size);
6443 is = ((const char *) inbox) + isize;
6444 size -= isize;
6445 if ('\0' != is[size - 1])
6446 {
6447 GNUNET_break_op (0);
6448 return GNUNET_SYSERR;
6449 }
6450 return GNUNET_YES;
6451}
6452
6453
6454/**
6455 * Communicator gave us a backchannel encapsulation. Process the request.
6456 * (We are the destination of the backchannel here.)
6457 *
6458 * @param cls a `struct CommunicatorMessageContext` (must call
6459 * #finish_cmc_handling() when done)
6460 * @param be the message that was received
6461 */
6462static void
6463handle_backchannel_encapsulation (
6464 void *cls,
6465 const struct TransportBackchannelEncapsulationMessage *be)
6466{
6467 struct CommunicatorMessageContext *cmc = cls;
6468 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
6469 struct GNUNET_MQ_Envelope *env;
6470 struct TransportClient *tc;
6471 const struct GNUNET_MessageHeader *inbox =
6472 (const struct GNUNET_MessageHeader *) &be[1];
6473 uint16_t isize = ntohs (inbox->size);
6474 const char *target_communicator = ((const char *) inbox) + isize;
6475 char *sender;
6476 char *self;
6477
6478 GNUNET_asprintf (&sender,
6479 "%s",
6480 GNUNET_i2s (&cmc->im.sender));
6481 GNUNET_asprintf (&self,
6482 "%s",
6483 GNUNET_i2s (&GST_my_identity));
6484
6485 /* Find client providing this communicator */
6486 for (tc = clients_head; NULL != tc; tc = tc->next)
6487 if ((CT_COMMUNICATOR == tc->type) &&
6488 (0 ==
6489 strcmp (tc->details.communicator.address_prefix, target_communicator)))
6490 break;
6491 if (NULL == tc)
6492 {
6493 char *stastr;
6494
6495 GNUNET_asprintf (
6496 &stastr,
6497 "# Backchannel message dropped: target communicator `%s' unknown",
6498 target_communicator);
6499 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
6500 GNUNET_free (stastr);
6501 finish_cmc_handling (cmc);
6502 return;
6503 }
6504 /* Finally, deliver backchannel message to communicator */
6505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6506 "Delivering backchannel message from %s to %s of type %u to %s\n",
6507 sender,
6508 self,
6509 ntohs (inbox->type),
6510 target_communicator);
6511 env = GNUNET_MQ_msg_extra (
6512 cbi,
6513 isize,
6514 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
6515 cbi->pid = cmc->im.sender;
6516 memcpy (&cbi[1], inbox, isize);
6517 GNUNET_MQ_send (tc->mq, env);
6518 finish_cmc_handling (cmc);
6519}
6520
6521
6522/**
6523 * Task called when we should check if any of the DV paths
6524 * we have learned to a target are due for garbage collection.
6525 *
6526 * Collects stale paths, and possibly frees the entire DV
6527 * entry if no paths are left. Otherwise re-schedules itself.
6528 *
6529 * @param cls a `struct DistanceVector`
6530 */
6531static void
6532path_cleanup_cb (void *cls)
6533{
6534 struct DistanceVector *dv = cls;
6535 struct DistanceVectorHop *pos;
6536
6537 dv->timeout_task = NULL;
6538 while (NULL != (pos = dv->dv_head))
6539 {
6540 GNUNET_assert (dv == pos->dv);
6541 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
6542 break;
6543 free_distance_vector_hop (pos);
6544 }
6545 if (NULL == pos)
6546 {
6547 free_dv_route (dv);
6548 return;
6549 }
6550 dv->timeout_task =
6551 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
6552}
6553
6554
6555/**
6556 * The @a hop is a validated path to the respective target
6557 * peer and we should tell core about it -- and schedule
6558 * a job to revoke the state.
6559 *
6560 * @param hop a path to some peer that is the reason for activation
6561 */
6562static void
6563activate_core_visible_dv_path (struct DistanceVectorHop *hop)
6564{
6565 struct DistanceVector *dv = hop->dv;
6566 struct VirtualLink *vl;
6567
6568 vl = lookup_virtual_link (&dv->target);
6569 if (NULL == vl)
6570 {
6571
6572 vl = GNUNET_new (struct VirtualLink);
6573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6574 "Creating new virtual link %p to %s using DV!\n",
6575 vl,
6576 GNUNET_i2s (&dv->target));
6577 vl->confirmed = GNUNET_YES;
6578 vl->message_uuid_ctr =
6579 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
6580 vl->target = dv->target;
6581 vl->core_recv_window = RECV_WINDOW_SIZE;
6582 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
6583 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
6584 GNUNET_break (GNUNET_YES ==
6585 GNUNET_CONTAINER_multipeermap_put (
6586 links,
6587 &vl->target,
6588 vl,
6589 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6590 vl->dv = dv;
6591 dv->vl = vl;
6592 vl->visibility_task =
6593 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6594 consider_sending_fc (vl);
6595 /* We lacked a confirmed connection to the target
6596 before, so tell CORE about it (finally!) */
6597 cores_send_connect_info (&dv->target);
6598 }
6599 else
6600 {
6601 /* Link was already up, remember dv is also now available and we are done */
6602 vl->dv = dv;
6603 dv->vl = vl;
6604 if (GNUNET_NO == vl->confirmed)
6605 {
6606 vl->confirmed = GNUNET_YES;
6607 vl->visibility_task =
6608 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6609 consider_sending_fc (vl);
6610 /* We lacked a confirmed connection to the target
6611 before, so tell CORE about it (finally!) */
6612 cores_send_connect_info (&dv->target);
6613 }
6614 else
6615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6616 "Virtual link to %s could now also use DV!\n",
6617 GNUNET_i2s (&dv->target));
6618 }
6619}
6620
6621
6622/**
6623 * We have learned a @a path through the network to some other peer, add it to
6624 * our DV data structure (returning #GNUNET_YES on success).
6625 *
6626 * We do not add paths if we have a sufficient number of shorter
6627 * paths to this target already (returning #GNUNET_NO).
6628 *
6629 * We also do not add problematic paths, like those where we lack the first
6630 * hop in our neighbour list (i.e. due to a topology change) or where some
6631 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6632 *
6633 * @param path the path we learned, path[0] should be us,
6634 * and then path contains a valid path from us to
6635 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6636 * @param path_len number of entries on the @a path, at least three!
6637 * @param network_latency how long does the message take from us to
6638 * `path[path_len-1]`? set to "forever" if unknown
6639 * @param path_valid_until how long is this path considered validated? Maybe
6640 * be zero.
6641 * @return #GNUNET_YES on success,
6642 * #GNUNET_NO if we have better path(s) to the target
6643 * #GNUNET_SYSERR if the path is useless and/or invalid
6644 * (i.e. path[1] not a direct neighbour
6645 * or path[i+1] is a direct neighbour for i>0)
6646 */
6647static int
6648learn_dv_path (const struct GNUNET_PeerIdentity *path,
6649 unsigned int path_len,
6650 struct GNUNET_TIME_Relative network_latency,
6651 struct GNUNET_TIME_Absolute path_valid_until)
6652{
6653 struct DistanceVectorHop *hop;
6654 struct DistanceVector *dv;
6655 struct Neighbour *next_hop;
6656 unsigned int shorter_distance;
6657
6658 if (path_len < 3)
6659 {
6660 /* what a boring path! not allowed! */
6661 GNUNET_break (0);
6662 return GNUNET_SYSERR;
6663 }
6664 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6665 next_hop = lookup_neighbour (&path[1]);
6666 if (NULL == next_hop)
6667 {
6668 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6669 GNUNET_break (0);
6670 return GNUNET_SYSERR;
6671 }
6672 for (unsigned int i = 2; i < path_len; i++)
6673 if (NULL != lookup_neighbour (&path[i]))
6674 {
6675 /* Useless path: we have a direct connection to some hop
6676 in the middle of the path, so this one is not even
6677 terribly useful for redundancy */
6678 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6679 "Path of %u hops useless: directly link to hop %u (%s)\n",
6680 path_len,
6681 i,
6682 GNUNET_i2s (&path[i]));
6683 GNUNET_STATISTICS_update (GST_stats,
6684 "# Useless DV path ignored: hop is neighbour",
6685 1,
6686 GNUNET_NO);
6687 return GNUNET_SYSERR;
6688 }
6689 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6690 if (NULL == dv)
6691 {
6692 dv = GNUNET_new (struct DistanceVector);
6693 dv->target = path[path_len - 1];
6694 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6695 &path_cleanup_cb,
6696 dv);
6697 GNUNET_assert (GNUNET_OK ==
6698 GNUNET_CONTAINER_multipeermap_put (
6699 dv_routes,
6700 &dv->target,
6701 dv,
6702 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6703 }
6704 /* Check if we have this path already! */
6705 shorter_distance = 0;
6706 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6707 pos = pos->next_dv)
6708 {
6709 if (pos->distance < path_len - 3)
6710 shorter_distance++;
6711 /* Note that the distances in 'pos' excludes us (path[0]),
6712 the next_hop (path[1]) and the target so we need to subtract three
6713 and check next_hop explicitly */
6714 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
6715 {
6716 int match = GNUNET_YES;
6717
6718 for (unsigned int i = 0; i < pos->distance; i++)
6719 {
6720 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6721 {
6722 match = GNUNET_NO;
6723 break;
6724 }
6725 }
6726 if (GNUNET_YES == match)
6727 {
6728 struct GNUNET_TIME_Relative last_timeout;
6729
6730 /* Re-discovered known path, update timeout */
6731 GNUNET_STATISTICS_update (GST_stats,
6732 "# Known DV path refreshed",
6733 1,
6734 GNUNET_NO);
6735 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6736 pos->timeout =
6737 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6738 pos->path_valid_until =
6739 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6740 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6741 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6742 if (0 <
6743 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6744 activate_core_visible_dv_path (pos);
6745 if (last_timeout.rel_value_us <
6746 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6747 DV_PATH_DISCOVERY_FREQUENCY)
6748 .rel_value_us)
6749 {
6750 /* Some peer send DV learn messages too often, we are learning
6751 the same path faster than it would be useful; do not forward! */
6752 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6753 "Rediscovered path too quickly, not forwarding further\n");
6754 return GNUNET_NO;
6755 }
6756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6757 "Refreshed known path to %s valid until %s, forwarding further\n",
6758 GNUNET_i2s (&dv->target),
6759 GNUNET_STRINGS_absolute_time_to_string (
6760 pos->path_valid_until));
6761 return GNUNET_YES;
6762 }
6763 }
6764 }
6765 /* Count how many shorter paths we have (incl. direct
6766 neighbours) before simply giving up on this one! */
6767 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6768 {
6769 /* We have a shorter path already! */
6770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6771 "Have many shorter DV paths %s, not forwarding further\n",
6772 GNUNET_i2s (&dv->target));
6773 return GNUNET_NO;
6774 }
6775 /* create new DV path entry */
6776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6777 "Discovered new DV path to %s valid until %s\n",
6778 GNUNET_i2s (&dv->target),
6779 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
6780 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
6781 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
6782 hop->next_hop = next_hop;
6783 hop->dv = dv;
6784 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6785 memcpy (&hop[1],
6786 &path[2],
6787 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
6788 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6789 hop->path_valid_until = path_valid_until;
6790 hop->distance = path_len - 3;
6791 hop->pd.aged_rtt = network_latency;
6792 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6793 GNUNET_CONTAINER_MDLL_insert (neighbour,
6794 next_hop->dv_head,
6795 next_hop->dv_tail,
6796 hop);
6797 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6798 activate_core_visible_dv_path (hop);
6799 return GNUNET_YES;
6800}
6801
6802
6803/**
6804 * Communicator gave us a DV learn message. Check the message.
6805 *
6806 * @param cls a `struct CommunicatorMessageContext`
6807 * @param dvl the send message that was sent
6808 * @return #GNUNET_YES if message is well-formed
6809 */
6810static int
6811check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6812{
6813 uint16_t size = ntohs (dvl->header.size);
6814 uint16_t num_hops = ntohs (dvl->num_hops);
6815 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6816
6817 (void) cls;
6818 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
6819 {
6820 GNUNET_break_op (0);
6821 return GNUNET_SYSERR;
6822 }
6823 if (num_hops > MAX_DV_HOPS_ALLOWED)
6824 {
6825 GNUNET_break_op (0);
6826 return GNUNET_SYSERR;
6827 }
6828 for (unsigned int i = 0; i < num_hops; i++)
6829 {
6830 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6831 {
6832 GNUNET_break_op (0);
6833 return GNUNET_SYSERR;
6834 }
6835 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6836 {
6837 GNUNET_break_op (0);
6838 return GNUNET_SYSERR;
6839 }
6840 }
6841 return GNUNET_YES;
6842}
6843
6844
6845/**
6846 * Build and forward a DV learn message to @a next_hop.
6847 *
6848 * @param next_hop peer to send the message to
6849 * @param msg message received
6850 * @param bi_history bitmask specifying hops on path that were bidirectional
6851 * @param nhops length of the @a hops array
6852 * @param hops path the message traversed so far
6853 * @param in_time when did we receive the message, used to calculate network
6854 * delay
6855 */
6856static void
6857forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6858 const struct TransportDVLearnMessage *msg,
6859 uint16_t bi_history,
6860 uint16_t nhops,
6861 const struct DVPathEntryP *hops,
6862 struct GNUNET_TIME_Absolute in_time)
6863{
6864 struct Neighbour *n;
6865 struct VirtualLink *vl;
6866 struct DVPathEntryP *dhops;
6867 char buf[sizeof(struct TransportDVLearnMessage)
6868 + (nhops + 1) * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
6869 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
6870 struct GNUNET_TIME_Relative nnd;
6871
6872 /* compute message for forwarding */
6873 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6874 "Forwarding DV learn message originating from %s to %s\n",
6875 GNUNET_i2s (&msg->initiator),
6876 GNUNET_i2s2 (next_hop));
6877 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6878 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6879 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
6880 + (nhops + 1) * sizeof(struct DVPathEntryP));
6881 fwd->num_hops = htons (nhops + 1);
6882 fwd->bidirectional = htons (bi_history);
6883 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6884 GNUNET_TIME_relative_ntoh (
6885 msg->non_network_delay));
6886 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6887 fwd->init_sig = msg->init_sig;
6888 fwd->initiator = msg->initiator;
6889 fwd->challenge = msg->challenge;
6890 fwd->monotonic_time = msg->monotonic_time;
6891 dhops = (struct DVPathEntryP *) &fwd[1];
6892 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
6893 dhops[nhops].hop = GST_my_identity;
6894 {
6895 struct DvHopPS dhp = {
6896 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6897 .purpose.size = htonl (sizeof(dhp)),
6898 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
6899 .succ = *next_hop,
6900 .challenge = msg->challenge
6901 };
6902 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6903 &dhp,
6904 &dhops[nhops].hop_sig);
6905 }
6906 /*route_control_message_without_fc (next_hop,
6907 &fwd->header,
6908 RMO_UNCONFIRMED_ALLOWED);*/
6909 vl = lookup_virtual_link (next_hop);
6910 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
6911 {
6912 route_control_message_without_fc (vl,
6913 &fwd->header,
6914 RMO_UNCONFIRMED_ALLOWED);
6915 }
6916 else
6917 {
6918 /* Use route via neighbour */
6919 n = lookup_neighbour (next_hop);
6920 if (NULL != n)
6921 route_via_neighbour (
6922 n,
6923 &fwd->header,
6924 RMO_UNCONFIRMED_ALLOWED);
6925 }
6926}
6927
6928
6929/**
6930 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6931 *
6932 * @param sender_monotonic_time monotonic time of the initiator
6933 * @param init the signer
6934 * @param challenge the challenge that was signed
6935 * @param init_sig signature presumably by @a init
6936 * @return #GNUNET_OK if the signature is valid
6937 */
6938static int
6939validate_dv_initiator_signature (
6940 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6941 const struct GNUNET_PeerIdentity *init,
6942 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge,
6943 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6944{
6945 struct DvInitPS ip = { .purpose.purpose = htonl (
6946 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6947 .purpose.size = htonl (sizeof(ip)),
6948 .monotonic_time = sender_monotonic_time,
6949 .challenge = *challenge };
6950
6951 if (
6952 GNUNET_OK !=
6953 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6954 &ip,
6955 init_sig,
6956 &init->public_key))
6957 {
6958 GNUNET_break_op (0);
6959 return GNUNET_SYSERR;
6960 }
6961 return GNUNET_OK;
6962}
6963
6964
6965/**
6966 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6967 */
6968struct NeighbourSelectionContext
6969{
6970 /**
6971 * Original message we received.
6972 */
6973 const struct TransportDVLearnMessage *dvl;
6974
6975 /**
6976 * The hops taken.
6977 */
6978 const struct DVPathEntryP *hops;
6979
6980 /**
6981 * Time we received the message.
6982 */
6983 struct GNUNET_TIME_Absolute in_time;
6984
6985 /**
6986 * Offsets of the selected peers.
6987 */
6988 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6989
6990 /**
6991 * Number of peers eligible for selection.
6992 */
6993 unsigned int num_eligible;
6994
6995 /**
6996 * Number of peers that were selected for forwarding.
6997 */
6998 unsigned int num_selections;
6999
7000 /**
7001 * Number of hops in @e hops
7002 */
7003 uint16_t nhops;
7004
7005 /**
7006 * Bitmap of bidirectional connections encountered.
7007 */
7008 uint16_t bi_history;
7009};
7010
7011
7012/**
7013 * Function called for each neighbour during #handle_dv_learn.
7014 *
7015 * @param cls a `struct NeighbourSelectionContext *`
7016 * @param pid identity of the peer
7017 * @param value a `struct Neighbour`
7018 * @return #GNUNET_YES (always)
7019 */
7020static int
7021dv_neighbour_selection (void *cls,
7022 const struct GNUNET_PeerIdentity *pid,
7023 void *value)
7024{
7025 struct NeighbourSelectionContext *nsc = cls;
7026
7027 (void) value;
7028 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7029 return GNUNET_YES; /* skip initiator */
7030 for (unsigned int i = 0; i < nsc->nhops; i++)
7031 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7032 return GNUNET_YES;
7033 /* skip peers on path */
7034 nsc->num_eligible++;
7035 return GNUNET_YES;
7036}
7037
7038
7039/**
7040 * Function called for each neighbour during #handle_dv_learn.
7041 * We call #forward_dv_learn() on the neighbour(s) selected
7042 * during #dv_neighbour_selection().
7043 *
7044 * @param cls a `struct NeighbourSelectionContext *`
7045 * @param pid identity of the peer
7046 * @param value a `struct Neighbour`
7047 * @return #GNUNET_YES (always)
7048 */
7049static int
7050dv_neighbour_transmission (void *cls,
7051 const struct GNUNET_PeerIdentity *pid,
7052 void *value)
7053{
7054 struct NeighbourSelectionContext *nsc = cls;
7055
7056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7057 "transmission %s\n",
7058 GNUNET_i2s (pid));
7059 (void) value;
7060 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7061 return GNUNET_YES; /* skip initiator */
7062 for (unsigned int i = 0; i < nsc->nhops; i++)
7063 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7064 return GNUNET_YES;
7065 /* skip peers on path */
7066 for (unsigned int i = 0; i < nsc->num_selections; i++)
7067 {
7068 if (nsc->selections[i] == nsc->num_eligible)
7069 {
7070 forward_dv_learn (pid,
7071 nsc->dvl,
7072 nsc->bi_history,
7073 nsc->nhops,
7074 nsc->hops,
7075 nsc->in_time);
7076 break;
7077 }
7078 }
7079 nsc->num_eligible++;
7080 return GNUNET_YES;
7081}
7082
7083
7084/**
7085 * Computes the number of neighbours we should forward a DVInit
7086 * message to given that it has so far taken @a hops_taken hops
7087 * though the network and that the number of neighbours we have
7088 * in total is @a neighbour_count, out of which @a eligible_count
7089 * are not yet on the path.
7090 *
7091 * NOTE: technically we might want to include NSE in the formula to
7092 * get a better grip on the overall network size. However, for now
7093 * using NSE here would create a dependency issue in the build system.
7094 * => Left for later, hardcoded to 50 for now.
7095 *
7096 * The goal of the fomula is that we want to reach a total of LOG(NSE)
7097 * peers via DV (`target_total`). We want the reach to be spread out
7098 * over various distances to the origin, with a bias towards shorter
7099 * distances.
7100 *
7101 * We make the strong assumption that the network topology looks
7102 * "similar" at other hops, in particular the @a neighbour_count
7103 * should be comparable at other hops.
7104 *
7105 * If the local neighbourhood is densely connected, we expect that @a
7106 * eligible_count is close to @a neighbour_count minus @a hops_taken
7107 * as a lot of the path is already known. In that case, we should
7108 * forward to few(er) peers to try to find a path out of the
7109 * neighbourhood. OTOH, if @a eligible_count is close to @a
7110 * neighbour_count, we should forward to many peers as we are either
7111 * still close to the origin (i.e. @a hops_taken is small) or because
7112 * we managed to get beyond a local cluster. We express this as
7113 * the `boost_factor` using the square of the fraction of eligible
7114 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
7115 * 99% are eligible, the 'boost' will be almost 1).
7116 *
7117 * Second, the more hops we have taken, the larger the problem of an
7118 * exponential traffic explosion gets. So we take the `target_total`,
7119 * and compute our degree such that at each distance d 2^{-d} peers
7120 * are selected (corrected by the `boost_factor`).
7121 *
7122 * @param hops_taken number of hops DVInit has travelled so far
7123 * @param neighbour_count number of neighbours we have in total
7124 * @param eligible_count number of neighbours we could in
7125 * theory forward to
7126 */
7127static unsigned int
7128calculate_fork_degree (unsigned int hops_taken,
7129 unsigned int neighbour_count,
7130 unsigned int eligible_count)
7131{
7132 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
7133 double eligible_ratio =
7134 ((double) eligible_count) / ((double) neighbour_count);
7135 double boost_factor = eligible_ratio * eligible_ratio;
7136 unsigned int rnd;
7137 double left;
7138
7139 if (hops_taken >= 64)
7140 {
7141 GNUNET_break (0);
7142 return 0; /* precaution given bitshift below */
7143 }
7144 for (unsigned int i = 1; i < hops_taken; i++)
7145 {
7146 /* For each hop, subtract the expected number of targets
7147 reached at distance d (so what remains divided by 2^d) */
7148 target_total -= (target_total * boost_factor / (1LLU << i));
7149 }
7150 rnd =
7151 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
7152 /* round up or down probabilistically depending on how close we were
7153 when floor()ing to rnd */
7154 left = target_total - (double) rnd;
7155 if (UINT32_MAX * left >
7156 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
7157 rnd++; /* round up */
7158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7159 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
7160 hops_taken,
7161 rnd,
7162 eligible_count,
7163 neighbour_count);
7164 return rnd;
7165}
7166
7167
7168/**
7169 * Function called when peerstore is done storing a DV monotonic time.
7170 *
7171 * @param cls a `struct Neighbour`
7172 * @param success #GNUNET_YES if peerstore was successful
7173 */
7174static void
7175neighbour_store_dvmono_cb (void *cls, int success)
7176{
7177 struct Neighbour *n = cls;
7178
7179 n->sc = NULL;
7180 if (GNUNET_YES != success)
7181 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7182 "Failed to store other peer's monotonic time in peerstore!\n");
7183}
7184
7185
7186/**
7187 * Communicator gave us a DV learn message. Process the request.
7188 *
7189 * @param cls a `struct CommunicatorMessageContext` (must call
7190 * #finish_cmc_handling() when done)
7191 * @param dvl the message that was received
7192 */
7193static void
7194handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
7195{
7196 struct CommunicatorMessageContext *cmc = cls;
7197 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
7198 int bi_hop;
7199 uint16_t nhops;
7200 uint16_t bi_history;
7201 const struct DVPathEntryP *hops;
7202 int do_fwd;
7203 int did_initiator;
7204 struct GNUNET_TIME_Absolute in_time;
7205 struct Neighbour *n;
7206
7207 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
7208 bi_history = ntohs (dvl->bidirectional);
7209 hops = (const struct DVPathEntryP *) &dvl[1];
7210 if (0 == nhops)
7211 {
7212 /* sanity check */
7213 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
7214 {
7215 GNUNET_break (0);
7216 finish_cmc_handling (cmc);
7217 return;
7218 }
7219 }
7220 else
7221 {
7222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7223 "handle dv learn message last hop %s\n",
7224 GNUNET_i2s (&hops[nhops - 1].hop));
7225 /* sanity check */
7226 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
7227 {
7228 GNUNET_break (0);
7229 finish_cmc_handling (cmc);
7230 return;
7231 }
7232 }
7233
7234 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
7235 cc = cmc->tc->details.communicator.cc;
7236 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
7237 cc); // FIXME: add bi-directional flag to cc?
7238 in_time = GNUNET_TIME_absolute_get ();
7239
7240 /* continue communicator here, everything else can happen asynchronous! */
7241 finish_cmc_handling (cmc);
7242
7243 n = lookup_neighbour (&dvl->initiator);
7244 if (NULL != n)
7245 {
7246 if ((n->dv_monotime_available == GNUNET_YES) &&
7247 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
7248 n->last_dv_learn_monotime.abs_value_us))
7249 {
7250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7251 "DV learn from %s discarded due to time travel",
7252 GNUNET_i2s (&dvl->initiator));
7253 GNUNET_STATISTICS_update (GST_stats,
7254 "# DV learn discarded due to time travel",
7255 1,
7256 GNUNET_NO);
7257 return;
7258 }
7259 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
7260 &dvl->initiator,
7261 &dvl->challenge,
7262 &dvl->init_sig))
7263 {
7264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7265 "DV learn signature from %s invalid\n",
7266 GNUNET_i2s (&dvl->initiator));
7267 GNUNET_break_op (0);
7268 return;
7269 }
7270 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
7271 if (GNUNET_YES == n->dv_monotime_available)
7272 {
7273 if (NULL != n->sc)
7274 {
7275 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7276 "store cancel\n");
7277 GNUNET_PEERSTORE_store_cancel (n->sc);
7278 }
7279 n->sc =
7280 GNUNET_PEERSTORE_store (peerstore,
7281 "transport",
7282 &dvl->initiator,
7283 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
7284 &dvl->monotonic_time,
7285 sizeof(dvl->monotonic_time),
7286 GNUNET_TIME_UNIT_FOREVER_ABS,
7287 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7288 &neighbour_store_dvmono_cb,
7289 n);
7290 }
7291 }
7292 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
7293 If signature verification load too high, implement random drop strategy */
7294 for (unsigned int i = 0; i < nhops; i++)
7295 {
7296 struct DvHopPS dhp = { .purpose.purpose =
7297 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
7298 .purpose.size = htonl (sizeof(dhp)),
7299 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
7300 .succ = (nhops == i + 1) ? GST_my_identity
7301 : hops[i + 1].hop,
7302 .challenge = dvl->challenge };
7303
7304 if (GNUNET_OK !=
7305 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
7306 &dhp,
7307 &hops[i].hop_sig,
7308 &hops[i].hop.public_key))
7309 {
7310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7311 "DV learn from %s signature of hop %u invalid\n",
7312 GNUNET_i2s (&dvl->initiator),
7313 i);
7314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7315 "signature of hop %s invalid\n",
7316 GNUNET_i2s (&hops[i].hop));
7317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7318 "pred %s\n",
7319 GNUNET_i2s (&dhp.pred));
7320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7321 "succ %s\n",
7322 GNUNET_i2s (&dhp.succ));
7323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7324 "hash %s\n",
7325 GNUNET_sh2s (&dhp.challenge.value));
7326 GNUNET_break_op (0);
7327 return;
7328 }
7329 }
7330 if (GNUNET_EXTRA_LOGGING > 0)
7331 {
7332 char *path;
7333
7334 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
7335 for (unsigned int i = 0; i < nhops; i++)
7336 {
7337 char *tmp;
7338
7339 GNUNET_asprintf (&tmp,
7340 "%s%s%s",
7341 path,
7342 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
7343 GNUNET_i2s (&hops[i].hop));
7344 GNUNET_free (path);
7345 path = tmp;
7346 }
7347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7348 "Received DVInit via %s%s%s\n",
7349 path,
7350 bi_hop ? "<->" : "-->",
7351 GNUNET_i2s (&GST_my_identity));
7352 GNUNET_free (path);
7353 }
7354 do_fwd = GNUNET_YES;
7355 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
7356 {
7357 struct GNUNET_PeerIdentity path[nhops + 1];
7358 struct GNUNET_TIME_Relative host_latency_sum;
7359 struct GNUNET_TIME_Relative latency;
7360 struct GNUNET_TIME_Relative network_latency;
7361 struct GNUNET_TIME_Absolute now;
7362
7363 /* We initiated this, learn the forward path! */
7364 path[0] = GST_my_identity;
7365 path[1] = hops[0].hop;
7366 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
7367
7368 // Need also something to lookup initiation time
7369 // to compute RTT! -> add RTT argument here?
7370 now = GNUNET_TIME_absolute_get ();
7371 latency = GNUNET_TIME_absolute_get_duration (GNUNET_TIME_absolute_ntoh (
7372 dvl->monotonic_time));
7373 GNUNET_assert (latency.rel_value_us >= host_latency_sum.rel_value_us);
7374 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
7375 // (based on dvl->challenge, we can identify time of origin!)
7376
7377 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
7378 /* assumption: latency on all links is the same */
7379 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
7380
7381 for (unsigned int i = 2; i <= nhops; i++)
7382 {
7383 struct GNUNET_TIME_Relative ilat;
7384
7385 /* assumption: linear latency increase per hop */
7386 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
7387 path[i] = hops[i - 1].hop;
7388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7389 "Learned path with %u hops to %s with latency %s\n",
7390 i,
7391 GNUNET_i2s (&path[i]),
7392 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
7393 learn_dv_path (path,
7394 i + 1,
7395 ilat,
7396 GNUNET_TIME_relative_to_absolute (
7397 ADDRESS_VALIDATION_LIFETIME));
7398 }
7399 /* as we initiated, do not forward again (would be circular!) */
7400 do_fwd = GNUNET_NO;
7401 return;
7402 }
7403 if (bi_hop)
7404 {
7405 /* last hop was bi-directional, we could learn something here! */
7406 struct GNUNET_PeerIdentity path[nhops + 2];
7407
7408 path[0] = GST_my_identity;
7409 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
7410 for (unsigned int i = 0; i < nhops; i++)
7411 {
7412 int iret;
7413
7414 if (0 == (bi_history & (1 << i)))
7415 break; /* i-th hop not bi-directional, stop learning! */
7416 if (i == nhops - 1)
7417 {
7418 path[i + 2] = dvl->initiator;
7419 }
7420 else
7421 {
7422 path[i + 2] = hops[nhops - i - 2].hop;
7423 }
7424
7425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7426 "Learned inverse path with %u hops to %s\n",
7427 i + 2,
7428 GNUNET_i2s (&path[i + 2]));
7429 iret = learn_dv_path (path,
7430 i + 3,
7431 GNUNET_TIME_UNIT_FOREVER_REL,
7432 GNUNET_TIME_UNIT_ZERO_ABS);
7433 if (GNUNET_SYSERR == iret)
7434 {
7435 /* path invalid or too long to be interesting for US, thus should also
7436 not be interesting to our neighbours, cut path when forwarding to
7437 'i' hops, except of course for the one that goes back to the
7438 initiator */
7439 GNUNET_STATISTICS_update (GST_stats,
7440 "# DV learn not forwarded due invalidity of path",
7441 1,
7442 GNUNET_NO);
7443 do_fwd = GNUNET_NO;
7444 break;
7445 }
7446 if ((GNUNET_NO == iret) && (nhops == i + 1))
7447 {
7448 /* we have better paths, and this is the longest target,
7449 so there cannot be anything interesting later */
7450 GNUNET_STATISTICS_update (GST_stats,
7451 "# DV learn not forwarded, got better paths",
7452 1,
7453 GNUNET_NO);
7454 do_fwd = GNUNET_NO;
7455 break;
7456 }
7457 }
7458 }
7459 if (MAX_DV_HOPS_ALLOWED == nhops)
7460 {
7461 /* At limit, we're out of here! */
7462 return;
7463 }
7464
7465 /* Forward to initiator, if path non-trivial and possible */
7466 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
7467 did_initiator = GNUNET_NO;
7468 if ((1 <= nhops) &&
7469 (GNUNET_YES ==
7470 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
7471 {
7472 /* send back to origin! */
7473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7474 "Sending DVL back to initiator %s\n",
7475 GNUNET_i2s (&dvl->initiator));
7476 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
7477 did_initiator = GNUNET_YES;
7478 }
7479 /* We forward under two conditions: either we still learned something
7480 ourselves (do_fwd), or the path was darn short and thus the initiator is
7481 likely to still be very interested in this (and we did NOT already
7482 send it back to the initiator) */
7483 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
7484 (GNUNET_NO == did_initiator)))
7485 {
7486 /* Pick random neighbours that are not yet on the path */
7487 struct NeighbourSelectionContext nsc;
7488 unsigned int n_cnt;
7489
7490 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
7491 nsc.nhops = nhops;
7492 nsc.dvl = dvl;
7493 nsc.bi_history = bi_history;
7494 nsc.hops = hops;
7495 nsc.in_time = in_time;
7496 nsc.num_eligible = 0;
7497 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7498 &dv_neighbour_selection,
7499 &nsc);
7500 if (0 == nsc.num_eligible)
7501 return; /* done here, cannot forward to anyone else */
7502 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
7503 nsc.num_selections =
7504 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
7505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7506 "Forwarding DVL to %u other peers\n",
7507 nsc.num_selections);
7508 for (unsigned int i = 0; i < nsc.num_selections; i++)
7509 nsc.selections[i] =
7510 (nsc.num_selections == n_cnt)
7511 ? i /* all were selected, avoid collisions by chance */
7512 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
7513 nsc.num_eligible = 0;
7514 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7515 &dv_neighbour_transmission,
7516 &nsc);
7517 }
7518}
7519
7520
7521/**
7522 * Communicator gave us a DV box. Check the message.
7523 *
7524 * @param cls a `struct CommunicatorMessageContext`
7525 * @param dvb the send message that was sent
7526 * @return #GNUNET_YES if message is well-formed
7527 */
7528static int
7529check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7530{
7531 uint16_t size = ntohs (dvb->header.size);
7532 uint16_t num_hops = ntohs (dvb->num_hops);
7533 const struct GNUNET_PeerIdentity *hops =
7534 (const struct GNUNET_PeerIdentity *) &dvb[1];
7535
7536 (void) cls;
7537 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
7538 + sizeof(struct GNUNET_MessageHeader))
7539 {
7540 GNUNET_break_op (0);
7541 return GNUNET_SYSERR;
7542 }
7543 /* This peer must not be on the path */
7544 for (unsigned int i = 0; i < num_hops; i++)
7545 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7546 {
7547 GNUNET_break_op (0);
7548 return GNUNET_SYSERR;
7549 }
7550 return GNUNET_YES;
7551}
7552
7553
7554/**
7555 * Create a DV Box message and queue it for transmission to
7556 * @ea next_hop.
7557 *
7558 * @param next_hop peer to receive the message next
7559 * @param total_hops how many hops did the message take so far
7560 * @param num_hops length of the @a hops array
7561 * @param origin origin of the message
7562 * @param hops next peer(s) to the destination, including destination
7563 * @param payload payload of the box
7564 * @param payload_size number of bytes in @a payload
7565 */
7566static void
7567forward_dv_box (struct Neighbour *next_hop,
7568 struct TransportDVBoxMessage *hdr,
7569 uint16_t total_hops,
7570 uint16_t num_hops,
7571 const struct GNUNET_PeerIdentity *hops,
7572 const void *enc_payload,
7573 uint16_t enc_payload_size)
7574{
7575 struct VirtualLink *vl = next_hop->vl;
7576 struct PendingMessage *pm;
7577 size_t msg_size = sizeof(struct TransportDVBoxMessage)
7578 + num_hops * sizeof(struct GNUNET_PeerIdentity)
7579 + enc_payload_size;
7580 char *buf;
7581 char msg_buf[msg_size] GNUNET_ALIGN;
7582 struct GNUNET_PeerIdentity *dhops;
7583
7584 hdr->num_hops = htons (num_hops);
7585 hdr->total_hops = htons (total_hops);
7586 hdr->header.size = htons (msg_size);
7587 memcpy (msg_buf, hdr, sizeof(*hdr));
7588 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
7589 TransportDVBoxMessage)];
7590 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
7591 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
7592
7593 if (GNUNET_YES == ntohs (hdr->without_fc))
7594 {
7595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7596 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
7597 enc_payload_size,
7598 GNUNET_i2s (&next_hop->pid),
7599 (unsigned int) num_hops,
7600 (unsigned int) total_hops);
7601 route_via_neighbour (next_hop, (const struct
7602 GNUNET_MessageHeader *) msg_buf,
7603 RMO_ANYTHING_GOES);
7604 }
7605 else if (NULL != vl)
7606 {
7607 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
7608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7609 "2 created pm %p storing vl %p \n",
7610 pm,
7611 vl);
7612 pm->pmt = PMT_DV_BOX;
7613 pm->vl = vl;
7614 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
7615 pm->logging_uuid = logging_uuid_gen++;
7616 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
7617 pm->bytes_msg = msg_size;
7618 buf = (char *) &pm[1];
7619 memcpy (buf, msg_buf, msg_size);
7620 GNUNET_CONTAINER_MDLL_insert (vl,
7621 vl->pending_msg_head,
7622 vl->pending_msg_tail,
7623 pm);
7624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7625 "Created pending message %llu for DV Box with next hop %s (%u/%u)\n",
7626 pm->logging_uuid,
7627 GNUNET_i2s (&next_hop->pid),
7628 (unsigned int) num_hops,
7629 (unsigned int) total_hops);
7630 check_vl_transmission (vl);
7631 }
7632 else
7633 {
7634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7635 "The virtual link is not ready for forwarding a DV Box with payload.\n");
7636 // FIXME The DV Box was send before the validation response. Shall we send a validation request for DV paths?
7637 }
7638}
7639
7640
7641/**
7642 * Free data structures associated with @a b.
7643 *
7644 * @param b data structure to release
7645 */
7646static void
7647free_backtalker (struct Backtalker *b)
7648{
7649 if (NULL != b->get)
7650 {
7651 GNUNET_PEERSTORE_iterate_cancel (b->get);
7652 b->get = NULL;
7653 GNUNET_assert (NULL != b->cmc);
7654 finish_cmc_handling (b->cmc);
7655 b->cmc = NULL;
7656 }
7657 if (NULL != b->task)
7658 {
7659 GNUNET_SCHEDULER_cancel (b->task);
7660 b->task = NULL;
7661 }
7662 if (NULL != b->sc)
7663 {
7664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7665 "store cancel\n");
7666 GNUNET_PEERSTORE_store_cancel (b->sc);
7667 b->sc = NULL;
7668 }
7669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7670 "Removing backtalker for %s\n",
7671 GNUNET_i2s (&b->pid));
7672 GNUNET_assert (
7673 GNUNET_YES ==
7674 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
7675 GNUNET_free (b);
7676}
7677
7678
7679/**
7680 * Callback to free backtalker records.
7681 *
7682 * @param cls NULL
7683 * @param pid unused
7684 * @param value a `struct Backtalker`
7685 * @return #GNUNET_OK (always)
7686 */
7687static int
7688free_backtalker_cb (void *cls,
7689 const struct GNUNET_PeerIdentity *pid,
7690 void *value)
7691{
7692 struct Backtalker *b = value;
7693
7694 (void) cls;
7695 (void) pid;
7696 free_backtalker (b);
7697 return GNUNET_OK;
7698}
7699
7700
7701/**
7702 * Function called when it is time to clean up a backtalker.
7703 *
7704 * @param cls a `struct Backtalker`
7705 */
7706static void
7707backtalker_timeout_cb (void *cls)
7708{
7709 struct Backtalker *b = cls;
7710
7711 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7712 "backtalker timeout.\n");
7713 b->task = NULL;
7714 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
7715 {
7716 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7717 return;
7718 }
7719 GNUNET_assert (NULL == b->sc);
7720 free_backtalker (b);
7721}
7722
7723
7724/**
7725 * Function called with the monotonic time of a backtalker
7726 * by PEERSTORE. Updates the time and continues processing.
7727 *
7728 * @param cls a `struct Backtalker`
7729 * @param record the information found, NULL for the last call
7730 * @param emsg error message
7731 */
7732static void
7733backtalker_monotime_cb (void *cls,
7734 const struct GNUNET_PEERSTORE_Record *record,
7735 const char *emsg)
7736{
7737 struct Backtalker *b = cls;
7738 struct GNUNET_TIME_AbsoluteNBO *mtbe;
7739 struct GNUNET_TIME_Absolute mt;
7740
7741 (void) emsg;
7742 if (NULL == record)
7743 {
7744 /* we're done with #backtalker_monotime_cb() invocations,
7745 continue normal processing */
7746 b->get = NULL;
7747 GNUNET_assert (NULL != b->cmc);
7748 if (0 != b->body_size)
7749 demultiplex_with_cmc (b->cmc,
7750 (const struct GNUNET_MessageHeader *) &b[1]);
7751 else
7752 finish_cmc_handling (b->cmc);
7753 b->cmc = NULL;
7754 return;
7755 }
7756 if (sizeof(*mtbe) != record->value_size)
7757 {
7758 GNUNET_break (0);
7759 return;
7760 }
7761 mtbe = record->value;
7762 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
7763 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
7764 {
7765 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7766 "Backtalker message from %s dropped, monotime in the past\n",
7767 GNUNET_i2s (&b->pid));
7768 GNUNET_STATISTICS_update (
7769 GST_stats,
7770 "# Backchannel messages dropped: monotonic time not increasing",
7771 1,
7772 GNUNET_NO);
7773 b->monotonic_time = mt;
7774 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
7775 */
7776 b->body_size = 0;
7777 return;
7778 }
7779}
7780
7781
7782/**
7783 * Function called by PEERSTORE when the store operation of
7784 * a backtalker's monotonic time is complete.
7785 *
7786 * @param cls the `struct Backtalker`
7787 * @param success #GNUNET_OK on success
7788 */
7789static void
7790backtalker_monotime_store_cb (void *cls, int success)
7791{
7792 struct Backtalker *b = cls;
7793
7794 if (GNUNET_OK != success)
7795 {
7796 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7797 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
7798 }
7799 b->sc = NULL;
7800 if (NULL != b->task)
7801 {
7802 GNUNET_SCHEDULER_cancel (b->task);
7803 b->task = NULL;
7804 }
7805 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7806}
7807
7808
7809/**
7810 * The backtalker @a b monotonic time changed. Update PEERSTORE.
7811 *
7812 * @param b a backtalker with updated monotonic time
7813 */
7814static void
7815update_backtalker_monotime (struct Backtalker *b)
7816{
7817 struct GNUNET_TIME_AbsoluteNBO mtbe;
7818
7819 if (NULL != b->sc)
7820 {
7821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7822 "store cancel before store with sc %p\n",
7823 b->sc);
7824 /*GNUNET_PEERSTORE_store_cancel (b->sc);
7825 b->sc = NULL;*/
7826 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7827 "store cancel before store with sc %p is null\n",
7828 b->sc);
7829 }
7830 else
7831 {
7832 GNUNET_SCHEDULER_cancel (b->task);
7833 b->task = NULL;
7834 }
7835 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
7836 b->sc =
7837 GNUNET_PEERSTORE_store (peerstore,
7838 "transport",
7839 &b->pid,
7840 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7841 &mtbe,
7842 sizeof(mtbe),
7843 GNUNET_TIME_UNIT_FOREVER_ABS,
7844 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7845 &backtalker_monotime_store_cb,
7846 b);
7847}
7848
7849
7850/**
7851 * Communicator gave us a DV box. Process the request.
7852 *
7853 * @param cls a `struct CommunicatorMessageContext` (must call
7854 * #finish_cmc_handling() when done)
7855 * @param dvb the message that was received
7856 */
7857static void
7858handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7859{
7860 struct CommunicatorMessageContext *cmc = cls;
7861 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
7862 uint16_t num_hops = ntohs (dvb->num_hops);
7863 const struct GNUNET_PeerIdentity *hops =
7864 (const struct GNUNET_PeerIdentity *) &dvb[1];
7865 const char *enc_payload = (const char *) &hops[num_hops];
7866 uint16_t enc_payload_size =
7867 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
7868 char enc[enc_payload_size];
7869 struct DVKeyState *key;
7870 struct GNUNET_HashCode hmac;
7871 const char *hdr;
7872 size_t hdr_len;
7873
7874 key = GNUNET_new (struct DVKeyState);
7875
7876 if (GNUNET_EXTRA_LOGGING > 0)
7877 {
7878 char *path;
7879
7880 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
7881 for (unsigned int i = 0; i < num_hops; i++)
7882 {
7883 char *tmp;
7884
7885 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
7886 GNUNET_free (path);
7887 path = tmp;
7888 }
7889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7890 "Received DVBox with remaining path %s\n",
7891 path);
7892 GNUNET_free (path);
7893 }
7894
7895 if (num_hops > 0)
7896 {
7897 /* We're trying from the end of the hops array, as we may be
7898 able to find a shortcut unknown to the origin that way */
7899 for (int i = num_hops - 1; i >= 0; i--)
7900 {
7901 struct Neighbour *n;
7902
7903 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7904 {
7905 GNUNET_break_op (0);
7906 finish_cmc_handling (cmc);
7907 return;
7908 }
7909 n = lookup_neighbour (&hops[i]);
7910 if (NULL == n)
7911 continue;
7912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7913 "Skipping %u/%u hops ahead while routing DV Box\n",
7914 i,
7915 num_hops);
7916
7917 forward_dv_box (n,
7918 (struct TransportDVBoxMessage *) dvb,
7919 ntohs (dvb->total_hops) + 1,
7920 num_hops - i - 1, /* number of hops left */
7921 &hops[i + 1], /* remaining hops */
7922 enc_payload,
7923 enc_payload_size);
7924 GNUNET_STATISTICS_update (GST_stats,
7925 "# DV hops skipped routing boxes",
7926 i,
7927 GNUNET_NO);
7928 GNUNET_STATISTICS_update (GST_stats,
7929 "# DV boxes routed (total)",
7930 1,
7931 GNUNET_NO);
7932 finish_cmc_handling (cmc);
7933 return;
7934 }
7935 /* Woopsie, next hop not in neighbours, drop! */
7936 GNUNET_STATISTICS_update (GST_stats,
7937 "# DV Boxes dropped: next hop unknown",
7938 1,
7939 GNUNET_NO);
7940 finish_cmc_handling (cmc);
7941 return;
7942 }
7943 /* We are the target. Unbox and handle message. */
7944 GNUNET_STATISTICS_update (GST_stats,
7945 "# DV boxes opened (ultimate target)",
7946 1,
7947 GNUNET_NO);
7948 cmc->total_hops = ntohs (dvb->total_hops);
7949
7950 dh_key_derive_eph_pub (&dvb->ephemeral_key, &dvb->iv, key);
7951 hdr = (const char *) &dvb[1];
7952 hdr_len = ntohs (dvb->orig_size) - sizeof(*dvb) - sizeof(struct
7953 GNUNET_PeerIdentity)
7954 * ntohs (dvb->total_hops);
7955
7956 dv_hmac (key, &hmac, hdr, hdr_len);
7957 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
7958 {
7959 /* HMAC mismatch, discard! */
7960 GNUNET_break_op (0);
7961 finish_cmc_handling (cmc);
7962 return;
7963 }
7964 /* begin actual decryption */
7965 {
7966 struct Backtalker *b;
7967 struct GNUNET_TIME_Absolute monotime;
7968 struct TransportDVBoxPayloadP ppay;
7969 char body[hdr_len - sizeof(ppay)] GNUNET_ALIGN;
7970 const struct GNUNET_MessageHeader *mh =
7971 (const struct GNUNET_MessageHeader *) body;
7972
7973 GNUNET_assert (hdr_len >=
7974 sizeof(ppay) + sizeof(struct GNUNET_MessageHeader));
7975 dv_decrypt (key, &ppay, hdr, sizeof(ppay));
7976 dv_decrypt (key, &body, &hdr[sizeof(ppay)], hdr_len - sizeof(ppay));
7977 dv_key_clean (key);
7978 if (ntohs (mh->size) != sizeof(body))
7979 {
7980 GNUNET_break_op (0);
7981 finish_cmc_handling (cmc);
7982 return;
7983 }
7984 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
7985 switch (ntohs (mh->type))
7986 {
7987 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
7988 GNUNET_break_op (0);
7989 finish_cmc_handling (cmc);
7990 return;
7991
7992 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
7993 GNUNET_break_op (0);
7994 finish_cmc_handling (cmc);
7995 return;
7996
7997 default:
7998 /* permitted, continue */
7999 break;
8000 }
8001 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
8002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8003 "Decrypted backtalk from %s\n",
8004 GNUNET_i2s (&ppay.sender));
8005 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
8006 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
8007 {
8008 GNUNET_STATISTICS_update (
8009 GST_stats,
8010 "# Backchannel messages dropped: monotonic time not increasing",
8011 1,
8012 GNUNET_NO);
8013 finish_cmc_handling (cmc);
8014 return;
8015 }
8016 if ((NULL == b) ||
8017 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
8018 {
8019 /* Check signature */
8020 struct EphemeralConfirmationPS ec;
8021
8022 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
8023 ec.target = GST_my_identity;
8024 ec.ephemeral_key = dvb->ephemeral_key;
8025 ec.purpose.size = htonl (sizeof(ec));
8026 ec.sender_monotonic_time = ppay.monotonic_time;
8027 if (
8028 GNUNET_OK !=
8029 GNUNET_CRYPTO_eddsa_verify (
8030 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
8031 &ec,
8032 &ppay.sender_sig,
8033 &ppay.sender.public_key))
8034 {
8035 /* Signature invalid, discard! */
8036 GNUNET_break_op (0);
8037 finish_cmc_handling (cmc);
8038 return;
8039 }
8040 }
8041 /* Update sender, we now know the real origin! */
8042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8043 "DVBox received for me from %s via %s\n",
8044 GNUNET_i2s2 (&ppay.sender),
8045 GNUNET_i2s (&cmc->im.sender));
8046 cmc->im.sender = ppay.sender;
8047
8048 if (NULL != b)
8049 {
8050 /* update key cache and mono time */
8051 b->last_ephemeral = dvb->ephemeral_key;
8052 b->monotonic_time = monotime;
8053 update_backtalker_monotime (b);
8054 b->timeout =
8055 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8056
8057 demultiplex_with_cmc (cmc, mh);
8058 return;
8059 }
8060 /* setup data structure to cache signature AND check
8061 monotonic time with PEERSTORE before forwarding backchannel payload */
8062 b = GNUNET_malloc (sizeof(struct Backtalker) + sizeof(body));
8063 b->pid = ppay.sender;
8064 b->body_size = sizeof(body);
8065 memcpy (&b[1], body, sizeof(body));
8066 GNUNET_assert (GNUNET_YES ==
8067 GNUNET_CONTAINER_multipeermap_put (
8068 backtalkers,
8069 &b->pid,
8070 b,
8071 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8072 b->monotonic_time = monotime; /* NOTE: to be checked still! */
8073 b->cmc = cmc;
8074 b->timeout =
8075 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8076 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8077 b->get =
8078 GNUNET_PEERSTORE_iterate (peerstore,
8079 "transport",
8080 &b->pid,
8081 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
8082 &backtalker_monotime_cb,
8083 b);
8084 } /* end actual decryption */
8085}
8086
8087
8088/**
8089 * Client notified us about transmission from a peer. Process the request.
8090 *
8091 * @param cls a `struct TransportClient` which sent us the message
8092 * @param obm the send message that was sent
8093 * @return #GNUNET_YES if message is well-formed
8094 */
8095static int
8096check_incoming_msg (void *cls,
8097 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8098{
8099 struct TransportClient *tc = cls;
8100
8101 if (CT_COMMUNICATOR != tc->type)
8102 {
8103 GNUNET_break (0);
8104 return GNUNET_SYSERR;
8105 }
8106 GNUNET_MQ_check_boxed_message (im);
8107 return GNUNET_OK;
8108}
8109
8110
8111/**
8112 * Closure for #check_known_address.
8113 */
8114struct CheckKnownAddressContext
8115{
8116 /**
8117 * Set to the address we are looking for.
8118 */
8119 const char *address;
8120
8121 /**
8122 * Set to a matching validation state, if one was found.
8123 */
8124 struct ValidationState *vs;
8125};
8126
8127
8128/**
8129 * Test if the validation state in @a value matches the
8130 * address from @a cls.
8131 *
8132 * @param cls a `struct CheckKnownAddressContext`
8133 * @param pid unused (must match though)
8134 * @param value a `struct ValidationState`
8135 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8136 */
8137static int
8138check_known_address (void *cls,
8139 const struct GNUNET_PeerIdentity *pid,
8140 void *value)
8141{
8142 struct CheckKnownAddressContext *ckac = cls;
8143 struct ValidationState *vs = value;
8144
8145 (void) pid;
8146 if (0 != strcmp (vs->address, ckac->address))
8147 return GNUNET_OK;
8148 ckac->vs = vs;
8149 return GNUNET_NO;
8150}
8151
8152
8153/**
8154 * Task run periodically to validate some address based on #validation_heap.
8155 *
8156 * @param cls NULL
8157 */
8158static void
8159validation_start_cb (void *cls);
8160
8161
8162/**
8163 * Set the time for next_challenge of @a vs to @a new_time.
8164 * Updates the heap and if necessary reschedules the job.
8165 *
8166 * @param vs validation state to update
8167 * @param new_time new time for revalidation
8168 */
8169static void
8170update_next_challenge_time (struct ValidationState *vs,
8171 struct GNUNET_TIME_Absolute new_time)
8172{
8173 struct GNUNET_TIME_Relative delta;
8174
8175 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
8176 return; /* be lazy */
8177 vs->next_challenge = new_time;
8178 if (NULL == vs->hn)
8179 vs->hn =
8180 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
8181 else
8182 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
8183 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
8184 (NULL != validation_task))
8185 return;
8186 if (NULL != validation_task)
8187 GNUNET_SCHEDULER_cancel (validation_task);
8188 /* randomize a bit */
8189 delta.rel_value_us =
8190 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
8191 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
8192 new_time = GNUNET_TIME_absolute_add (new_time, delta);
8193 validation_task =
8194 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
8195}
8196
8197
8198/**
8199 * Start address validation.
8200 *
8201 * @param pid peer the @a address is for
8202 * @param address an address to reach @a pid (presumably)
8203 */
8204static void
8205start_address_validation (const struct GNUNET_PeerIdentity *pid,
8206 const char *address)
8207{
8208 struct GNUNET_TIME_Absolute now;
8209 struct ValidationState *vs;
8210 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
8211
8212 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8213 pid,
8214 &check_known_address,
8215 &ckac);
8216 if (NULL != (vs = ckac.vs))
8217 {
8218 /* if 'vs' is not currently valid, we need to speed up retrying the
8219 * validation */
8220 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8221 {
8222 /* reduce backoff as we got a fresh advertisement */
8223 vs->challenge_backoff =
8224 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8225 GNUNET_TIME_relative_divide (
8226 vs->challenge_backoff,
8227 2));
8228 update_next_challenge_time (vs,
8229 GNUNET_TIME_relative_to_absolute (
8230 vs->challenge_backoff));
8231 }
8232 return;
8233 }
8234 now = GNUNET_TIME_absolute_get ();
8235 vs = GNUNET_new (struct ValidationState);
8236 vs->pid = *pid;
8237 vs->valid_until =
8238 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
8239 vs->first_challenge_use = now;
8240 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8241 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8242 &vs->challenge,
8243 sizeof(vs->challenge));
8244 vs->address = GNUNET_strdup (address);
8245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8246 "Starting address validation `%s' of peer %s using challenge %s\n",
8247 address,
8248 GNUNET_i2s (pid),
8249 GNUNET_sh2s (&vs->challenge.value));
8250 GNUNET_assert (GNUNET_YES ==
8251 GNUNET_CONTAINER_multipeermap_put (
8252 validation_map,
8253 &vs->pid,
8254 vs,
8255 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
8256 update_next_challenge_time (vs, now);
8257}
8258
8259
8260/**
8261 * Function called by PEERSTORE for each matching record.
8262 *
8263 * @param cls closure, a `struct IncomingRequest`
8264 * @param record peerstore record information
8265 * @param emsg error message, or NULL if no errors
8266 */
8267static void
8268handle_hello_for_incoming (void *cls,
8269 const struct GNUNET_PEERSTORE_Record *record,
8270 const char *emsg)
8271{
8272 struct IncomingRequest *ir = cls;
8273 const char *val;
8274
8275 if (NULL != emsg)
8276 {
8277 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8278 "Got failure from PEERSTORE: %s\n",
8279 emsg);
8280 return;
8281 }
8282 val = record->value;
8283 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8284 {
8285 GNUNET_break (0);
8286 return;
8287 }
8288 start_address_validation (&ir->pid, (const char *) record->value);
8289}
8290
8291
8292/**
8293 * Communicator gave us a transport address validation challenge. Process the
8294 * request.
8295 *
8296 * @param cls a `struct CommunicatorMessageContext` (must call
8297 * #finish_cmc_handling() when done)
8298 * @param tvc the message that was received
8299 */
8300static void
8301handle_validation_challenge (
8302 void *cls,
8303 const struct TransportValidationChallengeMessage *tvc)
8304{
8305 struct CommunicatorMessageContext *cmc = cls;
8306 struct TransportValidationResponseMessage tvr;
8307 struct VirtualLink *vl;
8308 struct GNUNET_TIME_RelativeNBO validity_duration;
8309 struct IncomingRequest *ir;
8310 struct Neighbour *n;
8311 struct GNUNET_PeerIdentity sender;
8312
8313 /* DV-routed messages are not allowed for validation challenges */
8314 if (cmc->total_hops > 0)
8315 {
8316 GNUNET_break_op (0);
8317 finish_cmc_handling (cmc);
8318 return;
8319 }
8320 validity_duration = cmc->im.expected_address_validity;
8321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8322 "Received address validation challenge %s\n",
8323 GNUNET_sh2s (&tvc->challenge.value));
8324 /* If we have a virtual link, we use this mechanism to signal the
8325 size of the flow control window, and to allow the sender
8326 to ask for increases. If for us the virtual link is still down,
8327 we will always give a window size of zero. */
8328 tvr.header.type =
8329 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
8330 tvr.header.size = htons (sizeof(tvr));
8331 tvr.reserved = htonl (0);
8332 tvr.challenge = tvc->challenge;
8333 tvr.origin_time = tvc->sender_time;
8334 tvr.validity_duration = validity_duration;
8335 {
8336 /* create signature */
8337 struct TransportValidationPS tvp = {
8338 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
8339 .purpose.size = htonl (sizeof(tvp)),
8340 .validity_duration = validity_duration,
8341 .challenge = tvc->challenge
8342 };
8343
8344 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8345 &tvp,
8346 &tvr.signature);
8347 }
8348 sender = cmc->im.sender;
8349 vl = lookup_virtual_link (&sender);
8350 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
8351 {
8352 // route_control_message_without_fc (&cmc->im.sender,
8353 route_control_message_without_fc (vl,
8354 &tvr.header,
8355 RMO_ANYTHING_GOES | RMO_REDUNDANT);
8356 }
8357 else
8358 {
8359 /* Use route via neighbour */
8360 n = lookup_neighbour (&sender);
8361 if (NULL != n)
8362 route_via_neighbour (n, &tvr.header,
8363 RMO_ANYTHING_GOES | RMO_REDUNDANT
8364 | RMO_UNCONFIRMED_ALLOWED);
8365 }
8366
8367 finish_cmc_handling (cmc);
8368 if (NULL != vl)
8369 return;
8370
8371 /* For us, the link is still down, but we need bi-directional
8372 connections (for flow-control and for this to be useful for
8373 CORE), so we must try to bring the link up! */
8374
8375 /* (1) Check existing queues, if any, we may be lucky! */
8376 n = lookup_neighbour (&sender);
8377 if (NULL != n)
8378 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8379 start_address_validation (&sender, q->address);
8380 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
8381 we could use */
8382 for (ir = ir_head; NULL != ir; ir = ir->next)
8383 if (0 == GNUNET_memcmp (&ir->pid, &sender))
8384 return;
8385 /* we are already trying */
8386 ir = GNUNET_new (struct IncomingRequest);
8387 ir->pid = sender;
8388 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
8389 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
8390 "transport",
8391 &ir->pid,
8392 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8393 &handle_hello_for_incoming,
8394 ir);
8395 ir_total++;
8396 /* Bound attempts we do in parallel here, might otherwise get excessive */
8397 while (ir_total > MAX_INCOMING_REQUEST)
8398 free_incoming_request (ir_head);
8399}
8400
8401
8402/**
8403 * Closure for #check_known_challenge.
8404 */
8405struct CheckKnownChallengeContext
8406{
8407 /**
8408 * Set to the challenge we are looking for.
8409 */
8410 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge;
8411
8412 /**
8413 * Set to a matching validation state, if one was found.
8414 */
8415 struct ValidationState *vs;
8416};
8417
8418
8419/**
8420 * Test if the validation state in @a value matches the
8421 * challenge from @a cls.
8422 *
8423 * @param cls a `struct CheckKnownChallengeContext`
8424 * @param pid unused (must match though)
8425 * @param value a `struct ValidationState`
8426 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8427 */
8428static int
8429check_known_challenge (void *cls,
8430 const struct GNUNET_PeerIdentity *pid,
8431 void *value)
8432{
8433 struct CheckKnownChallengeContext *ckac = cls;
8434 struct ValidationState *vs = value;
8435
8436 (void) pid;
8437 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
8438 return GNUNET_OK;
8439 ckac->vs = vs;
8440 return GNUNET_NO;
8441}
8442
8443
8444/**
8445 * Function called when peerstore is done storing a
8446 * validated address.
8447 *
8448 * @param cls a `struct ValidationState`
8449 * @param success #GNUNET_YES on success
8450 */
8451static void
8452peerstore_store_validation_cb (void *cls, int success)
8453{
8454 struct ValidationState *vs = cls;
8455
8456 vs->sc = NULL;
8457 if (GNUNET_YES == success)
8458 return;
8459 GNUNET_STATISTICS_update (GST_stats,
8460 "# Peerstore failed to store foreign address",
8461 1,
8462 GNUNET_NO);
8463}
8464
8465
8466/**
8467 * Find the queue matching @a pid and @a address.
8468 *
8469 * @param pid peer the queue must go to
8470 * @param address address the queue must use
8471 * @return NULL if no such queue exists
8472 */
8473static struct Queue *
8474find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
8475{
8476 struct Neighbour *n;
8477
8478 n = lookup_neighbour (pid);
8479 if (NULL == n)
8480 return NULL;
8481 for (struct Queue *pos = n->queue_head; NULL != pos;
8482 pos = pos->next_neighbour)
8483 {
8484 if (0 == strcmp (pos->address, address))
8485 return pos;
8486 }
8487 return NULL;
8488}
8489
8490
8491/**
8492 * Communicator gave us a transport address validation response. Process the
8493 * request.
8494 *
8495 * @param cls a `struct CommunicatorMessageContext` (must call
8496 * #finish_cmc_handling() when done)
8497 * @param tvr the message that was received
8498 */
8499static void
8500handle_validation_response (
8501 void *cls,
8502 const struct TransportValidationResponseMessage *tvr)
8503{
8504 struct CommunicatorMessageContext *cmc = cls;
8505 struct ValidationState *vs;
8506 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
8507 .vs = NULL };
8508 struct GNUNET_TIME_Absolute origin_time;
8509 struct Queue *q;
8510 struct Neighbour *n;
8511 struct VirtualLink *vl;
8512
8513 /* check this is one of our challenges */
8514 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8515 &cmc->im.sender,
8516 &check_known_challenge,
8517 &ckac);
8518 if (NULL == (vs = ckac.vs))
8519 {
8520 /* This can happen simply if we 'forgot' the challenge by now,
8521 i.e. because we received the validation response twice */
8522 GNUNET_STATISTICS_update (GST_stats,
8523 "# Validations dropped, challenge unknown",
8524 1,
8525 GNUNET_NO);
8526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8527 "Validation response %s dropped, challenge unknown\n",
8528 GNUNET_sh2s (&tvr->challenge.value));
8529 finish_cmc_handling (cmc);
8530 return;
8531 }
8532
8533 /* sanity check on origin time */
8534 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
8535 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
8536 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
8537 {
8538 GNUNET_break_op (0);
8539 finish_cmc_handling (cmc);
8540 return;
8541 }
8542
8543 {
8544 /* check signature */
8545 struct TransportValidationPS tvp = {
8546 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
8547 .purpose.size = htonl (sizeof(tvp)),
8548 .validity_duration = tvr->validity_duration,
8549 .challenge = tvr->challenge
8550 };
8551
8552 if (
8553 GNUNET_OK !=
8554 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
8555 &tvp,
8556 &tvr->signature,
8557 &cmc->im.sender.public_key))
8558 {
8559 GNUNET_break_op (0);
8560 finish_cmc_handling (cmc);
8561 return;
8562 }
8563 }
8564
8565 /* validity is capped by our willingness to keep track of the
8566 validation entry and the maximum the other peer allows */
8567 vs->valid_until = GNUNET_TIME_relative_to_absolute (
8568 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
8569 tvr->validity_duration),
8570 MAX_ADDRESS_VALID_UNTIL));
8571 vs->validated_until =
8572 GNUNET_TIME_absolute_min (vs->valid_until,
8573 GNUNET_TIME_relative_to_absolute (
8574 ADDRESS_VALIDATION_LIFETIME));
8575 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
8576 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
8577 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8578 &vs->challenge,
8579 sizeof(vs->challenge));
8580 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
8581 vs->validated_until,
8582 GNUNET_TIME_relative_multiply (vs->validation_rtt,
8583 VALIDATION_RTT_BUFFER_FACTOR));
8584 vs->last_challenge_use =
8585 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
8586 update_next_challenge_time (vs, vs->first_challenge_use);
8587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8588 "Validation response %s accepted, address valid until %s\n",
8589 GNUNET_sh2s (&tvr->challenge.value),
8590 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
8591 vs->sc = GNUNET_PEERSTORE_store (peerstore,
8592 "transport",
8593 &cmc->im.sender,
8594 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8595 vs->address,
8596 strlen (vs->address) + 1,
8597 vs->valid_until,
8598 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
8599 &peerstore_store_validation_cb,
8600 vs);
8601 finish_cmc_handling (cmc);
8602
8603 /* Finally, we now possibly have a confirmed (!) working queue,
8604 update queue status (if queue still is around) */
8605 q = find_queue (&vs->pid, vs->address);
8606 if (NULL == q)
8607 {
8608 GNUNET_STATISTICS_update (GST_stats,
8609 "# Queues lost at time of successful validation",
8610 1,
8611 GNUNET_NO);
8612 return;
8613 }
8614 q->validated_until = vs->validated_until;
8615 q->pd.aged_rtt = vs->validation_rtt;
8616 n = q->neighbour;
8617 vl = lookup_virtual_link (&vs->pid);
8618 if (NULL == vl)
8619 {
8620 vl = GNUNET_new (struct VirtualLink);
8621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8622 "Creating new virtual link %p to %s using direct neighbour!\n",
8623 vl,
8624 GNUNET_i2s (&vs->pid));
8625 vl->confirmed = GNUNET_YES;
8626 vl->message_uuid_ctr =
8627 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
8628 vl->target = n->pid;
8629 vl->core_recv_window = RECV_WINDOW_SIZE;
8630 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8631 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
8632 GNUNET_break (GNUNET_YES ==
8633 GNUNET_CONTAINER_multipeermap_put (
8634 links,
8635 &vl->target,
8636 vl,
8637 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8638 vl->n = n;
8639 n->vl = vl;
8640 q->idle = GNUNET_YES;
8641 vl->visibility_task =
8642 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8643 consider_sending_fc (vl);
8644 /* We lacked a confirmed connection to the target
8645 before, so tell CORE about it (finally!) */
8646 cores_send_connect_info (&n->pid);
8647 }
8648 else
8649 {
8650 /* Link was already up, remember n is also now available and we are done */
8651 if (NULL == vl->n)
8652 {
8653 vl->n = n;
8654 n->vl = vl;
8655 if (GNUNET_YES == vl->confirmed)
8656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8657 "Virtual link to %s could now also direct neighbour!\n",
8658 GNUNET_i2s (&vs->pid));
8659 }
8660 else
8661 {
8662 GNUNET_assert (n == vl->n);
8663 }
8664 if (GNUNET_NO == vl->confirmed)
8665 {
8666 vl->confirmed = GNUNET_YES;
8667 q->idle = GNUNET_YES;
8668 vl->visibility_task =
8669 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8670 consider_sending_fc (vl);
8671 /* We lacked a confirmed connection to the target
8672 before, so tell CORE about it (finally!) */
8673 cores_send_connect_info (&n->pid);
8674 }
8675 }
8676}
8677
8678
8679/**
8680 * Incoming meessage. Process the request.
8681 *
8682 * @param im the send message that was received
8683 */
8684static void
8685handle_incoming_msg (void *cls,
8686 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8687{
8688 struct TransportClient *tc = cls;
8689 struct CommunicatorMessageContext *cmc =
8690 GNUNET_new (struct CommunicatorMessageContext);
8691
8692 cmc->tc = tc;
8693 cmc->im = *im;
8694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8695 "Received message with size %u via communicator from peer %s\n",
8696 &im->header.size,
8697 GNUNET_i2s (&im->sender));
8698 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
8699}
8700
8701
8702/**
8703 * Communicator gave us a transport address validation response. Process the
8704 * request.
8705 *
8706 * @param cls a `struct CommunicatorMessageContext` (must call
8707 * #finish_cmc_handling() when done)
8708 * @param fc the message that was received
8709 */
8710static void
8711handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
8712{
8713 struct CommunicatorMessageContext *cmc = cls;
8714 struct VirtualLink *vl;
8715 uint32_t seq;
8716 struct GNUNET_TIME_Absolute st;
8717 uint64_t os;
8718 uint64_t wnd;
8719 uint32_t random;
8720
8721 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8722 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
8723 vl = lookup_virtual_link (&cmc->im.sender);
8724 if (NULL == vl)
8725 {
8726 vl = GNUNET_new (struct VirtualLink);
8727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8728 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
8729 vl,
8730 GNUNET_i2s (&cmc->im.sender));
8731 vl->confirmed = GNUNET_NO;
8732 vl->message_uuid_ctr =
8733 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
8734 vl->target = cmc->im.sender;
8735 vl->core_recv_window = RECV_WINDOW_SIZE;
8736 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8737 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
8738 GNUNET_break (GNUNET_YES ==
8739 GNUNET_CONTAINER_multipeermap_put (
8740 links,
8741 &vl->target,
8742 vl,
8743 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8744 }
8745 st = GNUNET_TIME_absolute_ntoh (fc->sender_time);
8746 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
8747 {
8748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8749 "FC dropped: Message out of order\n");
8750 /* out of order, drop */
8751 GNUNET_STATISTICS_update (GST_stats,
8752 "# FC dropped: message out of order",
8753 1,
8754 GNUNET_NO);
8755 finish_cmc_handling (cmc);
8756 return;
8757 }
8758 seq = ntohl (fc->seq);
8759 if (seq < vl->last_fc_seq)
8760 {
8761 /* Wrap-around/reset of other peer; start all counters from zero */
8762 vl->outbound_fc_window_size_used = 0;
8763 }
8764 vl->last_fc_seq = seq;
8765 vl->last_fc_timestamp = st;
8766 vl->outbound_fc_window_size = GNUNET_ntohll (fc->inbound_window_size);
8767 os = GNUNET_ntohll (fc->outbound_sent);
8768 vl->incoming_fc_window_size_loss =
8769 (int64_t) (os - vl->incoming_fc_window_size_used);
8770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8771 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
8772 GNUNET_i2s (&vl->target),
8773 (unsigned int) seq,
8774 (unsigned long long) vl->outbound_fc_window_size,
8775 (long long) vl->incoming_fc_window_size_loss);
8776 wnd = GNUNET_ntohll (fc->outbound_window_size);
8777 random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
8778 UINT32_MAX);
8779 if ((GNUNET_YES == vl->confirmed) && ((wnd < vl->incoming_fc_window_size) ||
8780 (vl->last_outbound_window_size_received
8781 != wnd) ||
8782 (0 == random
8783 % FC_NO_CHANGE_REPLY_PROBABILITY)))
8784 {
8785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8786 "Consider re-sending our FC message, as clearly the other peer's idea of the window is not up-to-date (%llu vs %llu) or %llu last received differs, or random reply %lu\n",
8787 (unsigned long long) wnd,
8788 (unsigned long long) vl->incoming_fc_window_size,
8789 (unsigned long long) vl->last_outbound_window_size_received,
8790 random % FC_NO_CHANGE_REPLY_PROBABILITY);
8791 consider_sending_fc (vl);
8792 }
8793 if ((wnd == vl->incoming_fc_window_size) &&
8794 (vl->last_outbound_window_size_received == wnd) &&
8795 (NULL != vl->fc_retransmit_task))
8796 {
8797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8798 "Stopping FC retransmission to %s: peer is current at window %llu\n",
8799 GNUNET_i2s (&vl->target),
8800 (unsigned long long) wnd);
8801 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
8802 vl->fc_retransmit_task = NULL;
8803 vl->fc_retransmit_count = 0;
8804 }
8805 vl->last_outbound_window_size_received = wnd;
8806 /* FC window likely increased, check transmission possibilities! */
8807 check_vl_transmission (vl);
8808 finish_cmc_handling (cmc);
8809}
8810
8811
8812/**
8813 * Given an inbound message @a msg from a communicator @a cmc,
8814 * demultiplex it based on the type calling the right handler.
8815 *
8816 * @param cmc context for demultiplexing
8817 * @param msg message to demultiplex
8818 */
8819static void
8820demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
8821 const struct GNUNET_MessageHeader *msg)
8822{
8823 struct GNUNET_MQ_MessageHandler handlers[] =
8824 { GNUNET_MQ_hd_var_size (fragment_box,
8825 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
8826 struct TransportFragmentBoxMessage,
8827 cmc),
8828 GNUNET_MQ_hd_var_size (reliability_box,
8829 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
8830 struct TransportReliabilityBoxMessage,
8831 cmc),
8832 GNUNET_MQ_hd_var_size (reliability_ack,
8833 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
8834 struct TransportReliabilityAckMessage,
8835 cmc),
8836 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
8837 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
8838 struct TransportBackchannelEncapsulationMessage,
8839 cmc),
8840 GNUNET_MQ_hd_var_size (dv_learn,
8841 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
8842 struct TransportDVLearnMessage,
8843 cmc),
8844 GNUNET_MQ_hd_var_size (dv_box,
8845 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
8846 struct TransportDVBoxMessage,
8847 cmc),
8848 GNUNET_MQ_hd_fixed_size (
8849 validation_challenge,
8850 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
8851 struct TransportValidationChallengeMessage,
8852 cmc),
8853 GNUNET_MQ_hd_fixed_size (flow_control,
8854 GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL,
8855 struct TransportFlowControlMessage,
8856 cmc),
8857 GNUNET_MQ_hd_fixed_size (
8858 validation_response,
8859 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
8860 struct TransportValidationResponseMessage,
8861 cmc),
8862 GNUNET_MQ_handler_end () };
8863 int ret;
8864
8865 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8866 "Handling message of type %u with %u bytes\n",
8867 (unsigned int) ntohs (msg->type),
8868 (unsigned int) ntohs (msg->size));
8869 ret = GNUNET_MQ_handle_message (handlers, msg);
8870 if (GNUNET_SYSERR == ret)
8871 {
8872 GNUNET_break (0);
8873 GNUNET_SERVICE_client_drop (cmc->tc->client);
8874 GNUNET_free (cmc);
8875 return;
8876 }
8877 if (GNUNET_NO == ret)
8878 {
8879 /* unencapsulated 'raw' message */
8880 handle_raw_message (cmc, msg);
8881 }
8882}
8883
8884
8885/**
8886 * New queue became available. Check message.
8887 *
8888 * @param cls the client
8889 * @param aqm the send message that was sent
8890 */
8891static int
8892check_add_queue_message (void *cls,
8893 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8894{
8895 struct TransportClient *tc = cls;
8896
8897 if (CT_COMMUNICATOR != tc->type)
8898 {
8899 GNUNET_break (0);
8900 return GNUNET_SYSERR;
8901 }
8902 GNUNET_MQ_check_zero_termination (aqm);
8903 return GNUNET_OK;
8904}
8905
8906
8907/**
8908 * If necessary, generates the UUID for a @a pm
8909 *
8910 * @param pm pending message to generate UUID for.
8911 */
8912static void
8913set_pending_message_uuid (struct PendingMessage *pm)
8914{
8915 if (pm->msg_uuid_set)
8916 return;
8917 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
8918 pm->msg_uuid_set = GNUNET_YES;
8919}
8920
8921
8922/**
8923 * Setup data structure waiting for acknowledgements.
8924 *
8925 * @param queue queue the @a pm will be sent over
8926 * @param dvh path the message will take, may be NULL
8927 * @param pm the pending message for transmission
8928 * @return corresponding fresh pending acknowledgement
8929 */
8930static struct PendingAcknowledgement *
8931prepare_pending_acknowledgement (struct Queue *queue,
8932 struct DistanceVectorHop *dvh,
8933 struct PendingMessage *pm)
8934{
8935 struct PendingAcknowledgement *pa;
8936
8937 pa = GNUNET_new (struct PendingAcknowledgement);
8938 pa->queue = queue;
8939 pa->dvh = dvh;
8940 pa->pm = pm;
8941 do
8942 {
8943 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8944 &pa->ack_uuid,
8945 sizeof(pa->ack_uuid));
8946 }
8947 while (GNUNET_YES != GNUNET_CONTAINER_multiuuidmap_put (
8948 pending_acks,
8949 &pa->ack_uuid.value,
8950 pa,
8951 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8952 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
8953 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
8954 if (NULL != dvh)
8955 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
8956 pa->transmission_time = GNUNET_TIME_absolute_get ();
8957 pa->message_size = pm->bytes_msg;
8958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8959 "Waiting for ACKnowledgment `%s' for <%llu>\n",
8960 GNUNET_uuid2s (&pa->ack_uuid.value),
8961 pm->logging_uuid);
8962 return pa;
8963}
8964
8965
8966/**
8967 * Fragment the given @a pm to the given @a mtu. Adds
8968 * additional fragments to the neighbour as well. If the
8969 * @a mtu is too small, generates and error for the @a pm
8970 * and returns NULL.
8971 *
8972 * @param queue which queue to fragment for
8973 * @param dvh path the message will take, or NULL
8974 * @param pm pending message to fragment for transmission
8975 * @return new message to transmit
8976 */
8977static struct PendingMessage *
8978fragment_message (struct Queue *queue,
8979 struct DistanceVectorHop *dvh,
8980 struct PendingMessage *pm)
8981{
8982 struct PendingAcknowledgement *pa;
8983 struct PendingMessage *ff;
8984 uint16_t mtu;
8985
8986 mtu = (UINT16_MAX == queue->mtu)
8987 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
8988 : queue->mtu;
8989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8990 "Fragmenting message <%llu> with size %u to %s for MTU %u\n",
8991 pm->logging_uuid,
8992 pm->bytes_msg,
8993 GNUNET_i2s (&pm->vl->target),
8994 (unsigned int) mtu);
8995 set_pending_message_uuid (pm);
8996 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8997 "Fragmenting message %llu <%llu> with size %u to %s for MTU %u\n",
8998 (unsigned long long) pm->msg_uuid.uuid,
8999 pm->logging_uuid,
9000 pm->bytes_msg,
9001 GNUNET_i2s (&pm->vl->target),
9002 (unsigned int) mtu);
9003
9004 /* This invariant is established in #handle_add_queue_message() */
9005 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
9006
9007 /* select fragment for transmission, descending the tree if it has
9008 been expanded until we are at a leaf or at a fragment that is small
9009 enough
9010 */
9011 ff = pm;
9012 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
9013 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
9014 {
9015 ff = ff->head_frag; /* descent into fragmented fragments */
9016 }
9017
9018 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < ff->bytes_msg))
9019 {
9020 /* Did not yet calculate all fragments, calculate next fragment */
9021 struct PendingMessage *frag;
9022 struct TransportFragmentBoxMessage tfb;
9023 const char *orig;
9024 char *msg;
9025 uint16_t fragmax;
9026 uint16_t fragsize;
9027 uint16_t msize;
9028 uint16_t xoff = 0;
9029
9030 orig = (const char *) &ff[1];
9031 msize = ff->bytes_msg;
9032 if (pm != ff)
9033 {
9034 const struct TransportFragmentBoxMessage *tfbo;
9035
9036 tfbo = (const struct TransportFragmentBoxMessage *) orig;
9037 orig += sizeof(struct TransportFragmentBoxMessage);
9038 msize -= sizeof(struct TransportFragmentBoxMessage);
9039 xoff = ntohs (tfbo->frag_off);
9040 }
9041 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
9042 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
9043 frag =
9044 GNUNET_malloc (sizeof(struct PendingMessage)
9045 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
9046 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9047 "3 created pm %p from pm %p storing vl %p from pm %p\n",
9048 frag,
9049 ff,
9050 pm->vl,
9051 pm);
9052 frag->logging_uuid = logging_uuid_gen++;
9053 frag->vl = pm->vl;
9054 frag->frag_parent = ff;
9055 frag->timeout = pm->timeout;
9056 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
9057 frag->pmt = PMT_FRAGMENT_BOX;
9058 msg = (char *) &frag[1];
9059 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
9060 tfb.header.size =
9061 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
9062 pa = prepare_pending_acknowledgement (queue, dvh, frag);
9063 tfb.ack_uuid = pa->ack_uuid;
9064 tfb.msg_uuid = pm->msg_uuid;
9065 tfb.frag_off = htons (ff->frag_off + xoff);
9066 tfb.msg_size = htons (pm->bytes_msg);
9067 memcpy (msg, &tfb, sizeof(tfb));
9068 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
9069 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag,
9070 ff->tail_frag, frag);
9071 ff->frag_off += fragsize;
9072 ff = frag;
9073 }
9074
9075 /* Move head to the tail and return it */
9076 GNUNET_CONTAINER_MDLL_remove (frag,
9077 ff->frag_parent->head_frag,
9078 ff->frag_parent->tail_frag,
9079 ff);
9080 GNUNET_CONTAINER_MDLL_insert_tail (frag,
9081 ff->frag_parent->head_frag,
9082 ff->frag_parent->tail_frag,
9083 ff);
9084
9085 return ff;
9086}
9087
9088
9089/**
9090 * Reliability-box the given @a pm. On error (can there be any), NULL
9091 * may be returned, otherwise the "replacement" for @a pm (which
9092 * should then be added to the respective neighbour's queue instead of
9093 * @a pm). If the @a pm is already fragmented or reliability boxed,
9094 * or itself an ACK, this function simply returns @a pm.
9095 *
9096 * @param queue which queue to prepare transmission for
9097 * @param dvh path the message will take, or NULL
9098 * @param pm pending message to box for transmission over unreliabile queue
9099 * @return new message to transmit
9100 */
9101static struct PendingMessage *
9102reliability_box_message (struct Queue *queue,
9103 struct DistanceVectorHop *dvh,
9104 struct PendingMessage *pm)
9105{
9106 struct TransportReliabilityBoxMessage rbox;
9107 struct PendingAcknowledgement *pa;
9108 struct PendingMessage *bpm;
9109 char *msg;
9110
9111 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
9112 return pm; /* already fragmented or reliability boxed, or control message:
9113 do nothing */
9114 if (NULL != pm->bpm)
9115 return pm->bpm; /* already computed earlier: do nothing */
9116 // TODO I guess we do not need this assertion. We might have a DLL with
9117 // fragments, because the MTU changed, and we do not need to fragment anymore.
9118 // But we should keep the fragments until message was completed, because
9119 // the MTU might change again.
9120 // GNUNET_assert (NULL == pm->head_frag);
9121 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
9122 {
9123 /* failed hard */
9124 GNUNET_break (0);
9125 client_send_response (pm);
9126 return NULL;
9127 }
9128
9129 pa = prepare_pending_acknowledgement (queue, dvh, pm);
9130
9131 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
9132 + pm->bytes_msg);
9133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9134 "4 created pm %p storing vl %p from pm %p\n",
9135 bpm,
9136 pm->vl,
9137 pm);
9138 bpm->logging_uuid = logging_uuid_gen++;
9139 bpm->vl = pm->vl;
9140 bpm->frag_parent = pm;
9141 // Why was this needed?
9142 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
9143 bpm->timeout = pm->timeout;
9144 bpm->pmt = PMT_RELIABILITY_BOX;
9145 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
9146 set_pending_message_uuid (bpm);
9147 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
9148 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
9149 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
9150
9151 rbox.ack_uuid = pa->ack_uuid;
9152 msg = (char *) &bpm[1];
9153 memcpy (msg, &rbox, sizeof(rbox));
9154 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
9155 pm->bpm = bpm;
9156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9157 "Preparing reliability box for message <%llu> of size %lu (%lu) to %s on queue %s\n",
9158 pm->logging_uuid,
9159 pm->bytes_msg,
9160 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
9161 GNUNET_i2s (&pm->vl->target),
9162 queue->address);
9163 return bpm;
9164}
9165
9166
9167static void
9168reorder_root_pm (struct PendingMessage *pm,
9169 struct GNUNET_TIME_Absolute next_attempt)
9170{
9171 struct VirtualLink *vl = pm->vl;
9172 struct PendingMessage *pos;
9173
9174 /* re-insert sort in neighbour list */
9175 GNUNET_CONTAINER_MDLL_remove (vl,
9176 vl->pending_msg_head,
9177 vl->pending_msg_tail,
9178 pm);
9179 pos = vl->pending_msg_tail;
9180 while ((NULL != pos) &&
9181 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
9182 pos = pos->prev_vl;
9183 GNUNET_CONTAINER_MDLL_insert_after (vl,
9184 vl->pending_msg_head,
9185 vl->pending_msg_tail,
9186 pos,
9187 pm);
9188}
9189
9190
9191/**
9192 * Change the value of the `next_attempt` field of @a pm
9193 * to @a next_attempt and re-order @a pm in the transmission
9194 * list as required by the new timestamp.
9195 *
9196 * @param pm a pending message to update
9197 * @param next_attempt timestamp to use
9198 */
9199static void
9200update_pm_next_attempt (struct PendingMessage *pm,
9201 struct GNUNET_TIME_Absolute next_attempt)
9202{
9203 struct VirtualLink *vl = pm->vl;
9204
9205 // TODO Do we really need a next_attempt value for PendingMessage other than the root Pending Message?
9206 pm->next_attempt = next_attempt;
9207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9208 "Next attempt for message <%llu> set to %s\n",
9209 pm->logging_uuid,
9210 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
9211
9212 if (NULL == pm->frag_parent)
9213 {
9214 reorder_root_pm (pm, next_attempt);
9215 }
9216 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))
9217 {
9218 struct PendingMessage *root = pm->frag_parent;
9219
9220 while (NULL != root->frag_parent)
9221 root = root->frag_parent;
9222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9223 "Next attempt for root message <%llu> set to %s\n",
9224 root->logging_uuid);
9225 root->next_attempt = next_attempt;
9226 reorder_root_pm (root, next_attempt);
9227 }
9228 else
9229 {
9230 /* re-insert sort in fragment list */
9231 struct PendingMessage *fp = pm->frag_parent;
9232 struct PendingMessage *pos;
9233
9234 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
9235 pos = fp->tail_frag;
9236 while ((NULL != pos) &&
9237 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
9238 pos = pos->prev_frag;
9239 GNUNET_CONTAINER_MDLL_insert_after (frag,
9240 fp->head_frag,
9241 fp->tail_frag,
9242 pos,
9243 pm);
9244 if (NULL == pos)
9245 {
9246 pos = fp;
9247 // Get the root pm
9248 while (NULL != pos->frag_parent)
9249 pos = pos->frag_parent;
9250 pos->next_attempt = next_attempt;
9251 reorder_root_pm (pos, next_attempt);
9252 }
9253 }
9254}
9255
9256
9257/**
9258 * Context for #select_best_pending_from_link().
9259 */
9260struct PendingMessageScoreContext
9261{
9262 /**
9263 * Set to the best message that was found, NULL for none.
9264 */
9265 struct PendingMessage *best;
9266
9267 /**
9268 * DVH that @e best should take, or NULL for direct transmission.
9269 */
9270 struct DistanceVectorHop *dvh;
9271
9272 /**
9273 * What is the estimated total overhead for this message?
9274 */
9275 size_t real_overhead;
9276
9277 /**
9278 * Number of pending messages we seriously considered this time.
9279 */
9280 unsigned int consideration_counter;
9281
9282 /**
9283 * Did we have to fragment?
9284 */
9285 int frag;
9286
9287 /**
9288 * Did we have to reliability box?
9289 */
9290 int relb;
9291
9292 /**
9293 * There are pending messages, but it was to early to send one of them.
9294 */
9295 int to_early;
9296
9297 /**
9298 * When will we try to transmit the message again for which it was to early to retry.
9299 */
9300 struct GNUNET_TIME_Relative to_early_retry_delay;
9301};
9302
9303
9304/**
9305 * Select the best pending message from @a vl for transmission
9306 * via @a queue.
9307 *
9308 * @param sc[in,out] best message so far (NULL for none), plus scoring data
9309 * @param queue the queue that will be used for transmission
9310 * @param vl the virtual link providing the messages
9311 * @param dvh path we are currently considering, or NULL for none
9312 * @param overhead number of bytes of overhead to be expected
9313 * from DV encapsulation (0 for without DV)
9314 */
9315static void
9316select_best_pending_from_link (struct PendingMessageScoreContext *sc,
9317 struct Queue *queue,
9318 struct VirtualLink *vl,
9319 struct DistanceVectorHop *dvh,
9320 size_t overhead)
9321{
9322 struct GNUNET_TIME_Absolute now;
9323
9324 now = GNUNET_TIME_absolute_get ();
9325 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
9326 pos = pos->next_vl)
9327 {
9328 size_t real_overhead = overhead;
9329 int frag;
9330 int relb;
9331
9332 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
9333 {
9334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9335 "DV messages must not be DV-routed to next hop!\n");
9336 continue; /* DV messages must not be DV-routed to next hop! */
9337 }
9338 if (pos->next_attempt.abs_value_us > now.abs_value_us)
9339 {
9340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9341 "too early for all messages, they are sorted by next_attempt\n");
9342 sc->to_early = GNUNET_YES;
9343 sc->to_early_retry_delay = GNUNET_TIME_absolute_get_remaining (
9344 pos->next_attempt);
9345
9346 break; /* too early for all messages, they are sorted by next_attempt */
9347 }
9348 sc->to_early = GNUNET_NO;
9349 if (NULL != pos->qe)
9350 {
9351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9352 "not eligible\n");
9353 continue; /* not eligible */
9354 }
9355 sc->consideration_counter++;
9356 /* determine if we have to fragment, if so add fragmentation
9357 overhead! */
9358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9359 "check %u for sc->best\n",
9360 pos->logging_uuid);
9361 frag = GNUNET_NO;
9362 if (((0 != queue->mtu) &&
9363 (pos->bytes_msg + real_overhead > queue->mtu)) ||
9364 (pos->bytes_msg > UINT16_MAX - sizeof(struct
9365 GNUNET_TRANSPORT_SendMessageTo))
9366 ||
9367 (NULL != pos->head_frag /* fragments already exist, should
9368 respect that even if MTU is UINT16_MAX for
9369 this queue */))
9370 {
9371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9372 "fragment msg with size %u, realoverhead is %u\n",
9373 pos->bytes_msg,
9374 real_overhead);
9375 frag = GNUNET_YES;
9376 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
9377 {
9378 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
9379 header without the ACK UUID when using a *reliable* channel! */
9380 }
9381 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
9382 }
9383 /* determine if we have to reliability-box, if so add reliability box
9384 overhead */
9385 relb = GNUNET_NO;
9386 if ((GNUNET_NO == frag) &&
9387 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
9388 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
9389 {
9390 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
9391
9392 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
9393 {
9394 frag = GNUNET_YES;
9395 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
9396 }
9397 else
9398 {
9399 relb = GNUNET_YES;
9400 }
9401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9402 "Create reliability box of msg with size %u, realoverhead is %u %u %u %u\n",
9403 pos->bytes_msg,
9404 real_overhead,
9405 queue->mtu,
9406 frag,
9407 relb);
9408 }
9409
9410 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
9411 message would beat it! */
9412 if (NULL != sc->best)
9413 {
9414 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
9415 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
9416 experimentally validated. There may be some huge potential for
9417 improvement here. Also, we right now only compare how well the
9418 given message fits _this_ queue, and do not consider how well other
9419 queues might suit the message. Taking other queues into consideration
9420 may further improve the result, but could also be expensive
9421 in terms of CPU time. */
9422 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
9423 long long pm_score = frag * 40 + relb * 20 + real_overhead;
9424 long long time_delta =
9425 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
9426 / 1000LL;
9427
9428 /* "time_delta" considers which message has been 'ready' for transmission
9429 for longer, if a message has a preference for low latency, increase
9430 the weight of the time_delta by 10x if it is favorable for that message */
9431 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9432 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
9433 time_delta *= 10; /* increase weight (always, both are low latency) */
9434 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9435 (time_delta > 0))
9436 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
9437 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9438 (time_delta < 0))
9439 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
9440 if (0 != queue->mtu)
9441 {
9442 /* Grant bonus if we are below MTU, larger bonus the closer we will
9443 be to the MTU */
9444 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
9445 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
9446 if (queue->mtu > real_overhead + pos->bytes_msg)
9447 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
9448 }
9449 if (sc_score + time_delta > pm_score)
9450 {
9451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9452 "sc_score of %u larger, keep sc->best %u\n",
9453 pos->logging_uuid,
9454 sc->best->logging_uuid);
9455 continue; /* sc_score larger, keep sc->best */
9456 }
9457 }
9458 sc->best = pos;
9459 sc->dvh = dvh;
9460 sc->frag = frag;
9461 sc->relb = relb;
9462 sc->real_overhead = real_overhead;
9463 }
9464}
9465
9466
9467/**
9468 * Function to call to further operate on the now DV encapsulated
9469 * message @a hdr, forwarding it via @a next_hop under respect of
9470 * @a options.
9471 *
9472 * @param cls a `struct PendingMessageScoreContext`
9473 * @param next_hop next hop of the DV path
9474 * @param hdr encapsulated message, technically a `struct TransportDVBoxMessage`
9475 * @param options options of the original message
9476 */
9477static void
9478extract_box_cb (void *cls,
9479 struct Neighbour *next_hop,
9480 const struct GNUNET_MessageHeader *hdr,
9481 enum RouteMessageOptions options)
9482{
9483 struct PendingMessageScoreContext *sc = cls;
9484 struct PendingMessage *pm = sc->best;
9485 struct PendingMessage *bpm;
9486 uint16_t bsize = ntohs (hdr->size);
9487
9488 GNUNET_assert (NULL == pm->bpm);
9489 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
9490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9491 "5 created pm %p storing vl %p from pm %p\n",
9492 bpm,
9493 pm->vl,
9494 pm);
9495 bpm->logging_uuid = logging_uuid_gen++;
9496 bpm->pmt = PMT_DV_BOX;
9497 bpm->vl = pm->vl;
9498 bpm->timeout = pm->timeout;
9499 bpm->bytes_msg = bsize;
9500 bpm->frag_parent = pm;
9501 set_pending_message_uuid (bpm);
9502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9503 "Creating DV Box %llu for original message %llu (next hop is %s)\n",
9504 bpm->logging_uuid,
9505 pm->logging_uuid,
9506 GNUNET_i2s (&next_hop->pid));
9507 memcpy (&bpm[1], hdr, bsize);
9508 pm->bpm = bpm;
9509}
9510
9511
9512/**
9513 * We believe we are ready to transmit a `struct PendingMessage` on a
9514 * queue, the big question is which one! We need to see if there is
9515 * one pending that is allowed by flow control and congestion control
9516 * and (ideally) matches our queue's performance profile.
9517 *
9518 * If such a message is found, we give the message to the communicator
9519 * for transmission (updating the tracker, and re-scheduling ourselves
9520 * if applicable).
9521 *
9522 * If no such message is found, the queue's `idle` field must be set
9523 * to #GNUNET_YES.
9524 *
9525 * @param cls the `struct Queue` to process transmissions for
9526 */
9527static void
9528transmit_on_queue (void *cls)
9529{
9530 struct Queue *queue = cls;
9531 struct Neighbour *n = queue->neighbour;
9532 struct PendingMessageScoreContext sc;
9533 struct PendingMessage *pm;
9534
9535 queue->transmit_task = NULL;
9536 if (NULL == n->vl)
9537 {
9538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9539 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
9540 GNUNET_i2s (&n->pid),
9541 queue->address);
9542 queue->idle = GNUNET_YES;
9543 return;
9544 }
9545 memset (&sc, 0, sizeof(sc));
9546 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
9547 if (NULL == sc.best)
9548 {
9549 /* Also look at DVH that have the n as first hop! */
9550 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
9551 dvh = dvh->next_neighbour)
9552 {
9553 select_best_pending_from_link (&sc,
9554 queue,
9555 dvh->dv->vl,
9556 dvh,
9557 sizeof(struct GNUNET_PeerIdentity)
9558 * (1 + dvh->distance)
9559 + sizeof(struct TransportDVBoxMessage)
9560 + sizeof(struct TransportDVBoxPayloadP));
9561 }
9562 }
9563 if (NULL == sc.best)
9564 {
9565 /* no message pending, nothing to do here! */
9566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9567 "No pending messages, queue `%s' to %s now idle\n",
9568 queue->address,
9569 GNUNET_i2s (&n->pid));
9570 if (GNUNET_YES == sc.to_early)
9571 schedule_transmit_on_queue (sc.to_early_retry_delay,
9572 queue,
9573 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9574 queue->idle = GNUNET_YES;
9575 return;
9576 }
9577 /* There is a message pending, we are certainly not idle */
9578 queue->idle = GNUNET_NO;
9579
9580 /* Given selection in `sc`, do transmission */
9581 pm = sc.best;
9582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9583 "Selected message <%llu>\n",
9584 pm->logging_uuid);
9585 if (NULL != sc.dvh)
9586 {
9587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9588 "Is this %u a DV box?\n",
9589 pm->pmt);
9590 GNUNET_assert (PMT_DV_BOX != pm->pmt);
9591 if ((NULL != sc.best->bpm) && (sc.best->bpm->used_dvh != sc.dvh))
9592 {
9593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9594 "Discard old box, because we have a new DV path.\n");
9595 free_pending_message (sc.best->bpm);
9596 sc.best->bpm = NULL;
9597 }
9598
9599 if (NULL == sc.best->bpm)
9600 {
9601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9602 "encapsulate_for_dv 2\n");
9603 encapsulate_for_dv (sc.dvh->dv,
9604 1,
9605 &sc.dvh,
9606 (const struct GNUNET_MessageHeader *) &sc.best[1],
9607 &extract_box_cb,
9608 &sc,
9609 RMO_NONE,
9610 GNUNET_NO);
9611 GNUNET_assert (NULL != sc.best->bpm);
9612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9613 "%u %u %u %u %u\n",
9614 sizeof(struct GNUNET_PeerIdentity),
9615 sizeof(struct TransportDVBoxMessage),
9616 sizeof(struct TransportDVBoxPayloadP),
9617 sizeof(struct TransportFragmentBoxMessage),
9618 ((const struct GNUNET_MessageHeader *) &sc.best[1])->size);
9619 sc.best->bpm->used_dvh = sc.dvh;
9620 }
9621 pm = sc.best->bpm;
9622 }
9623 if (GNUNET_YES == sc.frag)
9624 {
9625 pm = fragment_message (queue, sc.dvh, pm);
9626 if (NULL == pm)
9627 {
9628 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9629 "Fragmentation failed queue %s to %s for <%llu>, trying again\n",
9630 queue->address,
9631 GNUNET_i2s (&n->pid),
9632 sc.best->logging_uuid);
9633 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9634 queue,
9635 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9636 return;
9637 }
9638 }
9639 else if (GNUNET_YES == sc.relb)
9640 {
9641 pm = reliability_box_message (queue, sc.dvh, pm);
9642 if (NULL == pm)
9643 {
9644 /* Reliability boxing failed, try next message... */
9645 GNUNET_log (
9646 GNUNET_ERROR_TYPE_DEBUG,
9647 "Reliability boxing failed queue %s to %s for <%llu>, trying again\n",
9648 queue->address,
9649 GNUNET_i2s (&n->pid),
9650 sc.best->logging_uuid);
9651 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9652 queue,
9653 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9654 return;
9655 }
9656 }
9657
9658 /* Pass 'pm' for transission to the communicator */
9659 GNUNET_log (
9660 GNUNET_ERROR_TYPE_DEBUG,
9661 "Passing message <%llu> to queue %s for peer %s (considered %u others)\n",
9662 pm->logging_uuid,
9663 queue->address,
9664 GNUNET_i2s (&n->pid),
9665 sc.consideration_counter);
9666
9667 /* Flow control: increment amount of traffic sent; if we are routing
9668 via DV (and thus the ultimate target of the pending message is for
9669 a different virtual link than the one of the queue), then we need
9670 to use up not only the window of the direct link but also the
9671 flow control window for the DV link! */
9672 pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
9673
9674 if (pm->vl != queue->neighbour->vl)
9675 {
9676 /* If the virtual link of the queue differs, this better be distance
9677 vector routing! */
9678 GNUNET_assert (NULL != sc.dvh);
9679 /* If we do distance vector routing, we better not do this for a
9680 message that was itself DV-routed */
9681 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
9682 /* We use the size of the unboxed message here, to avoid counting
9683 the DV-Box header which is eaten up on the way by intermediaries */
9684 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
9685 }
9686 else
9687 {
9688 GNUNET_assert (NULL == sc.dvh);
9689 }
9690
9691 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
9692
9693 /* Check if this transmission somehow conclusively finished handing 'pm'
9694 even without any explicit ACKs */
9695 if ((PMT_CORE == pm->pmt) ||
9696 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
9697 {
9698 completed_pending_message (pm);
9699 }
9700 else
9701 {
9702 struct GNUNET_TIME_Relative wait_duration;
9703
9704 /* Message not finished, waiting for acknowledgement.
9705 Update time by which we might retransmit 's' based on queue
9706 characteristics (i.e. RTT); it takes one RTT for the message to
9707 arrive and the ACK to come back in the best case; but the other
9708 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
9709 retransmitting.
9710
9711 OPTIMIZE: Note that in the future this heuristic should likely
9712 be improved further (measure RTT stability, consider message
9713 urgency and size when delaying ACKs, etc.) */
9714
9715 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
9716 queue->pd.aged_rtt.rel_value_us)
9717 wait_duration = queue->pd.aged_rtt;
9718 else
9719 wait_duration = DEFAULT_ACK_WAIT_DURATION;
9720 struct GNUNET_TIME_Absolute next = GNUNET_TIME_relative_to_absolute (
9721 GNUNET_TIME_relative_multiply (
9722 wait_duration, 4));
9723 struct GNUNET_TIME_Relative plus = GNUNET_TIME_relative_multiply (
9724 wait_duration, 4);
9725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9726 "Waiting %s (%llu) for ACK until %llu\n",
9727 GNUNET_STRINGS_relative_time_to_string (
9728 GNUNET_TIME_relative_multiply (
9729 queue->pd.aged_rtt, 4), GNUNET_NO),
9730 plus,
9731 next);
9732 update_pm_next_attempt (pm,
9733 GNUNET_TIME_relative_to_absolute (
9734 GNUNET_TIME_relative_multiply (wait_duration,
9735 4)));
9736 }
9737 /* finally, re-schedule queue transmission task itself */
9738 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9739 queue,
9740 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9741}
9742
9743
9744/**
9745 * Queue to a peer went down. Process the request.
9746 *
9747 * @param cls the client
9748 * @param dqm the send message that was sent
9749 */
9750static void
9751handle_del_queue_message (void *cls,
9752 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
9753{
9754 struct TransportClient *tc = cls;
9755
9756 if (CT_COMMUNICATOR != tc->type)
9757 {
9758 GNUNET_break (0);
9759 GNUNET_SERVICE_client_drop (tc->client);
9760 return;
9761 }
9762 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
9763 queue = queue->next_client)
9764 {
9765 struct Neighbour *neighbour = queue->neighbour;
9766
9767 if ((dqm->qid != queue->qid) ||
9768 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
9769 continue;
9770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9771 "Dropped queue %s to peer %s\n",
9772 queue->address,
9773 GNUNET_i2s (&neighbour->pid));
9774 free_queue (queue);
9775 GNUNET_SERVICE_client_continue (tc->client);
9776 return;
9777 }
9778 GNUNET_break (0);
9779 GNUNET_SERVICE_client_drop (tc->client);
9780}
9781
9782
9783/**
9784 * Message was transmitted. Process the request.
9785 *
9786 * @param cls the client
9787 * @param sma the send message that was sent
9788 */
9789static void
9790handle_send_message_ack (void *cls,
9791 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
9792{
9793 struct TransportClient *tc = cls;
9794 struct QueueEntry *qe;
9795 struct PendingMessage *pm;
9796
9797 if (CT_COMMUNICATOR != tc->type)
9798 {
9799 GNUNET_break (0);
9800 GNUNET_SERVICE_client_drop (tc->client);
9801 return;
9802 }
9803
9804 /* find our queue entry matching the ACK */
9805 qe = NULL;
9806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9807 "Looking for queue for PID %s\n",
9808 GNUNET_i2s (&sma->receiver));
9809 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
9810 queue = queue->next_client)
9811 {
9812 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
9813 continue;
9814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9815 "Found PID %s\n",
9816 GNUNET_i2s (&queue->neighbour->pid));
9817
9818
9819 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
9820 qep = qep->next)
9821 {
9822 if (qep->mid != sma->mid)
9823 continue;
9824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9825 "QueueEntry MID: %llu on queue QID: %llu, Ack MID: %llu\n",
9826 (unsigned long long) qep->mid,
9827 (unsigned long long) queue->qid,
9828 (unsigned long long) sma->mid);
9829 qe = qep;
9830 if ((NULL != qe->pm)&&(qe->pm->qe != qe))
9831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9832 "For pending message %llu we had retransmissions.\n",
9833 qe->pm->logging_uuid);
9834 break;
9835 }
9836 }
9837 if (NULL == qe)
9838 {
9839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9840 "No QueueEntry found for Ack MID %llu\n",
9841 (unsigned long long) sma->mid);
9842 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
9843 /* this should never happen */
9844 /*GNUNET_break (0);
9845 GNUNET_SERVICE_client_drop (tc->client);*/
9846 GNUNET_SERVICE_client_continue (tc->client);
9847 return;
9848 }
9849 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
9850 qe->queue->queue_tail,
9851 qe);
9852 qe->queue->queue_length--;
9853 tc->details.communicator.total_queue_length--;
9854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9855 "Received ACK on queue %s to peer %s (new length: %u/%u)\n",
9856 qe->queue->address,
9857 GNUNET_i2s (&qe->queue->neighbour->pid),
9858 qe->queue->queue_length,
9859 tc->details.communicator.total_queue_length);
9860 GNUNET_SERVICE_client_continue (tc->client);
9861
9862 /* if applicable, resume transmissions that waited on ACK */
9863 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
9864 tc->details.communicator.total_queue_length)
9865 {
9866 /* Communicator dropped below threshold, resume all queues
9867 incident with this client! */
9868 GNUNET_STATISTICS_update (
9869 GST_stats,
9870 "# Transmission throttled due to communicator queue limit",
9871 -1,
9872 GNUNET_NO);
9873 for (struct Queue *queue = tc->details.communicator.queue_head;
9874 NULL != queue;
9875 queue = queue->next_client)
9876 {
9877 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9878 queue,
9879 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9880 }
9881 }
9882 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
9883 {
9884 /* queue dropped below threshold; only resume this one queue */
9885 GNUNET_STATISTICS_update (GST_stats,
9886 "# Transmission throttled due to queue queue limit",
9887 -1,
9888 GNUNET_NO);
9889 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9890 qe->queue,
9891 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9892 }
9893 else if (1 == qe->queue->q_capacity)
9894 {
9895 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
9896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9897 "Transmission rescheduled due to communicator message queue with qid %u has capacity %lu.\n",
9898 qe->queue->qid,
9899 qe->queue->q_capacity);
9900 /* message queue has capacity; only resume this one queue */
9901 /* queue dropped below threshold; only resume this one queue */
9902 GNUNET_STATISTICS_update (GST_stats,
9903 "# Transmission throttled due to message queue capacity",
9904 -1,
9905 GNUNET_NO);
9906 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9907 qe->queue,
9908 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9909 }
9910
9911 if (NULL != (pm = qe->pm))
9912 {
9913 struct VirtualLink *vl;
9914
9915 // GNUNET_assert (qe == pm->qe);
9916 pm->qe = NULL;
9917 /* If waiting for this communicator may have blocked transmission
9918 of pm on other queues for this neighbour, force schedule
9919 transmit on queue for queues of the neighbour */
9920 if (NULL == pm->frag_parent)
9921 {
9922 vl = pm->vl;
9923 if ((NULL != vl) &&
9924 (NULL != vl->pending_msg_head) &&
9925 (vl->pending_msg_head == pm))
9926 check_vl_transmission (vl);
9927 }
9928 }
9929 GNUNET_free (qe);
9930}
9931
9932
9933/**
9934 * Iterator telling new MONITOR client about all existing
9935 * queues to peers.
9936 *
9937 * @param cls the new `struct TransportClient`
9938 * @param pid a connected peer
9939 * @param value the `struct Neighbour` with more information
9940 * @return #GNUNET_OK (continue to iterate)
9941 */
9942static int
9943notify_client_queues (void *cls,
9944 const struct GNUNET_PeerIdentity *pid,
9945 void *value)
9946{
9947 struct TransportClient *tc = cls;
9948 struct Neighbour *neighbour = value;
9949
9950 GNUNET_assert (CT_MONITOR == tc->type);
9951 for (struct Queue *q = neighbour->queue_head; NULL != q;
9952 q = q->next_neighbour)
9953 {
9954 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
9955 .cs = q->cs,
9956 .num_msg_pending = q->num_msg_pending,
9957 .num_bytes_pending = q->num_bytes_pending };
9958
9959 notify_monitor (tc, pid, q->address, q->nt, &me);
9960 }
9961 return GNUNET_OK;
9962}
9963
9964
9965/**
9966 * Initialize a monitor client.
9967 *
9968 * @param cls the client
9969 * @param start the start message that was sent
9970 */
9971static void
9972handle_monitor_start (void *cls,
9973 const struct GNUNET_TRANSPORT_MonitorStart *start)
9974{
9975 struct TransportClient *tc = cls;
9976
9977 if (CT_NONE != tc->type)
9978 {
9979 GNUNET_break (0);
9980 GNUNET_SERVICE_client_drop (tc->client);
9981 return;
9982 }
9983 tc->type = CT_MONITOR;
9984 tc->details.monitor.peer = start->peer;
9985 tc->details.monitor.one_shot = ntohl (start->one_shot);
9986 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &notify_client_queues, tc);
9987 GNUNET_SERVICE_client_mark_monitor (tc->client);
9988 GNUNET_SERVICE_client_continue (tc->client);
9989}
9990
9991
9992/**
9993 * Find transport client providing communication service
9994 * for the protocol @a prefix.
9995 *
9996 * @param prefix communicator name
9997 * @return NULL if no such transport client is available
9998 */
9999static struct TransportClient *
10000lookup_communicator (const char *prefix)
10001{
10002 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
10003 {
10004 if (CT_COMMUNICATOR != tc->type)
10005 continue;
10006 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
10007 return tc;
10008 }
10009 GNUNET_log (
10010 GNUNET_ERROR_TYPE_WARNING,
10011 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
10012 prefix);
10013 return NULL;
10014}
10015
10016
10017/**
10018 * Signature of a function called with a communicator @a address of a peer
10019 * @a pid that an application wants us to connect to.
10020 *
10021 * @param pid target peer
10022 * @param address the address to try
10023 */
10024static void
10025suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
10026{
10027 static uint32_t idgen;
10028 struct TransportClient *tc;
10029 char *prefix;
10030 struct GNUNET_TRANSPORT_CreateQueue *cqm;
10031 struct GNUNET_MQ_Envelope *env;
10032 size_t alen;
10033
10034 prefix = GNUNET_HELLO_address_to_prefix (address);
10035 if (NULL == prefix)
10036 {
10037 GNUNET_break (0); /* We got an invalid address!? */
10038 return;
10039 }
10040 tc = lookup_communicator (prefix);
10041 if (NULL == tc)
10042 {
10043 GNUNET_STATISTICS_update (GST_stats,
10044 "# Suggestions ignored due to missing communicator",
10045 1,
10046 GNUNET_NO);
10047 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10048 "Cannot connect to %s at `%s', no matching communicator present\n",
10049 GNUNET_i2s (pid),
10050 address);
10051 GNUNET_free (prefix);
10052 return;
10053 }
10054 /* forward suggestion for queue creation to communicator */
10055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10056 "Request #%u for `%s' communicator to create queue to `%s'\n",
10057 (unsigned int) idgen,
10058 prefix,
10059 address);
10060 GNUNET_free (prefix);
10061 alen = strlen (address) + 1;
10062 env =
10063 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
10064 cqm->request_id = htonl (idgen++);
10065 cqm->receiver = *pid;
10066 memcpy (&cqm[1], address, alen);
10067 GNUNET_MQ_send (tc->mq, env);
10068}
10069
10070
10071/**
10072 * The queue @a q (which matches the peer and address in @a vs) is
10073 * ready for queueing. We should now queue the validation request.
10074 *
10075 * @param q queue to send on
10076 * @param vs state to derive validation challenge from
10077 */
10078static void
10079validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
10080{
10081 struct TransportValidationChallengeMessage tvc;
10082
10083 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
10084 tvc.header.type =
10085 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
10086 tvc.header.size = htons (sizeof(tvc));
10087 tvc.reserved = htonl (0);
10088 tvc.challenge = vs->challenge;
10089 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
10090 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10091 "Sending address validation challenge %s to %s\n",
10092 GNUNET_sh2s (&tvc.challenge.value),
10093 GNUNET_i2s (&q->neighbour->pid));
10094 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
10095}
10096
10097
10098/**
10099 * Task run periodically to validate some address based on #validation_heap.
10100 *
10101 * @param cls NULL
10102 */
10103static void
10104validation_start_cb (void *cls)
10105{
10106 struct ValidationState *vs;
10107 struct Queue *q;
10108
10109 (void) cls;
10110 validation_task = NULL;
10111 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
10112 /* drop validations past their expiration */
10113 while (
10114 (NULL != vs) &&
10115 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
10116 {
10117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10118 "Validation response %s cleaned up\n",
10119 GNUNET_sh2s (&vs->challenge.value));
10120 free_validation_state (vs);
10121 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
10122 }
10123 if (NULL == vs)
10124 {
10125 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10126 "Address validation task not scheduled anymore, nothing to do\n");
10127 return; /* woopsie, no more addresses known, should only
10128 happen if we're really a lonely peer */
10129 }
10130 q = find_queue (&vs->pid, vs->address);
10131 if (NULL == q)
10132 {
10133 vs->awaiting_queue = GNUNET_YES;
10134 suggest_to_connect (&vs->pid, vs->address);
10135 }
10136 else
10137 validation_transmit_on_queue (q, vs);
10138 /* Finally, reschedule next attempt */
10139 vs->challenge_backoff =
10140 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
10141 MAX_VALIDATION_CHALLENGE_FREQ);
10142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10143 "Address validation task will run again in %s\n",
10144 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
10145 GNUNET_YES));
10146 update_next_challenge_time (vs,
10147 GNUNET_TIME_relative_to_absolute (
10148 vs->challenge_backoff));
10149}
10150
10151
10152/**
10153 * Closure for #check_connection_quality.
10154 */
10155struct QueueQualityContext
10156{
10157 /**
10158 * Set to the @e k'th queue encountered.
10159 */
10160 struct Queue *q;
10161
10162 /**
10163 * Set to the number of quality queues encountered.
10164 */
10165 unsigned int quality_count;
10166
10167 /**
10168 * Set to the total number of queues encountered.
10169 */
10170 unsigned int num_queues;
10171
10172 /**
10173 * Decremented for each queue, for selection of the
10174 * k-th queue in @e q.
10175 */
10176 unsigned int k;
10177};
10178
10179
10180/**
10181 * Check whether any queue to the given neighbour is
10182 * of a good "quality" and if so, increment the counter.
10183 * Also counts the total number of queues, and returns
10184 * the k-th queue found.
10185 *
10186 * @param cls a `struct QueueQualityContext *` with counters
10187 * @param pid peer this is about
10188 * @param value a `struct Neighbour`
10189 * @return #GNUNET_OK (continue to iterate)
10190 */
10191static int
10192check_connection_quality (void *cls,
10193 const struct GNUNET_PeerIdentity *pid,
10194 void *value)
10195{
10196 struct QueueQualityContext *ctx = cls;
10197 struct Neighbour *n = value;
10198 int do_inc;
10199
10200 (void) pid;
10201 do_inc = GNUNET_NO;
10202 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
10203 {
10204 ctx->num_queues++;
10205 if (0 == ctx->k--)
10206 ctx->q = q;
10207 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
10208 statistics and consider those as well here? */
10209 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
10210 do_inc = GNUNET_YES;
10211 }
10212 if (GNUNET_YES == do_inc)
10213 ctx->quality_count++;
10214 return GNUNET_OK;
10215}
10216
10217
10218/**
10219 * Task run when we CONSIDER initiating a DV learn
10220 * process. We first check that sending out a message is
10221 * even possible (queues exist), then that it is desirable
10222 * (if not, reschedule the task for later), and finally
10223 * we may then begin the job. If there are too many
10224 * entries in the #dvlearn_map, we purge the oldest entry
10225 * using #lle_tail.
10226 *
10227 * @param cls NULL
10228 */
10229static void
10230start_dv_learn (void *cls)
10231{
10232 struct LearnLaunchEntry *lle;
10233 struct QueueQualityContext qqc;
10234 struct TransportDVLearnMessage dvl;
10235
10236 (void) cls;
10237 dvlearn_task = NULL;
10238 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
10239 return; /* lost all connectivity, cannot do learning */
10240 qqc.quality_count = 0;
10241 qqc.num_queues = 0;
10242 qqc.k = GNUNET_CONTAINER_multipeermap_size (neighbours);
10243 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10244 &check_connection_quality,
10245 &qqc);
10246 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
10247 {
10248 struct GNUNET_TIME_Relative delay;
10249 unsigned int factor;
10250
10251 /* scale our retries by how far we are above the threshold */
10252 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
10253 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
10254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10255 "At connection quality %u, will launch DV learn in %s\n",
10256 qqc.quality_count,
10257 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
10258 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
10259 return;
10260 }
10261 /* remove old entries in #dvlearn_map if it has grown too big */
10262 while (MAX_DV_LEARN_PENDING <=
10263 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
10264 {
10265 lle = lle_tail;
10266 GNUNET_assert (GNUNET_YES ==
10267 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
10268 &lle->challenge.value,
10269 lle));
10270 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
10271 GNUNET_free (lle);
10272 }
10273 /* setup data structure for learning */
10274 lle = GNUNET_new (struct LearnLaunchEntry);
10275 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
10276 &lle->challenge,
10277 sizeof(lle->challenge));
10278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10279 "Starting launch DV learn with challenge %s\n",
10280 GNUNET_sh2s (&lle->challenge.value));
10281 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
10282 GNUNET_break (GNUNET_YES ==
10283 GNUNET_CONTAINER_multishortmap_put (
10284 dvlearn_map,
10285 &lle->challenge.value,
10286 lle,
10287 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
10288 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
10289 dvl.header.size = htons (sizeof(dvl));
10290 dvl.num_hops = htons (0);
10291 dvl.bidirectional = htons (0);
10292 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
10293 dvl.monotonic_time =
10294 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
10295 {
10296 struct DvInitPS dvip = {
10297 .purpose.purpose = htonl (
10298 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
10299 .purpose.size = htonl (sizeof(dvip)),
10300 .monotonic_time = dvl.monotonic_time,
10301 .challenge = lle->challenge
10302 };
10303
10304 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
10305 &dvip,
10306 &dvl.init_sig);
10307 }
10308 dvl.initiator = GST_my_identity;
10309 dvl.challenge = lle->challenge;
10310
10311 qqc.quality_count = 0;
10312 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
10313 qqc.num_queues = 0;
10314 qqc.q = NULL;
10315 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10316 &check_connection_quality,
10317 &qqc);
10318 GNUNET_assert (NULL != qqc.q);
10319
10320 /* Do this as close to transmission time as possible! */
10321 lle->launch_time = GNUNET_TIME_absolute_get ();
10322
10323 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
10324 /* reschedule this job, randomizing the time it runs (but no
10325 actual backoff!) */
10326 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
10327 DV_LEARN_BASE_FREQUENCY),
10328 &start_dv_learn,
10329 NULL);
10330}
10331
10332
10333/**
10334 * A new queue has been created, check if any address validation
10335 * requests have been waiting for it.
10336 *
10337 * @param cls a `struct Queue`
10338 * @param pid peer concerned (unused)
10339 * @param value a `struct ValidationState`
10340 * @return #GNUNET_NO if a match was found and we can stop looking
10341 */
10342static int
10343check_validation_request_pending (void *cls,
10344 const struct GNUNET_PeerIdentity *pid,
10345 void *value)
10346{
10347 struct Queue *q = cls;
10348 struct ValidationState *vs = value;
10349
10350 (void) pid;
10351 if ((GNUNET_YES == vs->awaiting_queue) &&
10352 (0 == strcmp (vs->address, q->address)))
10353 {
10354 vs->awaiting_queue = GNUNET_NO;
10355 validation_transmit_on_queue (q, vs);
10356 return GNUNET_NO;
10357 }
10358 return GNUNET_OK;
10359}
10360
10361
10362/**
10363 * Function called with the monotonic time of a DV initiator
10364 * by PEERSTORE. Updates the time.
10365 *
10366 * @param cls a `struct Neighbour`
10367 * @param record the information found, NULL for the last call
10368 * @param emsg error message
10369 */
10370static void
10371neighbour_dv_monotime_cb (void *cls,
10372 const struct GNUNET_PEERSTORE_Record *record,
10373 const char *emsg)
10374{
10375 struct Neighbour *n = cls;
10376 struct GNUNET_TIME_AbsoluteNBO *mtbe;
10377
10378 (void) emsg;
10379 if (NULL == record)
10380 {
10381 /* we're done with #neighbour_dv_monotime_cb() invocations,
10382 continue normal processing */
10383 n->get = NULL;
10384 n->dv_monotime_available = GNUNET_YES;
10385 return;
10386 }
10387 if (sizeof(*mtbe) != record->value_size)
10388 {
10389 GNUNET_break (0);
10390 return;
10391 }
10392 mtbe = record->value;
10393 n->last_dv_learn_monotime =
10394 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
10395 GNUNET_TIME_absolute_ntoh (*mtbe));
10396}
10397
10398
10399/**
10400 * New queue became available. Process the request.
10401 *
10402 * @param cls the client
10403 * @param aqm the send message that was sent
10404 */
10405static void
10406handle_add_queue_message (void *cls,
10407 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
10408{
10409 struct TransportClient *tc = cls;
10410 struct Queue *queue;
10411 struct Neighbour *neighbour;
10412 const char *addr;
10413 uint16_t addr_len;
10414
10415 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
10416 {
10417 /* MTU so small as to be useless for transmissions,
10418 required for #fragment_message()! */
10419 GNUNET_break_op (0);
10420 GNUNET_SERVICE_client_drop (tc->client);
10421 return;
10422 }
10423 /* This may simply be a queue update */
10424 for (queue = tc->details.communicator.queue_head;
10425 NULL != queue;
10426 queue = queue->next_client)
10427 {
10428 if (queue->qid != aqm->qid)
10429 continue;
10430 break;
10431 }
10432
10433 if (NULL != queue)
10434 {
10435 neighbour = queue->neighbour;
10436 }
10437 else
10438 {
10439 neighbour = lookup_neighbour (&aqm->receiver);
10440 if (NULL == neighbour)
10441 {
10442 neighbour = GNUNET_new (struct Neighbour);
10443 neighbour->pid = aqm->receiver;
10444 GNUNET_assert (GNUNET_OK ==
10445 GNUNET_CONTAINER_multipeermap_put (
10446 neighbours,
10447 &neighbour->pid,
10448 neighbour,
10449 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
10450 neighbour->get =
10451 GNUNET_PEERSTORE_iterate (peerstore,
10452 "transport",
10453 &neighbour->pid,
10454 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
10455 &neighbour_dv_monotime_cb,
10456 neighbour);
10457 }
10458 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
10459 addr = (const char *) &aqm[1];
10460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10461 "New queue %s to %s available with QID %llu and q_len %lu and mtu %u\n",
10462 addr,
10463 GNUNET_i2s (&aqm->receiver),
10464 (unsigned long long) aqm->qid,
10465 GNUNET_ntohll (aqm->q_len),
10466 ntohl (aqm->mtu));
10467 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
10468 queue->tc = tc;
10469 queue->address = (const char *) &queue[1];
10470 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
10471 queue->qid = aqm->qid;
10472 queue->neighbour = neighbour;
10473 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (aqm->q_len))
10474 queue->unlimited_length = GNUNET_YES;
10475 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
10476 memcpy (&queue[1], addr, addr_len);
10477 /* notify monitors about new queue */
10478 {
10479 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
10480
10481 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
10482 }
10483 GNUNET_CONTAINER_MDLL_insert (neighbour,
10484 neighbour->queue_head,
10485 neighbour->queue_tail,
10486 queue);
10487 GNUNET_CONTAINER_MDLL_insert (client,
10488 tc->details.communicator.queue_head,
10489 tc->details.communicator.queue_tail,
10490 queue);
10491
10492 }
10493 queue->mtu = ntohl (aqm->mtu);
10494 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
10495 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
10496 queue->idle = GNUNET_YES;
10497 /* check if valdiations are waiting for the queue */
10498 (void)
10499 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
10500 &aqm->receiver,
10501 &check_validation_request_pending,
10502 queue);
10503 /* look for traffic for this queue */
10504 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10505 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10506 /* might be our first queue, try launching DV learning */
10507 if (NULL == dvlearn_task)
10508 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
10509 GNUNET_SERVICE_client_continue (tc->client);
10510}
10511
10512
10513/**
10514 * @brief Handle updates to queues.
10515 *
10516 * @param cls the transport client.
10517 * @param msg Message struct.
10518 */
10519static void
10520handle_update_queue_message (void *cls,
10521 const struct
10522 GNUNET_TRANSPORT_UpdateQueueMessage *msg)
10523{
10524 struct TransportClient *tc = cls;
10525 struct Queue *target_queue = NULL;
10526
10527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10528 "Received queue update message for %u with q_len %llu and mtu %u\n",
10529 msg->qid,
10530 (unsigned long long) GNUNET_ntohll (msg->q_len),
10531 ntohl (msg->mtu));
10532 for (target_queue = tc->details.communicator.queue_head;
10533 NULL != target_queue;
10534 target_queue = target_queue->next_client)
10535 {
10536 if (msg->qid == target_queue->qid)
10537 break;
10538 }
10539 if (NULL == target_queue)
10540 {
10541 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
10542 "Queue to update no longer exists! Discarding update.\n");
10543 return;
10544 }
10545
10546 target_queue->nt = msg->nt;
10547 target_queue->mtu = ntohl (msg->mtu);
10548 target_queue->cs = msg->cs;
10549 target_queue->priority = ntohl (msg->priority);
10550 /* The update message indicates how many messages
10551 * the queue should be able to handle.
10552 */
10553 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (msg->q_len))
10554 target_queue->unlimited_length = GNUNET_YES;
10555 else
10556 target_queue->unlimited_length = GNUNET_NO;
10557 target_queue->q_capacity = GNUNET_ntohll (msg->q_len);
10558 if (0 < target_queue->q_capacity)
10559 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10560 target_queue,
10561 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10562 GNUNET_SERVICE_client_continue (tc->client);
10563}
10564
10565
10566/**
10567 * Communicator tells us that our request to create a queue "worked", that
10568 * is setting up the queue is now in process.
10569 *
10570 * @param cls the `struct TransportClient`
10571 * @param cqr confirmation message
10572 */
10573static void
10574handle_queue_create_ok (void *cls,
10575 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
10576{
10577 struct TransportClient *tc = cls;
10578
10579 if (CT_COMMUNICATOR != tc->type)
10580 {
10581 GNUNET_break (0);
10582 GNUNET_SERVICE_client_drop (tc->client);
10583 return;
10584 }
10585 GNUNET_STATISTICS_update (GST_stats,
10586 "# Suggestions succeeded at communicator",
10587 1,
10588 GNUNET_NO);
10589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10590 "Request #%u for communicator to create queue succeeded\n",
10591 (unsigned int) ntohs (cqr->request_id));
10592 GNUNET_SERVICE_client_continue (tc->client);
10593}
10594
10595
10596/**
10597 * Communicator tells us that our request to create a queue failed. This
10598 * usually indicates that the provided address is simply invalid or that the
10599 * communicator's resources are exhausted.
10600 *
10601 * @param cls the `struct TransportClient`
10602 * @param cqr failure message
10603 */
10604static void
10605handle_queue_create_fail (
10606 void *cls,
10607 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
10608{
10609 struct TransportClient *tc = cls;
10610
10611 if (CT_COMMUNICATOR != tc->type)
10612 {
10613 GNUNET_break (0);
10614 GNUNET_SERVICE_client_drop (tc->client);
10615 return;
10616 }
10617 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10618 "Request #%u for communicator to create queue failed\n",
10619 (unsigned int) ntohs (cqr->request_id));
10620 GNUNET_STATISTICS_update (GST_stats,
10621 "# Suggestions failed in queue creation at communicator",
10622 1,
10623 GNUNET_NO);
10624 GNUNET_SERVICE_client_continue (tc->client);
10625}
10626
10627
10628/**
10629 * We have received a `struct ExpressPreferenceMessage` from an application
10630 * client.
10631 *
10632 * @param cls handle to the client
10633 * @param msg the start message
10634 */
10635static void
10636handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
10637{
10638 struct TransportClient *tc = cls;
10639 struct PeerRequest *pr;
10640
10641 if (CT_APPLICATION != tc->type)
10642 {
10643 GNUNET_break (0);
10644 GNUNET_SERVICE_client_drop (tc->client);
10645 return;
10646 }
10647 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
10648 &msg->peer);
10649 if (NULL == pr)
10650 {
10651 GNUNET_break (0);
10652 GNUNET_SERVICE_client_drop (tc->client);
10653 return;
10654 }
10655 (void) stop_peer_request (tc, &pr->pid, pr);
10656 GNUNET_SERVICE_client_continue (tc->client);
10657}
10658
10659
10660/**
10661 * Function called by PEERSTORE for each matching record.
10662 *
10663 * @param cls closure, a `struct PeerRequest`
10664 * @param record peerstore record information
10665 * @param emsg error message, or NULL if no errors
10666 */
10667static void
10668handle_hello_for_client (void *cls,
10669 const struct GNUNET_PEERSTORE_Record *record,
10670 const char *emsg)
10671{
10672 struct PeerRequest *pr = cls;
10673 const char *val;
10674
10675 if (NULL != emsg)
10676 {
10677 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
10678 "Got failure from PEERSTORE: %s\n",
10679 emsg);
10680 return;
10681 }
10682 val = record->value;
10683 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
10684 {
10685 GNUNET_break (0);
10686 return;
10687 }
10688 start_address_validation (&pr->pid, (const char *) record->value);
10689}
10690
10691
10692/**
10693 * We have received a `struct ExpressPreferenceMessage` from an application
10694 * client.
10695 *
10696 * @param cls handle to the client
10697 * @param msg the start message
10698 */
10699static void
10700handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
10701{
10702 struct TransportClient *tc = cls;
10703 struct PeerRequest *pr;
10704
10705 if (CT_NONE == tc->type)
10706 {
10707 tc->type = CT_APPLICATION;
10708 tc->details.application.requests =
10709 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
10710 }
10711 if (CT_APPLICATION != tc->type)
10712 {
10713 GNUNET_break (0);
10714 GNUNET_SERVICE_client_drop (tc->client);
10715 return;
10716 }
10717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10718 "Client suggested we talk to %s with preference %d at rate %u\n",
10719 GNUNET_i2s (&msg->peer),
10720 (int) ntohl (msg->pk),
10721 (int) ntohl (msg->bw.value__));
10722 pr = GNUNET_new (struct PeerRequest);
10723 pr->tc = tc;
10724 pr->pid = msg->peer;
10725 pr->bw = msg->bw;
10726 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
10727 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
10728 tc->details.application.requests,
10729 &pr->pid,
10730 pr,
10731 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
10732 {
10733 GNUNET_break (0);
10734 GNUNET_free (pr);
10735 GNUNET_SERVICE_client_drop (tc->client);
10736 return;
10737 }
10738 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
10739 "transport",
10740 &pr->pid,
10741 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
10742 &handle_hello_for_client,
10743 pr);
10744 GNUNET_SERVICE_client_continue (tc->client);
10745}
10746
10747
10748/**
10749 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
10750 * messages.
10751 *
10752 * @param cls a `struct TransportClient *`
10753 * @param m message to verify
10754 * @return #GNUNET_OK on success
10755 */
10756static int
10757check_request_hello_validation (void *cls,
10758 const struct RequestHelloValidationMessage *m)
10759{
10760 (void) cls;
10761 GNUNET_MQ_check_zero_termination (m);
10762 return GNUNET_OK;
10763}
10764
10765
10766/**
10767 * A client encountered an address of another peer. Consider validating it,
10768 * and if validation succeeds, persist it to PEERSTORE.
10769 *
10770 * @param cls a `struct TransportClient *`
10771 * @param m message to verify
10772 */
10773static void
10774handle_request_hello_validation (void *cls,
10775 const struct RequestHelloValidationMessage *m)
10776{
10777 struct TransportClient *tc = cls;
10778
10779 start_address_validation (&m->peer, (const char *) &m[1]);
10780 GNUNET_SERVICE_client_continue (tc->client);
10781}
10782
10783
10784/**
10785 * Free neighbour entry.
10786 *
10787 * @param cls NULL
10788 * @param pid unused
10789 * @param value a `struct Neighbour`
10790 * @return #GNUNET_OK (always)
10791 */
10792static int
10793free_neighbour_cb (void *cls,
10794 const struct GNUNET_PeerIdentity *pid,
10795 void *value)
10796{
10797 struct Neighbour *neighbour = value;
10798
10799 (void) cls;
10800 (void) pid;
10801 GNUNET_break (0); // should this ever happen?
10802 free_neighbour (neighbour);
10803
10804 return GNUNET_OK;
10805}
10806
10807
10808/**
10809 * Free DV route entry.
10810 *
10811 * @param cls NULL
10812 * @param pid unused
10813 * @param value a `struct DistanceVector`
10814 * @return #GNUNET_OK (always)
10815 */
10816static int
10817free_dv_routes_cb (void *cls,
10818 const struct GNUNET_PeerIdentity *pid,
10819 void *value)
10820{
10821 struct DistanceVector *dv = value;
10822
10823 (void) cls;
10824 (void) pid;
10825 free_dv_route (dv);
10826
10827 return GNUNET_OK;
10828}
10829
10830
10831/**
10832 * Free validation state.
10833 *
10834 * @param cls NULL
10835 * @param pid unused
10836 * @param value a `struct ValidationState`
10837 * @return #GNUNET_OK (always)
10838 */
10839static int
10840free_validation_state_cb (void *cls,
10841 const struct GNUNET_PeerIdentity *pid,
10842 void *value)
10843{
10844 struct ValidationState *vs = value;
10845
10846 (void) cls;
10847 (void) pid;
10848 free_validation_state (vs);
10849 return GNUNET_OK;
10850}
10851
10852
10853/**
10854 * Free pending acknowledgement.
10855 *
10856 * @param cls NULL
10857 * @param key unused
10858 * @param value a `struct PendingAcknowledgement`
10859 * @return #GNUNET_OK (always)
10860 */
10861static int
10862free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
10863{
10864 struct PendingAcknowledgement *pa = value;
10865
10866 (void) cls;
10867 (void) key;
10868 free_pending_acknowledgement (pa);
10869 return GNUNET_OK;
10870}
10871
10872
10873/**
10874 * Free acknowledgement cummulator.
10875 *
10876 * @param cls NULL
10877 * @param pid unused
10878 * @param value a `struct AcknowledgementCummulator`
10879 * @return #GNUNET_OK (always)
10880 */
10881static int
10882free_ack_cummulator_cb (void *cls,
10883 const struct GNUNET_PeerIdentity *pid,
10884 void *value)
10885{
10886 struct AcknowledgementCummulator *ac = value;
10887
10888 (void) cls;
10889 (void) pid;
10890 GNUNET_SCHEDULER_cancel (ac->task);
10891 GNUNET_free (ac);
10892 return GNUNET_OK;
10893}
10894
10895
10896/**
10897 * Function called when the service shuts down. Unloads our plugins
10898 * and cancels pending validations.
10899 *
10900 * @param cls closure, unused
10901 */
10902static void
10903do_shutdown (void *cls)
10904{
10905 struct LearnLaunchEntry *lle;
10906
10907 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10908 "shutdown logic\n");
10909 (void) cls;
10910 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10911 &free_neighbour_cb, NULL);
10912 if (NULL != validation_task)
10913 {
10914 GNUNET_SCHEDULER_cancel (validation_task);
10915 validation_task = NULL;
10916 }
10917 if (NULL != dvlearn_task)
10918 {
10919 GNUNET_SCHEDULER_cancel (dvlearn_task);
10920 dvlearn_task = NULL;
10921 }
10922 if (NULL != GST_stats)
10923 {
10924 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
10925 GST_stats = NULL;
10926 }
10927 if (NULL != GST_my_private_key)
10928 {
10929 GNUNET_free (GST_my_private_key);
10930 GST_my_private_key = NULL;
10931 }
10932 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
10933 &free_ack_cummulator_cb,
10934 NULL);
10935 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
10936 ack_cummulators = NULL;
10937 GNUNET_CONTAINER_multiuuidmap_iterate (pending_acks,
10938 &free_pending_ack_cb,
10939 NULL);
10940 GNUNET_CONTAINER_multiuuidmap_destroy (pending_acks);
10941 pending_acks = NULL;
10942 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
10943 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
10944 neighbours = NULL;
10945 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
10946 GNUNET_CONTAINER_multipeermap_destroy (links);
10947 links = NULL;
10948 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
10949 &free_backtalker_cb,
10950 NULL);
10951 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
10952 backtalkers = NULL;
10953 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
10954 &free_validation_state_cb,
10955 NULL);
10956 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
10957 validation_map = NULL;
10958 while (NULL != ir_head)
10959 free_incoming_request (ir_head);
10960 GNUNET_assert (0 == ir_total);
10961 while (NULL != (lle = lle_head))
10962 {
10963 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
10964 GNUNET_free (lle);
10965 }
10966 if (NULL != peerstore)
10967 {
10968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10969 "Disconnecting from PEERSTORE service\n");
10970 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
10971 peerstore = NULL;
10972 }
10973 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
10974 dvlearn_map = NULL;
10975 GNUNET_CONTAINER_heap_destroy (validation_heap);
10976 validation_heap = NULL;
10977 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
10978 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
10979 dv_routes = NULL;
10980 GNUNET_SCHEDULER_shutdown ();
10981}
10982
10983
10984static void
10985shutdown_task (void *cls)
10986{
10987 in_shutdown = GNUNET_YES;
10988
10989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10990 "Shutdown task executed\n");
10991 if (NULL != clients_head)
10992 {
10993 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
10994 {
10995 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
10996 "client still connected: %u\n",
10997 tc->type);
10998 }
10999 }
11000 else
11001 do_shutdown (cls);
11002
11003}
11004
11005
11006/**
11007 * Initiate transport service.
11008 *
11009 * @param cls closure
11010 * @param c configuration to use
11011 * @param service the initialized service
11012 */
11013static void
11014run (void *cls,
11015 const struct GNUNET_CONFIGURATION_Handle *c,
11016 struct GNUNET_SERVICE_Handle *service)
11017{
11018 (void) cls;
11019 (void) service;
11020 /* setup globals */
11021 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
11022 in_shutdown = GNUNET_NO;
11023 GST_cfg = c;
11024 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
11025 pending_acks = GNUNET_CONTAINER_multiuuidmap_create (32768, GNUNET_YES);
11026 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
11027 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11028 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
11029 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11030 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
11031 GNUNET_YES);
11032 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11033 validation_heap =
11034 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
11035 GST_my_private_key =
11036 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
11037 if (NULL == GST_my_private_key)
11038 {
11039 GNUNET_log (
11040 GNUNET_ERROR_TYPE_ERROR,
11041 _ (
11042 "Transport service is lacking key configuration settings. Exiting.\n"));
11043 GNUNET_SCHEDULER_shutdown ();
11044 return;
11045 }
11046 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
11047 &GST_my_identity.public_key);
11048 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
11049 "My identity is `%s'\n",
11050 GNUNET_i2s_full (&GST_my_identity));
11051 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
11052 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
11053 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
11054 if (NULL == peerstore)
11055 {
11056 GNUNET_break (0);
11057 GNUNET_SCHEDULER_shutdown ();
11058 return;
11059 }
11060}
11061
11062
11063/**
11064 * Define "main" method using service macro.
11065 */
11066GNUNET_SERVICE_MAIN (
11067 "transport",
11068 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
11069 &run,
11070 &client_connect_cb,
11071 &client_disconnect_cb,
11072 NULL,
11073 /* communication with applications */
11074 GNUNET_MQ_hd_fixed_size (suggest,
11075 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
11076 struct ExpressPreferenceMessage,
11077 NULL),
11078 GNUNET_MQ_hd_fixed_size (suggest_cancel,
11079 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
11080 struct ExpressPreferenceMessage,
11081 NULL),
11082 GNUNET_MQ_hd_var_size (request_hello_validation,
11083 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
11084 struct RequestHelloValidationMessage,
11085 NULL),
11086 /* communication with core */
11087 GNUNET_MQ_hd_fixed_size (client_start,
11088 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
11089 struct StartMessage,
11090 NULL),
11091 GNUNET_MQ_hd_var_size (client_send,
11092 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
11093 struct OutboundMessage,
11094 NULL),
11095 GNUNET_MQ_hd_fixed_size (client_recv_ok,
11096 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
11097 struct RecvOkMessage,
11098 NULL),
11099 /* communication with communicators */
11100 GNUNET_MQ_hd_var_size (communicator_available,
11101 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
11102 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
11103 NULL),
11104 GNUNET_MQ_hd_var_size (communicator_backchannel,
11105 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
11106 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
11107 NULL),
11108 GNUNET_MQ_hd_var_size (add_address,
11109 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
11110 struct GNUNET_TRANSPORT_AddAddressMessage,
11111 NULL),
11112 GNUNET_MQ_hd_fixed_size (del_address,
11113 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
11114 struct GNUNET_TRANSPORT_DelAddressMessage,
11115 NULL),
11116 GNUNET_MQ_hd_var_size (incoming_msg,
11117 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
11118 struct GNUNET_TRANSPORT_IncomingMessage,
11119 NULL),
11120 GNUNET_MQ_hd_fixed_size (queue_create_ok,
11121 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
11122 struct GNUNET_TRANSPORT_CreateQueueResponse,
11123 NULL),
11124 GNUNET_MQ_hd_fixed_size (queue_create_fail,
11125 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
11126 struct GNUNET_TRANSPORT_CreateQueueResponse,
11127 NULL),
11128 GNUNET_MQ_hd_var_size (add_queue_message,
11129 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
11130 struct GNUNET_TRANSPORT_AddQueueMessage,
11131 NULL),
11132 GNUNET_MQ_hd_fixed_size (update_queue_message,
11133 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE,
11134 struct GNUNET_TRANSPORT_UpdateQueueMessage,
11135 NULL),
11136 GNUNET_MQ_hd_fixed_size (del_queue_message,
11137 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
11138 struct GNUNET_TRANSPORT_DelQueueMessage,
11139 NULL),
11140 GNUNET_MQ_hd_fixed_size (send_message_ack,
11141 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
11142 struct GNUNET_TRANSPORT_SendMessageToAck,
11143 NULL),
11144 /* communication with monitors */
11145 GNUNET_MQ_hd_fixed_size (monitor_start,
11146 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
11147 struct GNUNET_TRANSPORT_MonitorStart,
11148 NULL),
11149 GNUNET_MQ_handler_end ());
11150
11151
11152/* end of file gnunet-service-transport.c */