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