diff options
| author | tv <tv@krebsco.de> | 2026-11-05 21:14:37 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-05 21:14:37 +0100 |
| commit | e77e54fe6f7aeba6e52e7ba48f763e7137e15c64 (patch) | |
| tree | cdabdf6a5d97a365f9e687dc9959ae9647dd019a /src/transport | |
| parent | 7d7c83616cc434f11a30b3e7f4577a55206cc76d (diff) | |
tor links in order
Diffstat (limited to 'src/transport')
| -rw-r--r-- | src/transport/sim.rs | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/src/transport/sim.rs b/src/transport/sim.rs index 06f15f6..40a1f7d 100644 --- a/src/transport/sim.rs +++ b/src/transport/sim.rs @@ -40,7 +40,7 @@ pub(crate) struct LinkParams { pub(crate) loss: f64, /// Probability that a message arrives twice (each copy with its own delay). pub(crate) duplicate: f64, - /// Delay, uniform in this range. Overlapping delays reorder messages. + /// Delay, uniform in this range. Overlapping delays reorder messages, unless `in_order`. pub(crate) delay: (Duration, Duration), /// Messages of these kinds are always lost: a peer that answers some messages but /// not others (e.g. keepalives but not sync). @@ -49,6 +49,9 @@ pub(crate) struct LinkParams { /// each taking its size at this rate, then the delay (the delay is the latency, as /// half a round trip). None: as fast as any size. pub(crate) rate: Option<u64>, + /// Messages arrive in the order they were sent, as on a stream (Tor's circuits, + /// libp2p's streams): one that would overtake waits for those before it. + pub(crate) in_order: bool, } impl Default for LinkParams { @@ -60,6 +63,7 @@ impl Default for LinkParams { delay: (Duration::from_millis(1), Duration::from_millis(5)), drop: Vec::new(), rate: None, + in_order: false, } } } @@ -88,6 +92,9 @@ struct NetInner { links: HashMap<(String, String), LinkParams>, /// Per link with a rate, when it is free again (`LinkParams::rate`). busy_until: HashMap<(String, String), tokio::time::Instant>, + /// Per link in order, what it carries, each with when it would arrive: one task + /// delivers them one after the other (`LinkParams::in_order`). + in_order: HashMap<(String, String), mpsc::UnboundedSender<(tokio::time::Instant, Delivery)>>, down: HashSet<String>, inboxes: HashMap<String, mpsc::UnboundedSender<Delivery>>, /// Per node, its current run (`restart`): what a transport of an earlier run sends @@ -118,6 +125,7 @@ impl SimNet { default_link: LinkParams::default(), links: HashMap::new(), busy_until: HashMap::new(), + in_order: HashMap::new(), down: HashSet::new(), inboxes: HashMap::new(), runs: HashMap::new(), @@ -244,6 +252,36 @@ impl SimNet { let delays = (0..copies) .map(|_| queued + inner.rng.duration_in(params.delay)) .collect::<Vec<_>>(); + if params.in_order { + let link = (from.to_owned(), message.peer.clone()); + let now = tokio::time::Instant::now(); + let net = self.clone(); + let link_tx = inner.in_order.entry(link.clone()).or_insert_with(|| { + let (tx, mut rx) = + mpsc::unbounded_channel::<(tokio::time::Instant, Delivery)>(); + let to = link.1; + tokio::spawn(async move { + // Each after those before it: a message that would arrive + // earlier waits (`sleep_until` a past instant returns at once). + while let Some((at, delivery)) = rx.recv().await { + tokio::time::sleep_until(at).await; + net.arrive(&to, delivery); + } + }); + tx + }); + for delay in delays { + let delivery = Delivery { + from: from.to_owned(), + body: message.body.clone(), + payload_len: message.payload_len, + handled: None, + }; + // The task runs as long as the runtime: the send doesn't fail. + let _ = link_tx.send((now + delay, delivery)); + } + return wait; + } (delays, wait) }; for delay in delays { |
