moonpool_sim/network/sim/
provider.rs1use super::stream::{SimTcpListener, SimTcpStream};
2use crate::NetworkProvider;
3use crate::buggify;
4use crate::network::ConnectFailureMode;
5use crate::sim::rng::sim_random;
6use crate::{Event, WeakSimWorld};
7use std::io;
8use tracing::instrument;
9
10#[derive(Debug, Clone)]
12pub struct SimNetworkProvider {
13 sim: WeakSimWorld,
14}
15
16impl SimNetworkProvider {
17 #[must_use]
19 pub fn new(sim: WeakSimWorld) -> Self {
20 Self { sim }
21 }
22
23 pub fn sleep(
32 &self,
33 duration: std::time::Duration,
34 ) -> crate::SimulationResult<crate::SleepFuture> {
35 self.sim.sleep(duration)
36 }
37}
38
39impl NetworkProvider for SimNetworkProvider {
40 type TcpStream = SimTcpStream;
41 type TcpListener = SimTcpListener;
42
43 #[instrument(skip(self))]
44 async fn bind(&self, addr: &str) -> io::Result<Self::TcpListener> {
45 let sim = self
46 .sim
47 .upgrade()
48 .map_err(|_| io::Error::other("simulation shutdown"))?;
49
50 let delay =
52 sim.with_network_config(|config| crate::network::sample_latency(&config.bind_latency));
53
54 let listener_id = sim.create_listener();
56
57 sim.schedule_event(
59 Event::Connection {
60 id: listener_id.0,
61 state: crate::ConnectionStateChange::BindComplete,
62 },
63 delay,
64 );
65
66 let listener = SimTcpListener::new(self.sim.clone(), addr.to_string());
67 Ok(listener)
68 }
69
70 #[instrument(skip(self))]
78 async fn connect(&self, addr: &str) -> io::Result<Self::TcpStream> {
79 let sim = self
80 .sim
81 .upgrade()
82 .map_err(|_| io::Error::other("simulation shutdown"))?;
83
84 let (failure_mode, failure_probability) = sim.with_network_config(|config| {
87 (
88 config.chaos.connect_failure_mode,
89 config.chaos.connect_failure_probability,
90 )
91 });
92
93 match failure_mode {
94 ConnectFailureMode::Disabled => {} ConnectFailureMode::AlwaysFail => {
96 if buggify!() {
98 tracing::debug!(addr = %addr, "Connection establishment failed (AlwaysFail mode)");
99 return Err(io::Error::new(
100 io::ErrorKind::ConnectionRefused,
101 "Connection establishment failed (AlwaysFail mode)",
102 ));
103 }
104 }
105 ConnectFailureMode::Probabilistic => {
106 if buggify!() {
108 if sim_random::<f64>() > failure_probability {
109 tracing::debug!(addr = %addr, "Connection establishment failed (Probabilistic mode - error)");
111 return Err(io::Error::new(
112 io::ErrorKind::ConnectionRefused,
113 "Connection establishment failed (Probabilistic mode)",
114 ));
115 }
116 tracing::debug!(addr = %addr, "Connection hanging forever (Probabilistic mode - hang)");
119 std::future::pending::<()>().await;
120 unreachable!("pending() never resolves");
121 }
122 }
123 }
124
125 let delay = sim
127 .with_network_config(|config| crate::network::sample_latency(&config.connect_latency));
128
129 let (client_id, server_id) = sim.create_connection_pair("client-addr", addr);
131
132 let _ = sim.connection_base_latency(client_id);
135 let _ = sim.connection_base_latency(server_id);
136
137 sim.store_pending_connection(addr, server_id);
139
140 sim.schedule_event(
142 Event::Connection {
143 id: client_id.0,
144 state: crate::ConnectionStateChange::ConnectionReady,
145 },
146 delay,
147 );
148
149 let stream = SimTcpStream::new(self.sim.clone(), client_id);
150 Ok(stream)
151 }
152}