Skip to content

Commit 527189f

Browse files
kstrafeTimonPost
authored andcommitted
Use duration for the link conditioner latency (#205)
* Use duration for the link conditioner latency * Test a really bad connection using the link conditioner This makes the link conditioner public and exposes an interface in the socket.
1 parent 5f3f7fa commit 527189f

File tree

5 files changed

+102
-13
lines changed

5 files changed

+102
-13
lines changed

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ crossbeam-channel = "0.3"
2929
lazy_static = "1.1"
3030
log = "0.4"
3131
mio = "0.6"
32-
rand = "0.5"
32+
rand = "0.6"
33+
rand_pcg = "0.1"
3334
clap = { version = "2.32", features = ["yaml"], optional = true }
3435
env_logger = { version = "0.6", optional = true }
3536

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,5 @@ pub use self::throughput::ThroughputMonitoring;
3939

4040
pub use self::config::Config;
4141
pub use self::error::{ErrorKind, Result};
42-
pub use self::net::{Socket, SocketEvent};
42+
pub use self::net::{LinkConditioner, Socket, SocketEvent};
4343
pub use self::packet::{DeliveryGuarantee, OrderingGuarantee, Packet};

src/net.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod virtual_connection;
1111
pub mod constants;
1212

1313
pub use self::events::SocketEvent;
14+
pub use self::link_conditioner::LinkConditioner;
1415
pub use self::quality::{NetworkQuality, RttMeasurer};
1516
pub use self::socket::Socket;
1617
pub use self::virtual_connection::VirtualConnection;

src/net/link_conditioner.rs

+21-8
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@
33
//! networks. This is not in heavy use yet, hence the allowing dead code. These will be removed as our testing
44
//! becomes more sophisticated.
55
6-
use rand::prelude::random;
6+
use rand::Rng;
7+
use rand_pcg::Pcg64Mcg as Random;
8+
use std::time::Duration;
79

8-
#[derive(Debug)]
10+
/// Network simulator. Used to simulate network conditions as dropped packets and packet delays.
11+
/// For use in [Socket::set_link_conditioner](crate::net::Socket::set_link_conditioner).
12+
#[derive(Clone, Debug)]
913
pub struct LinkConditioner {
1014
// Value between 0 and 1, representing the % change a packet will be dropped on sending
1115
packet_loss: f64,
12-
// Value in milliseconds, representing the delay imposed between packets
13-
latency: u32,
16+
// Duration of the delay imposed between packets
17+
latency: Duration,
18+
// Random number generator
19+
random: Random,
1420
}
1521

1622
impl LinkConditioner {
@@ -19,7 +25,8 @@ impl LinkConditioner {
1925
pub fn new() -> LinkConditioner {
2026
LinkConditioner {
2127
packet_loss: 0.0,
22-
latency: 0,
28+
latency: Duration::default(),
29+
random: Random::new(0),
2330
}
2431
}
2532

@@ -31,12 +38,18 @@ impl LinkConditioner {
3138

3239
/// Sets the latency the link conditioner should apply to each packet
3340
#[allow(dead_code)]
34-
pub fn set_latency(&mut self, latency: u32) {
41+
pub fn set_latency(&mut self, latency: Duration) {
3542
self.latency = latency
3643
}
3744

3845
/// Function that checks to see if a packet should be dropped or not
39-
pub fn should_send(&self) -> bool {
40-
random::<f64>() >= self.packet_loss
46+
pub fn should_send(&mut self) -> bool {
47+
self.random.gen_range(0.0, 1.0) >= self.packet_loss
48+
}
49+
}
50+
51+
impl Default for LinkConditioner {
52+
fn default() -> Self {
53+
Self::new()
4154
}
4255
}

src/net/socket.rs

+77-3
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ impl Socket {
126126
}
127127
}
128128

129+
/// Set the link conditioner for this socket. See [LinkConditioner] for further details.
130+
pub fn set_link_conditioner(&mut self, link_conditioner: Option<LinkConditioner>) {
131+
self.link_conditioner = link_conditioner;
132+
}
133+
129134
/// Iterate through all of the idle connections based on `idle_connection_timeout` config and
130135
/// remove them from the active connections. For each connection removed, we will send a
131136
/// `SocketEvent::TimeOut` event to the `event_sender` channel.
@@ -238,8 +243,8 @@ impl Socket {
238243

239244
// In the presence of a link conditioner, we would like it to determine whether or not we should
240245
// send a packet.
241-
fn should_send_packet(&self) -> bool {
242-
if let Some(link_conditioner) = &self.link_conditioner {
246+
fn should_send_packet(&mut self) -> bool {
247+
if let Some(link_conditioner) = &mut self.link_conditioner {
243248
link_conditioner.should_send()
244249
} else {
245250
true
@@ -277,7 +282,7 @@ impl Socket {
277282
mod tests {
278283
use crate::{
279284
net::constants::{ACKED_PACKET_HEADER, FRAGMENT_HEADER_SIZE, STANDARD_HEADER_SIZE},
280-
Config, Packet, Socket, SocketEvent,
285+
Config, LinkConditioner, Packet, Socket, SocketEvent,
281286
};
282287
use std::collections::HashSet;
283288
use std::net::{SocketAddr, UdpSocket};
@@ -779,4 +784,73 @@ mod tests {
779784
let time = Instant::now();
780785
server.manual_poll(time);
781786
}
787+
788+
#[test]
789+
fn really_bad_network_keeps_chugging_along() {
790+
let server_addr = "127.0.0.1:12320".parse::<SocketAddr>().unwrap();
791+
let client_addr = "127.0.0.1:12321".parse::<SocketAddr>().unwrap();
792+
793+
let (mut server, server_sender, server_receiver) = Socket::bind(server_addr).unwrap();
794+
let (mut client, client_sender, client_receiver) = Socket::bind(client_addr).unwrap();
795+
796+
let time = Instant::now();
797+
798+
// We give both the server and the client a really bad bidirectional link
799+
let link_conditioner = {
800+
let mut lc = LinkConditioner::new();
801+
lc.set_packet_loss(0.9);
802+
Some(lc)
803+
};
804+
805+
client.set_link_conditioner(link_conditioner.clone());
806+
server.set_link_conditioner(link_conditioner);
807+
808+
let mut set = HashSet::new();
809+
810+
// We chat 100 packets between the client and server, which will re-send any non-acked
811+
// packets
812+
let mut send_many_packets = |dummy: Option<u8>| {
813+
for id in 0..100 {
814+
client_sender
815+
.send(Packet::reliable_unordered(
816+
server_addr,
817+
vec![dummy.unwrap_or(id)],
818+
))
819+
.unwrap();
820+
821+
server_sender
822+
.send(Packet::reliable_unordered(client_addr, vec![255]))
823+
.unwrap();
824+
825+
client.manual_poll(time);
826+
server.manual_poll(time);
827+
828+
while let Ok(_) = client_receiver.try_recv() {}
829+
while let Ok(event) = server_receiver.try_recv() {
830+
match event {
831+
SocketEvent::Packet(pkt) => {
832+
set.insert(pkt.payload()[0]);
833+
}
834+
SocketEvent::Timeout(_) => {
835+
panic!["Unable to time out, time has not advanced"]
836+
}
837+
SocketEvent::Connect(_) => {}
838+
}
839+
}
840+
}
841+
842+
return set.len();
843+
};
844+
845+
// The first chatting sequence sends packets 0..100 from the client to the server. After
846+
// this we just chat with a value of 255 so we don't accidentally overlap those chatting
847+
// packets with the packets we want to ack.
848+
assert_eq![42, send_many_packets(None)];
849+
assert_eq![85, send_many_packets(Some(255))];
850+
assert_eq![98, send_many_packets(Some(255))];
851+
assert_eq![100, send_many_packets(Some(255))];
852+
853+
// 101 because we have 0..100 and 255 from the dummies
854+
assert_eq![101, send_many_packets(Some(255))];
855+
}
782856
}

0 commit comments

Comments
 (0)