Skip to content

Commit

Permalink
Renet: add delay for ack packet
Browse files Browse the repository at this point in the history
  • Loading branch information
lucaspoffo committed Mar 31, 2024
1 parent 957a0ce commit a657e38
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 16 deletions.
23 changes: 20 additions & 3 deletions renet/src/packet.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use bytes::Bytes;
use std::{fmt, ops::Range};
use std::{fmt, ops::Range, time::Duration};

pub type Payload = Vec<u8>;

Expand Down Expand Up @@ -44,6 +44,7 @@ pub enum Packet {
// Acks are saved in multiples ranges, all values in the ranges are considered acked.
Ack {
sequence: u64,
ack_delay: Duration,
ack_ranges: Vec<Range<u64>>,
},
}
Expand Down Expand Up @@ -92,6 +93,10 @@ impl Packet {
}
}

pub fn is_ack_eliciting(&self) -> bool {
matches!(self, Packet::SmallReliable { .. } | Packet::ReliableSlice { .. })
}

pub fn to_bytes(&self, b: &mut octets::OctetsMut) -> Result<usize, SerializationError> {
let before = b.cap();

Expand Down Expand Up @@ -153,9 +158,14 @@ impl Packet {
b.put_varint(slice.payload.len() as u64)?;
b.put_bytes(&slice.payload)?;
}
Packet::Ack { sequence, ack_ranges } => {
Packet::Ack {
sequence,
ack_ranges,
ack_delay,
} => {
b.put_u8(4)?;
b.put_varint(*sequence)?;
b.put_u32(ack_delay.as_micros() as u32)?;

// Consider this ranges:
// [20010..20020 , 20035..20040]
Expand Down Expand Up @@ -305,6 +315,8 @@ impl Packet {
4 => {
// Ack
let sequence = b.get_varint()?;
let packet_delay_microsecs = b.get_u32()?;
let ack_delay = Duration::from_micros(packet_delay_microsecs as u64);

let first_range_end = b.get_varint()?;
let first_range_size = b.get_varint()?;
Expand Down Expand Up @@ -344,7 +356,11 @@ impl Packet {

ack_ranges.reverse();

Ok(Packet::Ack { sequence, ack_ranges })
Ok(Packet::Ack {
sequence,
ack_ranges,
ack_delay,
})
}
_ => Err(SerializationError::InvalidPacketType),
}
Expand Down Expand Up @@ -441,6 +457,7 @@ mod tests {

let packet = Packet::Ack {
sequence: 0,
ack_delay: Duration::ZERO,
ack_ranges: vec![3..7, 10..20, 30..100],
};

Expand Down
48 changes: 35 additions & 13 deletions renet/src/remote_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ pub struct RenetClient {
stats: ConnectionStats,
available_bytes_per_tick: u64,
connection_status: RenetConnectionStatus,
received_ack_eliciting_packet: bool,
start_ack_delay: Option<Duration>,
rtt: f64,
}

Expand Down Expand Up @@ -189,6 +191,8 @@ impl RenetClient {
rtt: 0.0,
available_bytes_per_tick,
connection_status: RenetConnectionStatus::Connecting,
received_ack_eliciting_packet: false,
start_ack_delay: None,
}
}

Expand Down Expand Up @@ -399,6 +403,10 @@ impl RenetClient {

self.add_pending_ack(packet.sequence());

if packet.is_ack_eliciting() {
self.received_ack_eliciting_packet = true;
}

match packet {
Packet::SmallReliable { channel_id, messages, .. } => {
let Some(channel) = self.receive_reliable_channels.get_mut(&channel_id) else {
Expand Down Expand Up @@ -443,7 +451,7 @@ impl RenetClient {
self.disconnect_with_reason(DisconnectReason::ReceiveChannelError { channel_id, error });
}
}
Packet::Ack { ack_ranges, .. } => {
Packet::Ack { ack_ranges, ack_delay, .. } => {
// Create list with just new acks
// This prevents DoS from huge ack ranges
let mut new_acks: Vec<u64> = Vec::new();
Expand All @@ -458,11 +466,14 @@ impl RenetClient {
self.stats.acked_packet(sent_packet.sent_at, self.current_time);

// Update rtt
let rtt = (self.current_time - sent_packet.sent_at).as_secs_f64();
if self.rtt < f64::EPSILON {
self.rtt = rtt;
} else {
self.rtt = self.rtt * 0.875 + rtt * 0.125;
let rtt = self.current_time - sent_packet.sent_at;
if let Some(rtt) = rtt.checked_sub(ack_delay) {
let rtt = rtt.as_secs_f64();
if self.rtt < f64::EPSILON {
self.rtt = rtt;
} else {
self.rtt = self.rtt * 0.875 + rtt * 0.125;
}
}

match sent_packet.info {
Expand Down Expand Up @@ -515,12 +526,23 @@ impl RenetClient {
}

if !self.pending_acks.is_empty() {
let ack_packet = Packet::Ack {
sequence: self.packet_sequence,
ack_ranges: self.pending_acks.clone(),
};
self.packet_sequence += 1;
packets.push(ack_packet);
let ack_delay =
if let Some(start_ack_delay) = self.start_ack_delay { self.current_time - start_ack_delay } else { Duration::ZERO };

const MAX_ACK_DELAY: Duration = Duration::from_millis(200);
if self.received_ack_eliciting_packet || ack_delay >= MAX_ACK_DELAY {
let ack_packet = Packet::Ack {
sequence: self.packet_sequence,
ack_ranges: self.pending_acks.clone(),
ack_delay,
};
self.packet_sequence += 1;
packets.push(ack_packet);
self.start_ack_delay = None;
self.received_ack_eliciting_packet = false;
} else if self.start_ack_delay.is_none() {
self.start_ack_delay = Some(self.current_time);
}
}

let sent_at = self.current_time;
Expand Down Expand Up @@ -577,7 +599,7 @@ impl RenetClient {
},
);
}
Packet::Ack { sequence, ack_ranges } => {
Packet::Ack { sequence, ack_ranges, .. } => {
let last_range = ack_ranges.last().unwrap();
let largest_acked_packet = last_range.end - 1;
self.sent_packets.insert(
Expand Down

0 comments on commit a657e38

Please sign in to comment.