aboutsummaryrefslogtreecommitdiff
path: root/src/transport
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-05-19 13:56:22 +0200
committerChristian Grothoff <christian@grothoff.org>2019-05-19 13:56:22 +0200
commit6e2ca97fb0d3d85c1ef127bc0b9bd3e1e72aa9e8 (patch)
treeab6fccbfa05730f952c519cb3f397afd7af199aa /src/transport
parentbe18b8ecb5232ef5bc718cb8d71c4bcc9f03d2f7 (diff)
downloadgnunet-6e2ca97fb0d3d85c1ef127bc0b9bd3e1e72aa9e8.tar.gz
gnunet-6e2ca97fb0d3d85c1ef127bc0b9bd3e1e72aa9e8.zip
FC work
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/gnunet-service-tng.c809
1 files changed, 547 insertions, 262 deletions
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c
index e00c7d573..f009a491b 100644
--- a/src/transport/gnunet-service-tng.c
+++ b/src/transport/gnunet-service-tng.c
@@ -25,11 +25,27 @@
25 * TODO: 25 * TODO:
26 * Implement next: 26 * Implement next:
27 * - FIXME-FC: realize transport-to-transport flow control (needed in case 27 * - FIXME-FC: realize transport-to-transport flow control (needed in case
28 * communicators do not offer flow control). Note that we may not 28 * communicators do not offer flow control).
29 * want to simply delay the ACKs as that may cause unnecessary 29 * We do transmit FC window sizes now. Left:
30 * re-transmissions. => Introduce proper flow and congestion window(s)! 30 * for SENDING)
31 * - Increment "outbound_fc_window_size_used_kb" on transmission
32 * - Throttle sending if "outbound_fc_window_size_used_kb" reaches limit
33 * - Send *new* challenge when we get close to the limit (including
34 * at the beginning when the limit is zero!)
35 * - Retransmit challenge if it goes unanswered!
36 *
37 * for RECEIVING)
38 * - increment incoming_fc_window_size_ram_kb when receiving
39 * incoming packets!
40 * - OR drop if incoming_fc_window_size_ram goes
41 * (significantly?) beyond available_fc_window_size_kb
42 * - decrement incoming_fc_window_size_ram_kb when CORE is done
43 * with incoming packets!
44 * - increment incoming_fc_window_size_used_kb when CORE is done
45 * with incoming packets!
46 *
31 * - review retransmission logic, right now there is no smartness there! 47 * - review retransmission logic, right now there is no smartness there!
32 * => congestion control, flow control, etc [PERFORMANCE-BASICS] 48 * => congestion control, etc [PERFORMANCE-BASICS]
33 * 49 *
34 * Optimizations: 50 * Optimizations:
35 * - When forwarding DV learn messages, if a peer is reached that 51 * - When forwarding DV learn messages, if a peer is reached that
@@ -59,6 +75,14 @@
59 * AcknowledgementUUIDP altogether, as they won't be acked! [BANDWIDTH] 75 * AcknowledgementUUIDP altogether, as they won't be acked! [BANDWIDTH]
60 * (-> have 2nd type of acknowledgment message; low priority, as we 76 * (-> have 2nd type of acknowledgment message; low priority, as we
61 * do not have an MTU-limited *reliable* communicator) 77 * do not have an MTU-limited *reliable* communicator)
78 * - Adapt available_fc_window_size_kb, using larger values for high-bandwidth
79 * and high-latency links *if* we have the RAM [GOODPUT / utilization / stalls]
80 * - Set last_window_consum_limit_kb promise properly based on
81 * latency and bandwidth of the respective connection [GOODPUT / utilization / stalls]
82 * - re-sending challenge response without a challenge when we have
83 * significantly increased the FC window (upon CORE being done with messages)
84 * so as to avoid the sender having to give us a fresh challenge [BANDWIDTH]
85 * Also can re-use signature in this case [CPU].
62 * 86 *
63 * Design realizations / discussion: 87 * Design realizations / discussion:
64 * - communicators do flow control by calling MQ "notify sent" 88 * - communicators do flow control by calling MQ "notify sent"
@@ -114,6 +138,22 @@
114#define GOODPUT_AGING_SLOTS 4 138#define GOODPUT_AGING_SLOTS 4
115 139
116/** 140/**
141 * How big is the flow control window size by default;
142 * limits per-neighbour RAM utilization (in kilobytes).
143 */
144#define DEFAULT_WINDOW_SIZE_KB 128
145
146/**
147 * For how many incoming connections do we try to create a
148 * virtual link for (at the same time!). This does NOT
149 * limit the number of incoming connections, just the number
150 * for which we are actively trying to find working addresses
151 * in the absence (!) of our own applications wanting the
152 * link to go up.
153 */
154#define MAX_INCOMING_REQUEST 16
155
156/**
117 * Maximum number of peers we select for forwarding DVInit 157 * Maximum number of peers we select for forwarding DVInit
118 * messages at the same time (excluding initiator). 158 * messages at the same time (excluding initiator).
119 */ 159 */
@@ -818,64 +858,8 @@ struct TransportValidationChallengeMessage
818 struct ChallengeNonceP challenge; 858 struct ChallengeNonceP challenge;
819 859
820 /** 860 /**
821 * Timestamp of the sender, to be copied into the reply 861 * Timestamp of the sender, to be copied into the reply to allow
822 * to allow sender to calculate RTT. 862 * sender to calculate RTT. Must be monotonically increasing!
823 */
824 struct GNUNET_TIME_AbsoluteNBO sender_time;
825};
826
827
828/**
829 * Message send to another peer to answer to a validation challenge
830 * and at the same time issue a challenge in the other direction.
831 */
832struct TransportValidationChallengeResponseMessage
833{
834
835 /**
836 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE_RESPONSE
837 */
838 struct GNUNET_MessageHeader header;
839
840 /**
841 * Flow control window size in kilobytes (1024 b), in NBO.
842 * The receiver can now send this many kilobytes as per
843 * the @e received_challenge "account".
844 */
845 uint32_t fc_window_size_kb GNUNET_PACKED;
846
847 /**
848 * Challenge returned to the origin by the receiving peer.
849 */
850 struct ChallengeNonceP received_challenge;
851
852 /**
853 * The peer's signature matching the
854 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
855 */
856 struct GNUNET_CRYPTO_EddsaSignature signature;
857
858 /**
859 * Fresh challenge created by the sender to be returned
860 * by the receiving peer.
861 */
862 struct ChallengeNonceP sender_challenge;
863
864 /**
865 * How long does the sender believe the address on
866 * which the challenge was received to remain valid?
867 */
868 struct GNUNET_TIME_RelativeNBO validity_duration;
869
870 /**
871 * Timestamp of the sender, to be copied into the reply
872 * to allow sender to calculate RTT.
873 */
874 struct GNUNET_TIME_AbsoluteNBO origin_time;
875
876 /**
877 * Timestamp of the sender, to be copied into the reply
878 * to allow sender to calculate RTT.
879 */ 863 */
880 struct GNUNET_TIME_AbsoluteNBO sender_time; 864 struct GNUNET_TIME_AbsoluteNBO sender_time;
881}; 865};
@@ -1224,7 +1208,84 @@ struct VirtualLink
1224 uint64_t message_uuid_ctr; 1208 uint64_t message_uuid_ctr;
1225 1209
1226 /** 1210 /**
1227 * How many more messages can we send to core before we exhaust 1211 * Sender timestamp of @e n_challenge, used to generate out-of-order
1212 * challenges (as sender's timestamps must be monotonically
1213 * increasing). Note that we do not persist this monotonic time
1214 * as we do not really have to worry about ancient flow control
1215 * window sizes after restarts.
1216 */
1217 struct GNUNET_TIME_Absolute n_challenge_time;
1218
1219 /**
1220 * Last challenge we received from @a n, for which we created the
1221 * flow control window given in @e fc_window_size_kb.
1222 */
1223 struct ChallengeNonceP n_challenge;
1224
1225 /**
1226 * Last challenge we used with @a n for flow control. If we receive
1227 * window size increases for a different challenge, they are
1228 * out-of-order and must be discarded!
1229 */
1230 struct ChallengeNonceP my_challenge;
1231
1232 /**
1233 * Memory allocated for this virtual link. Expresses how much RAM
1234 * we are willing to allocate to this virtual link. OPTIMIZE-ME:
1235 * Can be adapted to dedicate more RAM to links that need it, while
1236 * sticking to some overall RAM limit. For now, set to
1237 * #DEFAULT_WINDOW_SIZE_KB.
1238 */
1239 uint32_t available_fc_window_size_kb;
1240
1241 /**
1242 * Memory actually used to buffer packets on this virtual link.
1243 * Expresses how much RAM we are currently using for virtual link.
1244 * Note that once CORE is done with a packet, we decrement the value
1245 * here.
1246 */
1247 uint32_t incoming_fc_window_size_ram_kb;
1248
1249 /**
1250 * Last flow control window size we provided to the other peer, in
1251 * kilobytes (1024 b). We are allowing the other peer to send this
1252 * many kilobytes as per its last @e n_challenge "account".
1253 */
1254 uint32_t incoming_fc_window_size_kb;
1255
1256 /**
1257 * How many bytes could we still get from the previous flow control
1258 * window, in kilobytes (1024 b). We need to consider this value
1259 * when calculating what we allow for the current window due to
1260 * the possibility of out-of-order challenges.
1261 */
1262 uint32_t last_fc_window_size_remaining_kb;
1263
1264 /**
1265 * How much of the window did the other peer successfully use (and
1266 * we already passed it on to CORE)? Must be below @e
1267 * incoming_fc_window_size_kb. We should effectively signal the
1268 * other peer that the window is this much bigger at the next
1269 * opportunity / challenge.
1270 */
1271 uint32_t incoming_fc_window_size_used_kb;
1272
1273 /**
1274 * Our current flow control window size in kilobytes (1024 b). We
1275 * are allowed to transmit this many kilobytes to @a n as per
1276 * our @e my_challenge "account".
1277 */
1278 uint32_t outbound_fc_window_size_kb;
1279
1280 /**
1281 * How much of our current flow control window size have we
1282 * used (in kilobytes (1024 b)). Must be below
1283 * @e outbound_fc_window_size_kb.
1284 */
1285 uint32_t outbound_fc_window_size_used_kb;
1286
1287 /**
1288 * How many more messages can we send to CORE before we exhaust
1228 * the receive window of CORE for this peer? If this hits zero, 1289 * the receive window of CORE for this peer? If this hits zero,
1229 * we must tell communicators to stop providing us more messages 1290 * we must tell communicators to stop providing us more messages
1230 * for this peer. In fact, the window can go negative as we 1291 * for this peer. In fact, the window can go negative as we
@@ -1787,6 +1848,35 @@ struct Neighbour
1787 1848
1788 1849
1789/** 1850/**
1851 * Another peer attempted to talk to us, we should try to establish
1852 * a connection in the other direction.
1853 */
1854struct IncomingRequest
1855{
1856
1857 /**
1858 * Kept in a DLL.
1859 */
1860 struct IncomingRequest *next;
1861
1862 /**
1863 * Kept in a DLL.
1864 */
1865 struct IncomingRequest *prev;
1866
1867 /**
1868 * Handle for watching the peerstore for HELLOs for this peer.
1869 */
1870 struct GNUNET_PEERSTORE_WatchContext *wc;
1871
1872 /**
1873 * Which peer is this about?
1874 */
1875 struct GNUNET_PeerIdentity pid;
1876};
1877
1878
1879/**
1790 * A peer that an application (client) would like us to talk to directly. 1880 * A peer that an application (client) would like us to talk to directly.
1791 */ 1881 */
1792struct PeerRequest 1882struct PeerRequest
@@ -2357,6 +2447,13 @@ struct ValidationState
2357 struct GNUNET_PEERSTORE_StoreContext *sc; 2447 struct GNUNET_PEERSTORE_StoreContext *sc;
2358 2448
2359 /** 2449 /**
2450 * Self-imposed limit on the previous flow control window. (May be zero,
2451 * if we never used data from the previous window or are establishing the
2452 * connection for the first time).
2453 */
2454 uint32_t last_window_consum_limit_kb;
2455
2456 /**
2360 * We are technically ready to send the challenge, but we are waiting for 2457 * We are technically ready to send the challenge, but we are waiting for
2361 * the respective queue to become available for transmission. 2458 * the respective queue to become available for transmission.
2362 */ 2459 */
@@ -2545,6 +2642,23 @@ static struct PendingAcknowledgement *pa_head;
2545static struct PendingAcknowledgement *pa_tail; 2642static struct PendingAcknowledgement *pa_tail;
2546 2643
2547/** 2644/**
2645 * List of incomming connections where we are trying
2646 * to get a connection back established. Length
2647 * kept in #ir_total.
2648 */
2649static struct IncomingRequest *ir_head;
2650
2651/**
2652 * Tail of DLL starting at #ir_head.
2653 */
2654static struct IncomingRequest *ir_tail;
2655
2656/**
2657 * Length of the DLL starting at #ir_head.
2658 */
2659static unsigned int ir_total;
2660
2661/**
2548 * Generator of `logging_uuid` in `struct PendingMessage`. 2662 * Generator of `logging_uuid` in `struct PendingMessage`.
2549 */ 2663 */
2550static unsigned long long logging_uuid_gen; 2664static unsigned long long logging_uuid_gen;
@@ -2587,6 +2701,22 @@ get_age ()
2587 2701
2588 2702
2589/** 2703/**
2704 * Release @a ir data structure.
2705 *
2706 * @param ir data structure to release
2707 */
2708static void
2709free_incoming_request (struct IncomingRequest *ir)
2710{
2711 GNUNET_CONTAINER_DLL_remove (ir_head, ir_tail, ir);
2712 GNUNET_assert (ir_total > 0);
2713 ir_total--;
2714 GNUNET_PEERSTORE_watch_cancel (ir->wc);
2715 GNUNET_free (ir);
2716}
2717
2718
2719/**
2590 * Release @a pa data structure. 2720 * Release @a pa data structure.
2591 * 2721 *
2592 * @param pa data structure to release 2722 * @param pa data structure to release
@@ -5688,6 +5818,7 @@ activate_core_visible_dv_path (struct DistanceVectorHop *hop)
5688 vl->dv = dv; 5818 vl->dv = dv;
5689 dv->vl = vl; 5819 dv->vl = vl;
5690 vl->core_recv_window = RECV_WINDOW_SIZE; 5820 vl->core_recv_window = RECV_WINDOW_SIZE;
5821 vl->available_fc_window_size_kb = DEFAULT_WINDOW_SIZE_KB;
5691 vl->visibility_task = 5822 vl->visibility_task =
5692 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl); 5823 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
5693 GNUNET_break (GNUNET_YES == 5824 GNUNET_break (GNUNET_YES ==
@@ -7052,6 +7183,270 @@ check_incoming_msg (void *cls,
7052 7183
7053 7184
7054/** 7185/**
7186 * We received a @a challenge from another peer, check if we can
7187 * increase the flow control window to that peer.
7188 *
7189 * @param vl virtual link
7190 * @param challenge the challenge we received
7191 * @param sender_time when did the peer send the message?
7192 * @param last_window_consum_limit_kb maximum number of kb the sender
7193 * promises to use of the previous window (if any)
7194 */
7195static void
7196update_fc_window (struct VirtualLink *vl,
7197 const struct ChallengeNonceP *challenge,
7198 struct GNUNET_TIME_Absolute sender_time,
7199 uint32_t last_window_consum_limit_kb)
7200{
7201 if (0 == GNUNET_memcmp (challenge, &vl->n_challenge))
7202 {
7203 uint32_t avail;
7204
7205 /* Challenge identical to last one, update
7206 @a last_window_consum_limit_kb (to minimum) */
7207 vl->last_fc_window_size_remaining_kb =
7208 GNUNET_MIN (last_window_consum_limit_kb,
7209 vl->last_fc_window_size_remaining_kb);
7210 /* window could have shrunk! */
7211 if (vl->available_fc_window_size_kb > vl->last_fc_window_size_remaining_kb)
7212 avail =
7213 vl->available_fc_window_size_kb - vl->last_fc_window_size_remaining_kb;
7214 else
7215 avail = 0;
7216 /* guard against integer overflow */
7217 if (vl->incoming_fc_window_size_used_kb + avail >=
7218 vl->incoming_fc_window_size_used_kb)
7219 vl->incoming_fc_window_size_kb =
7220 vl->incoming_fc_window_size_used_kb + avail;
7221 else
7222 vl->incoming_fc_window_size_kb = UINT32_MAX;
7223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7224 "Updated window to %u/%u kb (%u used) for virtual link to %s!\n",
7225 vl->incoming_fc_window_size_kb,
7226 vl->available_fc_window_size_kb,
7227 vl->incoming_fc_window_size_used_kb,
7228 GNUNET_i2s (&vl->target));
7229 return;
7230 }
7231 if (vl->n_challenge_time.abs_value_us >= sender_time.abs_value_us)
7232 {
7233 GNUNET_STATISTICS_update (GST_stats,
7234 "# Challenges ignored: sender time not increasing",
7235 1,
7236 GNUNET_NO);
7237 return;
7238 }
7239 /* new challenge! */
7240 if (vl->incoming_fc_window_size_used_kb > last_window_consum_limit_kb)
7241 {
7242 /* lying peer: it already used more than it promised it would ever use! */
7243 GNUNET_break_op (0);
7244 last_window_consum_limit_kb = vl->incoming_fc_window_size_used_kb;
7245 }
7246 /* What remains is at most the difference between what we already processed
7247 and what the sender promises to limit itself to. */
7248 vl->last_fc_window_size_remaining_kb =
7249 last_window_consum_limit_kb - vl->incoming_fc_window_size_used_kb;
7250 vl->n_challenge = *challenge;
7251 vl->n_challenge_time = sender_time;
7252 vl->incoming_fc_window_size_used_kb = 0;
7253 /* window could have shrunk! */
7254 if (vl->available_fc_window_size_kb > vl->last_fc_window_size_remaining_kb)
7255 vl->incoming_fc_window_size_kb =
7256 vl->available_fc_window_size_kb - vl->last_fc_window_size_remaining_kb;
7257 else
7258 vl->incoming_fc_window_size_kb = 0;
7259 GNUNET_log (
7260 GNUNET_ERROR_TYPE_DEBUG,
7261 "New window at %u/%u kb (%u left on previous) for virtual link to %s!\n",
7262 vl->incoming_fc_window_size_kb,
7263 vl->available_fc_window_size_kb,
7264 vl->last_fc_window_size_remaining_kb,
7265 GNUNET_i2s (&vl->target));
7266}
7267
7268
7269/**
7270 * Closure for #check_known_address.
7271 */
7272struct CheckKnownAddressContext
7273{
7274 /**
7275 * Set to the address we are looking for.
7276 */
7277 const char *address;
7278
7279 /**
7280 * Set to a matching validation state, if one was found.
7281 */
7282 struct ValidationState *vs;
7283};
7284
7285
7286/**
7287 * Test if the validation state in @a value matches the
7288 * address from @a cls.
7289 *
7290 * @param cls a `struct CheckKnownAddressContext`
7291 * @param pid unused (must match though)
7292 * @param value a `struct ValidationState`
7293 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7294 */
7295static int
7296check_known_address (void *cls,
7297 const struct GNUNET_PeerIdentity *pid,
7298 void *value)
7299{
7300 struct CheckKnownAddressContext *ckac = cls;
7301 struct ValidationState *vs = value;
7302
7303 (void) pid;
7304 if (0 != strcmp (vs->address, ckac->address))
7305 return GNUNET_OK;
7306 ckac->vs = vs;
7307 return GNUNET_NO;
7308}
7309
7310
7311/**
7312 * Task run periodically to validate some address based on #validation_heap.
7313 *
7314 * @param cls NULL
7315 */
7316static void
7317validation_start_cb (void *cls);
7318
7319
7320/**
7321 * Set the time for next_challenge of @a vs to @a new_time.
7322 * Updates the heap and if necessary reschedules the job.
7323 *
7324 * @param vs validation state to update
7325 * @param new_time new time for revalidation
7326 */
7327static void
7328update_next_challenge_time (struct ValidationState *vs,
7329 struct GNUNET_TIME_Absolute new_time)
7330{
7331 struct GNUNET_TIME_Relative delta;
7332
7333 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
7334 return; /* be lazy */
7335 vs->next_challenge = new_time;
7336 if (NULL == vs->hn)
7337 vs->hn =
7338 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
7339 else
7340 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
7341 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
7342 (NULL != validation_task))
7343 return;
7344 if (NULL != validation_task)
7345 GNUNET_SCHEDULER_cancel (validation_task);
7346 /* randomize a bit */
7347 delta.rel_value_us =
7348 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
7349 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
7350 new_time = GNUNET_TIME_absolute_add (new_time, delta);
7351 validation_task =
7352 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
7353}
7354
7355
7356/**
7357 * Start address validation.
7358 *
7359 * @param pid peer the @a address is for
7360 * @param address an address to reach @a pid (presumably)
7361 */
7362static void
7363start_address_validation (const struct GNUNET_PeerIdentity *pid,
7364 const char *address)
7365{
7366 struct GNUNET_TIME_Absolute now;
7367 struct ValidationState *vs;
7368 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
7369
7370 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7371 pid,
7372 &check_known_address,
7373 &ckac);
7374 if (NULL != (vs = ckac.vs))
7375 {
7376 /* if 'vs' is not currently valid, we need to speed up retrying the
7377 * validation */
7378 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7379 {
7380 /* reduce backoff as we got a fresh advertisement */
7381 vs->challenge_backoff =
7382 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7383 GNUNET_TIME_relative_divide (vs->challenge_backoff,
7384 2));
7385 update_next_challenge_time (vs,
7386 GNUNET_TIME_relative_to_absolute (
7387 vs->challenge_backoff));
7388 }
7389 return;
7390 }
7391 now = GNUNET_TIME_absolute_get ();
7392 vs = GNUNET_new (struct ValidationState);
7393 vs->pid = *pid;
7394 vs->valid_until =
7395 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
7396 vs->first_challenge_use = now;
7397 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7398 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7399 &vs->challenge,
7400 sizeof (vs->challenge));
7401 vs->address = GNUNET_strdup (address);
7402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7403 "Starting address validation `%s' of peer %s using challenge %s\n",
7404 address,
7405 GNUNET_i2s (pid),
7406 GNUNET_sh2s (&vs->challenge.value));
7407 GNUNET_assert (GNUNET_YES ==
7408 GNUNET_CONTAINER_multipeermap_put (
7409 validation_map,
7410 &vs->pid,
7411 vs,
7412 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7413 update_next_challenge_time (vs, now);
7414}
7415
7416
7417/**
7418 * Function called by PEERSTORE for each matching record.
7419 *
7420 * @param cls closure, a `struct IncomingRequest`
7421 * @param record peerstore record information
7422 * @param emsg error message, or NULL if no errors
7423 */
7424static void
7425handle_hello_for_incoming (void *cls,
7426 const struct GNUNET_PEERSTORE_Record *record,
7427 const char *emsg)
7428{
7429 struct IncomingRequest *ir = cls;
7430 const char *val;
7431
7432 if (NULL != emsg)
7433 {
7434 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7435 "Got failure from PEERSTORE: %s\n",
7436 emsg);
7437 return;
7438 }
7439 val = record->value;
7440 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7441 {
7442 GNUNET_break (0);
7443 return;
7444 }
7445 start_address_validation (&ir->pid, (const char *) record->value);
7446}
7447
7448
7449/**
7055 * Communicator gave us a transport address validation challenge. Process the 7450 * Communicator gave us a transport address validation challenge. Process the
7056 * request. 7451 * request.
7057 * 7452 *
@@ -7065,62 +7460,86 @@ handle_validation_challenge (
7065 const struct TransportValidationChallengeMessage *tvc) 7460 const struct TransportValidationChallengeMessage *tvc)
7066{ 7461{
7067 struct CommunicatorMessageContext *cmc = cls; 7462 struct CommunicatorMessageContext *cmc = cls;
7068 struct TransportValidationResponseMessage *tvr; 7463 struct TransportValidationResponseMessage tvr;
7464 struct VirtualLink *vl;
7465 struct GNUNET_TIME_RelativeNBO validity_duration;
7466 struct IncomingRequest *ir;
7467 struct Neighbour *n;
7069 7468
7469 /* We use a validity_duration of 0 for DV-routed messages,
7470 as we can neither control the validity and need to allow
7471 the receiver to tell DV paths from direct connections */
7070 if (cmc->total_hops > 0) 7472 if (cmc->total_hops > 0)
7071 { 7473 validity_duration = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
7072 /* DV routing is not allowed for validation challenges! */ 7474 else
7073 GNUNET_break_op (0); 7475 validity_duration = cmc->im.expected_address_validity;
7074 finish_cmc_handling (cmc);
7075 return;
7076 }
7077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 7476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7078 "Received address validation challenge %s\n", 7477 "Received address validation challenge %s\n",
7079 GNUNET_sh2s (&tvc->challenge.value)); 7478 GNUNET_sh2s (&tvc->challenge.value));
7080 tvr = GNUNET_new (struct TransportValidationResponseMessage); 7479 /* If we have a virtual link, we use this mechanism to signal the
7081 tvr->header.type = 7480 size of the flow control window, and to allow the sender
7481 to ask for increases. If for us the virtual link is still down,
7482 we will always give a window size of zero. */
7483 vl = lookup_virtual_link (&cmc->im.sender);
7484 if (NULL != vl)
7485 update_fc_window (vl,
7486 &tvc->challenge,
7487 GNUNET_TIME_absolute_ntoh (tvc->sender_time),
7488 ntohl (tvc->last_window_consum_limit_kb));
7489 tvr.header.type =
7082 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE); 7490 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
7083 tvr->header.size = htons (sizeof (*tvr)); 7491 tvr.header.size = htons (sizeof (tvr));
7084 tvr->challenge = tvc->challenge; 7492 tvr.fc_window_size_kb =
7085 tvr->origin_time = tvc->sender_time; 7493 htonl ((NULL == vl) ? 0 : vl->incoming_fc_window_size_kb);
7086 tvr->validity_duration = cmc->im.expected_address_validity; 7494 tvr.challenge = tvc->challenge;
7495 tvr.origin_time = tvc->sender_time;
7496 tvr.validity_duration = validity_duration;
7087 { 7497 {
7088 /* create signature */ 7498 /* create signature */
7089 struct TransportValidationPS tvp = 7499 struct TransportValidationPS tvp =
7090 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE), 7500 {.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7091 .purpose.size = htonl (sizeof (tvp)), 7501 .purpose.size = htonl (sizeof (tvp)),
7092 .validity_duration = tvr->validity_duration, 7502 .validity_duration = validity_duration,
7093 .challenge = tvc->challenge}; 7503 .challenge = tvc->challenge};
7094 7504
7095 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key, 7505 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7096 &tvp.purpose, 7506 &tvp.purpose,
7097 &tvr->signature)); 7507 &tvr.signature));
7098 } 7508 }
7099 route_message (&cmc->im.sender, 7509 route_message (&cmc->im.sender,
7100 &tvr->header, 7510 &tvr.header,
7101 RMO_ANYTHING_GOES | RMO_REDUNDANT); 7511 RMO_ANYTHING_GOES | RMO_REDUNDANT);
7102 finish_cmc_handling (cmc); 7512 finish_cmc_handling (cmc);
7103} 7513 if (NULL != vl)
7104 7514 return;
7105
7106/**
7107 * Communicator gave us a transport address validation challenge. Process the
7108 * request.
7109 *
7110 * @param cls a `struct CommunicatorMessageContext` (must call
7111 * #finish_cmc_handling() when done)
7112 * @param tvrc the message that was received
7113 */
7114static void
7115handle_validation_challenge_response (
7116 void *cls,
7117 const struct TransportValidationChallengeResponseMessage *tvrc)
7118{
7119 struct CommunicatorMessageContext *cmc = cls;
7120 struct TransportValidationResponseMessage *tvr;
7121 7515
7516 /* For us, the link is still down, but we need bi-directional
7517 connections (for flow-control and for this to be useful for
7518 CORE), so we must try to bring the link up! */
7122 7519
7123 finish_cmc_handling (cmc); 7520 /* (1) Check existing queues, if any, we may be lucky! */
7521 n = lookup_neighbour (&cmc->im.sender);
7522 if (NULL != n)
7523 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7524 start_address_validation (&cmc->im.sender, q->address);
7525 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
7526 we could use */
7527 for (ir = ir_head; NULL != ir; ir = ir->next)
7528 if (0 == GNUNET_memcmp (&ir->pid, &cmc->im.sender))
7529 return; /* we are already trying */
7530 ir = GNUNET_new (struct IncomingRequest);
7531 ir->pid = cmc->im.sender;
7532 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
7533 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
7534 "transport",
7535 &ir->pid,
7536 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7537 &handle_hello_for_incoming,
7538 ir);
7539 ir_total++;
7540 /* Bound attempts we do in parallel here, might otherwise get excessive */
7541 while (ir_total > MAX_INCOMING_REQUEST)
7542 free_incoming_request (ir_head);
7124} 7543}
7125 7544
7126 7545
@@ -7189,51 +7608,6 @@ peerstore_store_validation_cb (void *cls, int success)
7189 7608
7190 7609
7191/** 7610/**
7192 * Task run periodically to validate some address based on #validation_heap.
7193 *
7194 * @param cls NULL
7195 */
7196static void
7197validation_start_cb (void *cls);
7198
7199
7200/**
7201 * Set the time for next_challenge of @a vs to @a new_time.
7202 * Updates the heap and if necessary reschedules the job.
7203 *
7204 * @param vs validation state to update
7205 * @param new_time new time for revalidation
7206 */
7207static void
7208update_next_challenge_time (struct ValidationState *vs,
7209 struct GNUNET_TIME_Absolute new_time)
7210{
7211 struct GNUNET_TIME_Relative delta;
7212
7213 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
7214 return; /* be lazy */
7215 vs->next_challenge = new_time;
7216 if (NULL == vs->hn)
7217 vs->hn =
7218 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
7219 else
7220 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
7221 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
7222 (NULL != validation_task))
7223 return;
7224 if (NULL != validation_task)
7225 GNUNET_SCHEDULER_cancel (validation_task);
7226 /* randomize a bit */
7227 delta.rel_value_us =
7228 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
7229 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
7230 new_time = GNUNET_TIME_absolute_add (new_time, delta);
7231 validation_task =
7232 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
7233}
7234
7235
7236/**
7237 * Find the queue matching @a pid and @a address. 7611 * Find the queue matching @a pid and @a address.
7238 * 7612 *
7239 * @param pid peer the queue must go to 7613 * @param pid peer the queue must go to
@@ -7387,10 +7761,23 @@ handle_validation_response (
7387 if (NULL != vl) 7761 if (NULL != vl)
7388 { 7762 {
7389 /* Link was already up, remember n is also now available and we are done */ 7763 /* Link was already up, remember n is also now available and we are done */
7390 vl->n = n; 7764 if (NULL == vl->n)
7391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 7765 {
7392 "Virtual link to %s could now also direct neighbour!\n", 7766 vl->n = n;
7393 GNUNET_i2s (&vs->pid)); 7767 n->vl = vl;
7768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7769 "Virtual link to %s could now also direct neighbour!\n",
7770 GNUNET_i2s (&vs->pid));
7771 }
7772 else
7773 {
7774 GNUNET_assert (n == vl->n);
7775 }
7776 if (0 == GNUNET_memcmp (&vl->my_challenge, &tvr->challenge))
7777 {
7778 /* Update window size if the challenge matches */
7779 vl->outbound_fc_window_size_kb = ntohl (tvr->fc_window_size_kb);
7780 }
7394 return; 7781 return;
7395 } 7782 }
7396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 7783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -7401,6 +7788,9 @@ handle_validation_response (
7401 vl->n = n; 7788 vl->n = n;
7402 n->vl = vl; 7789 n->vl = vl;
7403 vl->core_recv_window = RECV_WINDOW_SIZE; 7790 vl->core_recv_window = RECV_WINDOW_SIZE;
7791 vl->available_fc_window_size_kb = DEFAULT_WINDOW_SIZE_KB;
7792 vl->outbound_fc_window_size_kb = ntohl (tvr->fc_window_size_kb);
7793 vl->my_challenge = tvr->challenge;
7404 vl->visibility_task = 7794 vl->visibility_task =
7405 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl); 7795 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
7406 GNUNET_break (GNUNET_YES == 7796 GNUNET_break (GNUNET_YES ==
@@ -7479,11 +7869,6 @@ demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
7479 struct TransportValidationChallengeMessage, 7869 struct TransportValidationChallengeMessage,
7480 &cmc), 7870 &cmc),
7481 GNUNET_MQ_hd_fixed_size ( 7871 GNUNET_MQ_hd_fixed_size (
7482 validation_challenge_response,
7483 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE_RESPONSE,
7484 struct TransportValidationChallengeResponseMessage,
7485 &cmc),
7486 GNUNET_MQ_hd_fixed_size (
7487 validation_response, 7872 validation_response,
7488 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE, 7873 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
7489 struct TransportValidationResponseMessage, 7874 struct TransportValidationResponseMessage,
@@ -8398,11 +8783,11 @@ validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
8398{ 8783{
8399 struct TransportValidationChallengeMessage tvc; 8784 struct TransportValidationChallengeMessage tvc;
8400 8785
8401 vs->last_challenge_use = GNUNET_TIME_absolute_get (); 8786 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
8402 tvc.header.type = 8787 tvc.header.type =
8403 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE); 8788 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
8404 tvc.header.size = htons (sizeof (tvc)); 8789 tvc.header.size = htons (sizeof (tvc));
8405 tvc.last_window_consum_limit_kb = htonl (0); // FIXME! 8790 tvc.last_window_consum_limit_kb = htonl (vs->last_window_consum_limit_kb);
8406 tvc.challenge = vs->challenge; 8791 tvc.challenge = vs->challenge;
8407 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use); 8792 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
8408 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 8793 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -8893,119 +9278,16 @@ handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
8893 9278
8894 9279
8895/** 9280/**
8896 * Closure for #check_known_address.
8897 */
8898struct CheckKnownAddressContext
8899{
8900 /**
8901 * Set to the address we are looking for.
8902 */
8903 const char *address;
8904
8905 /**
8906 * Set to a matching validation state, if one was found.
8907 */
8908 struct ValidationState *vs;
8909};
8910
8911
8912/**
8913 * Test if the validation state in @a value matches the
8914 * address from @a cls.
8915 *
8916 * @param cls a `struct CheckKnownAddressContext`
8917 * @param pid unused (must match though)
8918 * @param value a `struct ValidationState`
8919 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8920 */
8921static int
8922check_known_address (void *cls,
8923 const struct GNUNET_PeerIdentity *pid,
8924 void *value)
8925{
8926 struct CheckKnownAddressContext *ckac = cls;
8927 struct ValidationState *vs = value;
8928
8929 (void) pid;
8930 if (0 != strcmp (vs->address, ckac->address))
8931 return GNUNET_OK;
8932 ckac->vs = vs;
8933 return GNUNET_NO;
8934}
8935
8936
8937/**
8938 * Start address validation.
8939 *
8940 * @param pid peer the @a address is for
8941 * @param address an address to reach @a pid (presumably)
8942 */
8943static void
8944start_address_validation (const struct GNUNET_PeerIdentity *pid,
8945 const char *address)
8946{
8947 struct GNUNET_TIME_Absolute now;
8948 struct ValidationState *vs;
8949 struct CheckKnownAddressContext ckac = {.address = address, .vs = NULL};
8950
8951 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8952 pid,
8953 &check_known_address,
8954 &ckac);
8955 if (NULL != (vs = ckac.vs))
8956 {
8957 /* if 'vs' is not currently valid, we need to speed up retrying the
8958 * validation */
8959 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8960 {
8961 /* reduce backoff as we got a fresh advertisement */
8962 vs->challenge_backoff =
8963 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8964 GNUNET_TIME_relative_divide (vs->challenge_backoff,
8965 2));
8966 update_next_challenge_time (vs,
8967 GNUNET_TIME_relative_to_absolute (
8968 vs->challenge_backoff));
8969 }
8970 return;
8971 }
8972 now = GNUNET_TIME_absolute_get ();
8973 vs = GNUNET_new (struct ValidationState);
8974 vs->pid = *pid;
8975 vs->valid_until =
8976 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
8977 vs->first_challenge_use = now;
8978 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8979 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8980 &vs->challenge,
8981 sizeof (vs->challenge));
8982 vs->address = GNUNET_strdup (address);
8983 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8984 "Starting address validation `%s' of peer %s using challenge %s\n",
8985 address,
8986 GNUNET_i2s (pid),
8987 GNUNET_sh2s (&vs->challenge.value));
8988 GNUNET_assert (GNUNET_YES ==
8989 GNUNET_CONTAINER_multipeermap_put (
8990 validation_map,
8991 &vs->pid,
8992 vs,
8993 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8994 update_next_challenge_time (vs, now);
8995}
8996
8997
8998/**
8999 * Function called by PEERSTORE for each matching record. 9281 * Function called by PEERSTORE for each matching record.
9000 * 9282 *
9001 * @param cls closure 9283 * @param cls closure, a `struct PeerRequest`
9002 * @param record peerstore record information 9284 * @param record peerstore record information
9003 * @param emsg error message, or NULL if no errors 9285 * @param emsg error message, or NULL if no errors
9004 */ 9286 */
9005static void 9287static void
9006handle_hello (void *cls, 9288handle_hello_for_client (void *cls,
9007 const struct GNUNET_PEERSTORE_Record *record, 9289 const struct GNUNET_PEERSTORE_Record *record,
9008 const char *emsg) 9290 const char *emsg)
9009{ 9291{
9010 struct PeerRequest *pr = cls; 9292 struct PeerRequest *pr = cls;
9011 const char *val; 9293 const char *val;
@@ -9077,7 +9359,7 @@ handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
9077 "transport", 9359 "transport",
9078 &pr->pid, 9360 &pr->pid,
9079 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY, 9361 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
9080 &handle_hello, 9362 &handle_hello_for_client,
9081 pr); 9363 pr);
9082 GNUNET_SERVICE_client_continue (tc->client); 9364 GNUNET_SERVICE_client_continue (tc->client);
9083} 9365}
@@ -9286,6 +9568,9 @@ do_shutdown (void *cls)
9286 NULL); 9568 NULL);
9287 GNUNET_CONTAINER_multipeermap_destroy (validation_map); 9569 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
9288 validation_map = NULL; 9570 validation_map = NULL;
9571 while (NULL != ir_head)
9572 free_incoming_request (ir_head);
9573 GNUNET_assert (0 == ir_total);
9289 while (NULL != (lle = lle_head)) 9574 while (NULL != (lle = lle_head))
9290 { 9575 {
9291 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle); 9576 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);