cultmesh-rs: a Pong in the capped grace acknowledges nothing; the grace deadline saturates
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 8m57s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 1m41s
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 8m57s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 1m41s
A Ping in the 2 s grace after the capped frame was answered with a Pong built from the session's ack state, which includes the capped frame. Every reply while the session is ending now zeroes its ack fields. The deadline no longer wraps at the end of the clock. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
03141bc93b
commit
b2077fa2bf
2 changed files with 47 additions and 2 deletions
|
|
@ -605,7 +605,18 @@ where
|
|||
};
|
||||
|
||||
let mut unsendable = match result.reply {
|
||||
Some(reply) => self.send_packet(key.remote_addr, &reply)?,
|
||||
Some(mut reply) => {
|
||||
// A reply (a Pong) in the grace after the capped frame acknowledges nothing either.
|
||||
if self
|
||||
.sessions
|
||||
.get(&key)
|
||||
.is_some_and(|entry| entry.ending_deadline_monotonic_millis.is_some())
|
||||
{
|
||||
reply.ack = 0;
|
||||
reply.ack_mask = 0;
|
||||
}
|
||||
self.send_packet(key.remote_addr, &reply)?
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
|
|
@ -710,7 +721,7 @@ where
|
|||
let packets = self.refusal_packets(&mut entry.session, &refusal, true);
|
||||
if !packets.is_empty() {
|
||||
entry.ending_deadline_monotonic_millis =
|
||||
Some(now_monotonic + CAPPED_ANSWER_GRACE_MILLIS);
|
||||
Some(now_monotonic.saturating_add(CAPPED_ANSWER_GRACE_MILLIS));
|
||||
}
|
||||
self.sessions.insert(key, entry);
|
||||
packets
|
||||
|
|
|
|||
|
|
@ -2022,3 +2022,37 @@ fn nothing_behind_the_capped_frame_is_served() -> Result<()> {
|
|||
assert!(sink.0.lock().unwrap().receipts.is_empty(), "the put behind the cap was not stored");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A Ping inside the grace is answered with a Pong that acknowledges nothing: its ack fields are built from
|
||||
/// what the session received, which includes the capped frame.
|
||||
#[test]
|
||||
fn a_pong_in_the_grace_after_the_cap_acknowledges_nothing() -> Result<()> {
|
||||
let mut server = server(Default::default(), Clock::new(84_000), Sink::default(), Source::default())?;
|
||||
let (mut peer, capped) = peer_at_the_cap(&mut server, 84)?;
|
||||
peer.drain();
|
||||
|
||||
let ping = peer.session.create_ping(b"alive".to_vec());
|
||||
peer.send_packet(&ping)?;
|
||||
assert_eq!(server.poll_once()?, CultMeshRudpPollOutcome::Handled);
|
||||
let pong = peer
|
||||
.drain()
|
||||
.into_iter()
|
||||
.find(|packet| packet.packet_type == cultnet_rs::CultNetRudpPacketType::Pong)
|
||||
.expect("the ping is answered");
|
||||
assert_eq!(pong.payload, b"alive");
|
||||
assert!(!acknowledges(&pong, capped), "the Pong acknowledges the capped frame");
|
||||
assert_eq!((pong.ack, pong.ack_mask), (0, 0));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The grace deadline saturates: at the end of the clock the answer is not given up on at once.
|
||||
#[test]
|
||||
fn the_grace_deadline_does_not_wrap_at_the_end_of_the_clock() -> Result<()> {
|
||||
let mut server = server(Default::default(), Clock::new(u64::MAX - 10), Sink::default(), Source::default())?;
|
||||
let (peer, _) = peer_at_the_cap(&mut server, 85)?;
|
||||
peer.drain();
|
||||
server.maintain()?;
|
||||
assert!(!peer.drain().iter().any(is_goodbye), "the deadline wrapped and the session ended before its grace");
|
||||
assert_eq!(server.session_count(), 1);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue