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