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