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