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