diff --git a/Cargo.toml b/Cargo.toml
index 5b40400..787a4e5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,7 +10,6 @@ keywords = [ "virtual", "udp", "connection", "message", "queue"]
license="MIT/Apache-2.0"
[dependencies]
-clock_ticks = "0.1.0"
rand = "0.3.14"
clippy = { version = "*", optional = true }
diff --git a/src/server.rs b/src/server.rs
index 5949eee..e9c1023 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -104,7 +104,7 @@ impl Server {
while !self.closed {
let tick_start = tick::start();
- let tick_delay = 1000000000 / self.config.send_rate;
+ let tick_delay = 1000_000_000 / self.config.send_rate;
// Receive all incoming UDP packets to our local address
let mut bytes_received = 0;
@@ -150,7 +150,7 @@ impl Server {
// Then feed the packet into the connection object for
// parsing
connection.receive_packet(
- packet, tick_delay / 1000000, self, handler
+ packet, tick_delay / 1000_000, self, handler
);
}
diff --git a/src/shared/binary_rate_limiter.rs b/src/shared/binary_rate_limiter.rs
index 0613e2b..b133729 100644
--- a/src/shared/binary_rate_limiter.rs
+++ b/src/shared/binary_rate_limiter.rs
@@ -5,9 +5,9 @@
// , at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-extern crate clock_ticks;
use std::cmp;
+use std::time::{Duration, Instant};
use super::super::{Config, RateLimiter};
/// Minimum time before switching back into good mode in milliseconds.
@@ -32,9 +32,9 @@ pub struct BinaryRateLimiter {
max_tick: u32,
mode: Mode,
rtt_threshold: u32,
- last_bad_time: u32,
- last_good_time: u32,
- good_time_duration: u32,
+ last_bad_time: Instant,
+ last_good_time: Instant,
+ good_time_duration: Duration,
delay_until_good_mode: u32
}
@@ -44,6 +44,7 @@ impl BinaryRateLimiter {
pub fn new(config: &Config) -> Box {
let rate = config.send_rate as f32;
+ let now = Instant::now();
Box::new(BinaryRateLimiter {
tick: 0,
@@ -51,9 +52,9 @@ impl BinaryRateLimiter {
max_tick: (rate / (33.0 / (100.0 / rate))) as u32,
mode: Mode::Good,
rtt_threshold: 250,
- last_bad_time: 0,
- last_good_time: precise_time_ms(),
- good_time_duration: 0,
+ last_bad_time: now,
+ last_good_time: now,
+ good_time_duration: Duration::new(0, 0),
delay_until_good_mode: MIN_GOOD_MODE_TIME_DELAY
})
@@ -68,14 +69,15 @@ impl RateLimiter for BinaryRateLimiter {
// Check current network conditions
let conditions = if rtt <= self.rtt_threshold {
// Keep track of the time we are in good mode
- self.good_time_duration += precise_time_ms() - self.last_good_time;
- self.last_good_time = precise_time_ms();
+ let now = Instant::now();
+ self.good_time_duration += now - self.last_good_time;
+ self.last_good_time = now;
Mode::Good
} else {
// Remember the last time we were in bad mode
- self.last_bad_time = precise_time_ms();
- self.good_time_duration = 0;
+ self.last_bad_time = Instant::now();
+ self.good_time_duration = Duration::new(0, 0);
Mode::Bad
};
@@ -91,7 +93,7 @@ impl RateLimiter for BinaryRateLimiter {
// To avoid rapid toggling between good and bad mode, if we
// drop from good mode to bad in under 10 seconds
- if time_since(self.last_bad_time) < 10000 {
+ if self.last_bad_time.elapsed() < Duration::from_millis(10000) {
// We double the amount of time before bad mode goes
// back to good.
@@ -113,8 +115,8 @@ impl RateLimiter for BinaryRateLimiter {
// periods of bad behavior, for each 10 seconds the
// connection is in good mode, we halve the time before bad
// mode goes back to good.
- if self.good_time_duration >= 10000 {
- self.good_time_duration -= 10000;
+ if self.good_time_duration >= Duration::from_millis(10000) {
+ self.good_time_duration -= Duration::from_millis(10000);
// We also clamp this at a minimum
self.delay_until_good_mode = cmp::max(
@@ -132,7 +134,7 @@ impl RateLimiter for BinaryRateLimiter {
// If you are in bad mode, and conditions have been good for a
// specific length of time return to good mode
- if time_since(self.last_bad_time) > self.delay_until_good_mode {
+ if self.last_bad_time.elapsed() > Duration::from_millis(self.delay_until_good_mode as u64) {
self.mode = Mode::Good;
}
@@ -159,21 +161,14 @@ impl RateLimiter for BinaryRateLimiter {
}
fn reset(&mut self) {
+ let now = Instant::now();
self.tick = 0;
self.mode = Mode::Good;
- self.last_bad_time = 0;
- self.last_good_time = precise_time_ms();
- self.good_time_duration = 0;
+ self.last_bad_time = now;
+ self.last_good_time = now;
+ self.good_time_duration = Duration::new(0, 0);
self.delay_until_good_mode = MIN_GOOD_MODE_TIME_DELAY;
}
}
-fn precise_time_ms() -> u32 {
- (clock_ticks::precise_time_ns() / 1000000) as u32
-}
-
-fn time_since(t: u32) -> u32 {
- precise_time_ms() - t
-}
-
diff --git a/src/shared/connection.rs b/src/shared/connection.rs
index 2c94071..8b89047 100644
--- a/src/shared/connection.rs
+++ b/src/shared/connection.rs
@@ -6,12 +6,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate rand;
-extern crate clock_ticks;
use std::cmp;
use std::net::SocketAddr;
use std::collections::HashMap;
use std::collections::VecDeque;
+use std::time::{Duration, Instant};
use super::message_queue::{MessageQueue, MessageIterator};
use super::super::traits::socket::Socket;
use super::super::{Config, MessageKind, Handler, RateLimiter};
@@ -43,7 +43,7 @@ enum PacketState {
#[derive(Debug)]
struct SentPacketAck {
seq: u32,
- time: u32,
+ time: Instant,
state: PacketState,
packet: Option>
}
@@ -124,7 +124,7 @@ pub struct Connection {
smoothed_rtt: f32,
/// Last time a packet was received
- last_receive_time: u32,
+ last_receive_time: Instant,
/// Queue of recently received packets used for ack bitfield construction
recv_ack_queue: VecDeque,
@@ -187,7 +187,7 @@ impl Connection {
local_seq_number: 0,
remote_seq_number: 0,
smoothed_rtt: 0.0,
- last_receive_time: precise_time_ms(),
+ last_receive_time: Instant::now(),
recv_ack_queue: VecDeque::new(),
sent_ack_queue: Vec::new(),
sent_packets: 0,
@@ -333,7 +333,7 @@ impl Connection {
}
// Update time used for disconnect detection
- self.last_receive_time = precise_time_ms();
+ self.last_receive_time = Instant::now();
// Read remote sequence number
self.remote_seq_number = packet[8] as u32;
@@ -353,19 +353,24 @@ impl Connection {
if let Some(lost_packet) = {
let ack = self.sent_ack_queue.get_mut(i).unwrap();
+ let last_receive_since_ack = if self.last_receive_time > ack.time {
+ dur_as_ms(self.last_receive_time - ack.time)
+ } else {
+ 0
+ };
// Calculate the roundtrip time from acknowledged packets
if seq_was_acked(ack.seq, ack_seq_number, bitfield) {
self.acked_packets = self.acked_packets.wrapping_add(1);
self.smoothed_rtt = moving_average(
self.smoothed_rtt,
- (cmp::max(self.last_receive_time - ack.time, tick_delay) - tick_delay) as f32
+ (cmp::max(last_receive_since_ack, tick_delay) - tick_delay) as f32
);
ack.state = PacketState::Acked;
None
// Extract data from lost packets
- } else if self.last_receive_time - ack.time
+ } else if last_receive_since_ack
> self.config.packet_drop_threshold {
self.lost_packets = self.lost_packets.wrapping_add(1);
@@ -546,7 +551,7 @@ impl Connection {
if self.send_ack_required(self.local_seq_number) {
self.sent_ack_queue.push(SentPacketAck {
seq: self.local_seq_number,
- time: precise_time_ms(),
+ time: Instant::now(),
state: PacketState::Unknown,
packet: Some(packet)
});
@@ -576,7 +581,7 @@ impl Connection {
self.local_seq_number = 0;
self.remote_seq_number = 0;
self.smoothed_rtt = 0.0;
- self.last_receive_time = precise_time_ms();
+ self.last_receive_time = Instant::now();
self.recv_ack_queue.clear();
self.sent_ack_queue.clear();
self.sent_packets = 0;
@@ -653,7 +658,7 @@ impl Connection {
) -> bool {
// Calculate time since last received packet
- let inactive_time = precise_time_ms() - self.last_receive_time;
+ let inactive_time = dur_as_ms(self.last_receive_time.elapsed());
match self.state {
@@ -743,7 +748,7 @@ fn seq_was_acked(seq: u32, ack: u32, bitfield: u32) -> bool {
}
}
-fn precise_time_ms() -> u32 {
- (clock_ticks::precise_time_ns() / 1000000) as u32
+fn dur_as_ms(dur: Duration) -> u32 {
+ (dur.as_secs() as u32 * 1000) + (dur.subsec_nanos() / 1000_000)
}
diff --git a/src/tests/mock.rs b/src/tests/mock.rs
index c2e347d..46bdb1a 100644
--- a/src/tests/mock.rs
+++ b/src/tests/mock.rs
@@ -5,13 +5,12 @@
// , at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-extern crate clock_ticks;
use std::cmp;
use std::net;
use std::thread;
use std::io::Error;
-use std::time::Duration;
+use std::time::{Duration, Instant};
use std::net::ToSocketAddrs;
use std::collections::HashMap;
@@ -270,7 +269,7 @@ pub struct MockTickRecorder {
load_ticks: u32,
tick_delay: u32,
tick_count: u32,
- last_tick_time: u32,
+ last_tick_time: Instant,
expected_time: u32,
last_sleep_duration: u32,
accumulated: i32
@@ -284,7 +283,7 @@ impl MockTickRecorder {
load_ticks: load_ticks,
tick_delay: 1000 / send_rate,
tick_count: 0,
- last_tick_time: 0,
+ last_tick_time: Instant::now(),
expected_time: expected_time,
last_sleep_duration: 0,
accumulated: 0
@@ -292,17 +291,19 @@ impl MockTickRecorder {
}
fn init(&mut self) {
- self.last_tick_time = precise_time_ms();
+ self.last_tick_time = Instant::now();
}
fn tick(&mut self) -> bool {
if self.tick_count > 1 {
- let delay = (precise_time_ms() - self.last_tick_time) as i32 - (self.last_sleep_duration as i32 - self.tick_delay as i32 * 2);
+ let elapsed = self.last_tick_time.elapsed();
+ let delay = elapsed.as_secs() as i32 * 1000 + elapsed.subsec_nanos() as i32 / 1000_000 -
+ (self.last_sleep_duration as i32 - self.tick_delay as i32 * 2);
self.accumulated += delay;
}
- self.last_tick_time = precise_time_ms();
+ self.last_tick_time = Instant::now();
self.tick_count += 1;
if self.tick_count == self.max_ticks + 2 {
@@ -315,9 +316,10 @@ impl MockTickRecorder {
// Fake load by waiting sleeping twice the normal tick delay
} else if self.tick_count > 1 && self.tick_count <= self.load_ticks + 1 {
- let before = precise_time_ms();
+ let before = Instant::now();
thread::sleep(Duration::from_millis((self.tick_delay * 2) as u64));
- self.last_sleep_duration = precise_time_ms() - before;
+ let elapsed = before.elapsed();
+ self.last_sleep_duration = elapsed.as_secs() as u32 * 1000 + elapsed.subsec_nanos() / 1000_000;
false
} else {
@@ -566,10 +568,6 @@ fn to_socket_addr(address: T) -> net::SocketAddr {
address.to_socket_addrs().unwrap().nth(0).unwrap()
}
-fn precise_time_ms() -> u32 {
- (clock_ticks::precise_time_ns() / 1000000) as u32
-}
-
pub fn create_connection(config: Option) -> (Connection, MockOwner, MockOwnerHandler) {
let config = config.unwrap_or_else(||Config::default());
let local_address: net::SocketAddr = "127.0.0.1:1234".parse().unwrap();
diff --git a/src/tick.rs b/src/tick.rs
index 8431027..9a98ae0 100644
--- a/src/tick.rs
+++ b/src/tick.rs
@@ -5,27 +5,27 @@
// , at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-extern crate clock_ticks;
-
use std::cmp;
use std::thread;
-use std::time::Duration;
+use std::time::{Duration, Instant};
use super::Config;
-pub fn start() -> u64 {
- clock_ticks::precise_time_ns()
+pub fn start() -> Instant {
+ Instant::now()
}
pub fn end(
tick_delay: u32,
- tick_start: u64,
+ tick_start: Instant,
overflow: &mut u32,
config: &Config
) {
// Actual time taken by the tick
- let time_taken = (clock_ticks::precise_time_ns() - tick_start) as u32;
+ let elapsed = tick_start.elapsed();
+ assert!(elapsed.as_secs() == 0, "tick exceeded 1 second");
+ let time_taken = elapsed.subsec_nanos();
// Required delay reduction to keep tick rate
let mut reduction = cmp::min(time_taken, tick_delay);