mirror of https://github.com/ospab/ostp.git
fix: resolve fatal connection halt caused by unrecoverable dropped untracked Ack/Nack frames. Control frames are now saved in sent_history without auto-retransmission to allow targeted Nack recovery.
This commit is contained in:
parent
9c05f130ac
commit
5c33f08a9b
|
|
@ -745,7 +745,7 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ostp"
|
name = "ostp"
|
||||||
version = "0.1.56"
|
version = "0.1.57"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
|
|
@ -762,7 +762,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ostp-client"
|
name = "ostp-client"
|
||||||
version = "0.1.56"
|
version = "0.1.57"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|
@ -780,7 +780,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ostp-core"
|
name = "ostp-core"
|
||||||
version = "0.1.56"
|
version = "0.1.57"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
|
@ -813,7 +813,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ostp-server"
|
name = "ostp-server"
|
||||||
version = "0.1.56"
|
version = "0.1.57"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|
@ -828,7 +828,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ostp-tun-helper"
|
name = "ostp-tun-helper"
|
||||||
version = "0.1.56"
|
version = "0.1.57"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ struct SentFrame {
|
||||||
bytes: Bytes,
|
bytes: Bytes,
|
||||||
last_sent: Instant,
|
last_sent: Instant,
|
||||||
retries: u8,
|
retries: u8,
|
||||||
|
is_retransmittable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProtocolMachine {
|
impl ProtocolMachine {
|
||||||
|
|
@ -356,7 +357,7 @@ impl ProtocolMachine {
|
||||||
self.build_datagram(stream_id, kind, payload, false)
|
self.build_datagram(stream_id, kind, payload, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_datagram(&mut self, stream_id: u16, kind: FrameKind, payload: Bytes, track: bool) -> Result<Bytes, ProtocolError> {
|
fn build_datagram(&mut self, stream_id: u16, kind: FrameKind, payload: Bytes, is_retransmittable: bool) -> Result<Bytes, ProtocolError> {
|
||||||
let padding = self.padder.build_padding(payload.len());
|
let padding = self.padder.build_padding(payload.len());
|
||||||
let header = FrameHeader {
|
let header = FrameHeader {
|
||||||
version: 1,
|
version: 1,
|
||||||
|
|
@ -395,9 +396,7 @@ impl ProtocolMachine {
|
||||||
|
|
||||||
let final_bytes = Bytes::from(out);
|
let final_bytes = Bytes::from(out);
|
||||||
|
|
||||||
if track {
|
self.push_sent_frame(nonce, final_bytes.clone(), is_retransmittable);
|
||||||
self.push_sent_frame(nonce, final_bytes.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(final_bytes)
|
Ok(final_bytes)
|
||||||
}
|
}
|
||||||
|
|
@ -417,6 +416,10 @@ impl ProtocolMachine {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let base_rto_ms = self.rto.as_millis().max(1) as u64;
|
let base_rto_ms = self.rto.as_millis().max(1) as u64;
|
||||||
for frame in self.sent_history.iter_mut() {
|
for frame in self.sent_history.iter_mut() {
|
||||||
|
if !frame.is_retransmittable {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if frame.retries == self.max_retries {
|
if frame.retries == self.max_retries {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
"Frame {} exceeded max retries ({}); continuing with backoff",
|
"Frame {} exceeded max retries ({}); continuing with backoff",
|
||||||
|
|
@ -518,12 +521,13 @@ impl ProtocolMachine {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_sent_frame(&mut self, nonce: u64, bytes: Bytes) {
|
fn push_sent_frame(&mut self, nonce: u64, bytes: Bytes, is_retransmittable: bool) {
|
||||||
self.sent_history.push_back(SentFrame {
|
self.sent_history.push_back(SentFrame {
|
||||||
nonce,
|
nonce,
|
||||||
bytes,
|
bytes,
|
||||||
last_sent: Instant::now(),
|
last_sent: Instant::now(),
|
||||||
retries: 0,
|
retries: 0,
|
||||||
|
is_retransmittable,
|
||||||
});
|
});
|
||||||
while self.sent_history.len() > self.max_sent_history {
|
while self.sent_history.len() > self.max_sent_history {
|
||||||
self.sent_history.pop_front();
|
self.sent_history.pop_front();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue