Parsing ACK_FREQUENCY frame and TP min_ack_delay
diff --git a/include/quiche.h b/include/quiche.h
index 52b99e5..835d54e 100644
--- a/include/quiche.h
+++ b/include/quiche.h
@@ -171,6 +171,9 @@
// Sets the congestion control algorithm used.
void quiche_config_set_cc_algorithm(quiche_config *config, enum quiche_cc_algorithm algo);
+// Extension: Sets the `min_ack_delay` transport parameter.
+void quiche_config_ext_set_min_ack_delay(quiche_config *config, uint64_t v);
+
// Frees the config object.
void quiche_config_free(quiche_config *config);
diff --git a/src/ffi.rs b/src/ffi.rs
index a5be0d9..afc168c 100644
--- a/src/ffi.rs
+++ b/src/ffi.rs
@@ -232,6 +232,11 @@
}
#[no_mangle]
+pub extern fn quiche_config_ext_set_min_ack_delay(config: &mut Config, v: u64) {
+ config.ext_set_min_ack_delay(v);
+}
+
+#[no_mangle]
pub extern fn quiche_config_free(config: *mut Config) {
unsafe { Box::from_raw(config) };
}
diff --git a/src/frame.rs b/src/frame.rs
index 744fc98..b9f8310 100644
--- a/src/frame.rs
+++ b/src/frame.rs
@@ -138,6 +138,13 @@
},
HandshakeDone,
+
+ AckFrequency {
+ sequence_number: u64,
+ packet_tolerance: u64,
+ update_max_ack_delay: u64,
+ ignore_order: bool,
+ },
}
impl Frame {
@@ -256,6 +263,13 @@
0x1e => Frame::HandshakeDone,
+ 0xaf => Frame::AckFrequency {
+ sequence_number: b.get_varint()?,
+ packet_tolerance: b.get_varint()?,
+ update_max_ack_delay: b.get_varint()?,
+ ignore_order: b.get_u8()? != 0,
+ },
+
_ => return Err(Error::InvalidFrame),
};
@@ -503,6 +517,20 @@
Frame::HandshakeDone => {
b.put_varint(0x1e)?;
},
+
+ Frame::AckFrequency {
+ sequence_number,
+ packet_tolerance,
+ update_max_ack_delay,
+ ignore_order,
+ } => {
+ b.put_varint(0xaf)?;
+
+ b.put_varint(*sequence_number)?;
+ b.put_varint(*packet_tolerance)?;
+ b.put_varint(*update_max_ack_delay)?;
+ b.put_u8(*ignore_order as u8)?;
+ },
}
Ok(before - b.cap())
@@ -676,6 +704,19 @@
Frame::HandshakeDone => {
1 // frame type
},
+
+ Frame::AckFrequency {
+ sequence_number,
+ packet_tolerance,
+ update_max_ack_delay,
+ ..
+ } => {
+ 1 + // frame type
+ octets::varint_len(*sequence_number) + // sequence_number
+ octets::varint_len(*packet_tolerance) + // packet_tolerance
+ octets::varint_len(*update_max_ack_delay) + // update_max_ack_delay
+ 1 // ignore_order
+ },
}
}
@@ -823,6 +864,19 @@
Frame::HandshakeDone => {
write!(f, "HANDSHAKE_DONE")?;
},
+
+ Frame::AckFrequency {
+ sequence_number,
+ packet_tolerance,
+ update_max_ack_delay,
+ ignore_order,
+ } => {
+ write!(
+ f,
+ "ACK_FREQUENCY sequence_number={} packet_tolerenace={} update_max_ack_delay={} ignore_order={}",
+ sequence_number, packet_tolerance, update_max_ack_delay, ignore_order
+ )?;
+ },
}
Ok(())
diff --git a/src/lib.rs b/src/lib.rs
index 7227b97..b29a05f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -660,6 +660,13 @@
self.local_transport_params.max_ack_delay = v;
}
+ /// Sets the `min_ack_delay` transport parameter.
+ ///
+ /// The default value is `25000`.
+ pub fn ext_set_min_ack_delay(&mut self, v: u64) {
+ self.local_transport_params.min_ack_delay = Some(v);
+ }
+
/// Sets the `disable_active_migration` transport parameter.
///
/// The default value is `false`.
@@ -817,6 +824,16 @@
/// Whether to send GREASE.
grease: bool,
+
+ /// ACK Frequency config
+ ack_frequency: AckFrequency,
+}
+
+#[derive(Default)]
+struct AckFrequency {
+ sequence_number: Option<u64>,
+ packet_tolerance: u64,
+ ignore_order: bool,
}
/// Creates a new server-side connection.
@@ -1072,6 +1089,8 @@
closed: false,
grease: config.grease,
+
+ ack_frequency: Default::default(),
});
if let Some(odcid) = odcid {
@@ -1728,7 +1747,9 @@
let mut payload_len = 0;
// Create ACK frame.
- if self.pkt_num_spaces[epoch].ack_elicited && !is_closing {
+ if (self.pkt_num_spaces[epoch].ack_elicited || self.ack_ok(epoch)) &&
+ !is_closing
+ {
let ack_delay =
self.pkt_num_spaces[epoch].largest_rx_pkt_time.elapsed();
@@ -3016,6 +3037,40 @@
// Once the handshake is confirmed, we can drop Handshake keys.
self.drop_epoch_state(packet::EPOCH_HANDSHAKE);
},
+
+ frame::Frame::AckFrequency {
+ sequence_number,
+ packet_tolerance,
+ update_max_ack_delay,
+ ignore_order,
+ } =>
+ if let Some(min_ack_delay) =
+ self.local_transport_params.min_ack_delay
+ {
+ // Check and update sequence_number if valid
+ if let Some(seq) = self.ack_frequency.sequence_number {
+ if seq >= sequence_number {
+ return Err(Error::InvalidFrame);
+ }
+ }
+ self.ack_frequency.sequence_number = Some(sequence_number);
+
+ if packet_tolerance > 0 {
+ self.ack_frequency.packet_tolerance = packet_tolerance;
+ } else {
+ return Err(Error::InvalidFrame);
+ }
+
+ if update_max_ack_delay >= min_ack_delay {
+ self.local_transport_params.max_ack_delay =
+ update_max_ack_delay;
+ }
+
+ self.ack_frequency.ignore_order = ignore_order;
+ } else {
+ // AckFrequency Extension is not supported
+ return Err(Error::InvalidFrame);
+ },
}
Ok(())
@@ -3081,6 +3136,12 @@
let cap = self.max_tx_data as usize - self.tx_data as usize;
cmp::min(cap, self.recovery.cwnd_available())
}
+
+ // Ack strategy for application phase
+ fn ack_ok(&self, epoch: packet::Epoch) -> bool {
+ !self.pkt_num_spaces[epoch].recv_pkt_need_ack.is_empty() &&
+ self.pkt_num_spaces[epoch].next_pkt_num % 4 == 0
+ }
}
/// Statistics about the connection.
@@ -3133,6 +3194,7 @@
pub disable_active_migration: bool,
// pub preferred_address: ...,
pub active_conn_id_limit: u64,
+ pub min_ack_delay: Option<u64>,
}
impl Default for TransportParams {
@@ -3152,6 +3214,7 @@
max_ack_delay: 25,
disable_active_migration: false,
active_conn_id_limit: 0,
+ min_ack_delay: None,
}
}
}
@@ -3272,6 +3335,10 @@
tp.active_conn_id_limit = val.get_varint()?;
},
+ 0xde1a => {
+ tp.min_ack_delay = Some(val.get_varint()?);
+ },
+
// Ignore unknown parameters.
_ => (),
}
@@ -3383,6 +3450,12 @@
b.put_varint(tp.active_conn_id_limit)?;
}
+ if let Some(min_ack_delay) = tp.min_ack_delay {
+ b.put_u16(0xde1a)?;
+ b.put_u16(octets::varint_len(min_ack_delay) as u16)?;
+ b.put_varint(min_ack_delay)?;
+ }
+
b.off()
};
@@ -3431,6 +3504,7 @@
)?;
write!(f, "ack_delay_exponent={} ", self.ack_delay_exponent)?;
write!(f, "max_ack_delay={} ", self.max_ack_delay)?;
+ write!(f, "min_ack_delay={:?} ", self.min_ack_delay)?;
write!(
f,
"disable_active_migration={}",
@@ -3758,12 +3832,13 @@
max_ack_delay: 2_u64.pow(14) - 1,
disable_active_migration: true,
active_conn_id_limit: 8,
+ min_ack_delay: Some(1),
};
let mut raw_params = [42; 256];
let mut raw_params =
TransportParams::encode(&tp, true, &mut raw_params).unwrap();
- assert_eq!(raw_params.len(), 101);
+ assert_eq!(raw_params.len(), 106);
let new_tp = TransportParams::decode(&mut raw_params, false).unwrap();
diff --git a/src/ranges.rs b/src/ranges.rs
index 3d1f718..d81b7ca 100644
--- a/src/ranges.rs
+++ b/src/ranges.rs
@@ -107,6 +107,14 @@
}
}
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
pub fn flatten(&self) -> Flatten {
Flatten {
inner: self.inner.iter(),