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