fix(client): align DSCP wire semantics
This commit is contained in:
18 files changed
+249
-140
No files matched your search
@@ -45,7 +45,7 @@ fn close_sends_one_close_packet_with_negotiated_token() {
|
||||
));
|
||||
assert!(!client.runtime.is_open());
|
||||
assert!(client.schedule.is_none());
|
||||
assert_eq!(client.applied_dscp, None);
|
||||
assert_eq!(client.applied_traffic_class, None);
|
||||
let packets: Vec<_> = server.rx.iter().take(2).collect();
|
||||
let close = &packets[1];
|
||||
assert_eq!(close[3], flags::FLAG_CLOSE);
|
||||
@@ -82,7 +82,7 @@ fn close_event_reservation_failure_precedes_dscp_clear_and_send() {
|
||||
assert!(client.test_hooks.fail_close_dscp_clear.get());
|
||||
assert!(client.runtime.is_open());
|
||||
assert!(client.schedule.is_some());
|
||||
assert_eq!(client.applied_dscp, Some(0));
|
||||
assert_eq!(client.applied_traffic_class, Some(0));
|
||||
|
||||
client.test_hooks.fail_close_dscp_clear.set(false);
|
||||
client.close().unwrap();
|
||||
@@ -114,7 +114,7 @@ fn close_dscp_clear_failure_precedes_send_and_preserves_open_state() {
|
||||
assert_eq!(client.test_hooks.close_send_attempts.get(), 0);
|
||||
assert!(client.runtime.is_open());
|
||||
assert!(client.schedule.is_some());
|
||||
assert_eq!(client.applied_dscp, Some(0));
|
||||
assert_eq!(client.applied_traffic_class, Some(0));
|
||||
|
||||
client.close().unwrap();
|
||||
assert_eq!(client.test_hooks.close_send_attempts.get(), 1);
|
||||
@@ -147,7 +147,7 @@ fn close_send_failure_leaves_machine_and_schedule_open_for_retry() {
|
||||
assert_eq!(client.test_hooks.close_sent_at.get(), Some(sent_at));
|
||||
assert!(client.runtime.is_open());
|
||||
assert!(client.schedule.is_some());
|
||||
assert_eq!(client.applied_dscp, Some(0));
|
||||
assert_eq!(client.applied_traffic_class, Some(0));
|
||||
assert_eq!(client.test_hooks.close_send_attempts.get(), 1);
|
||||
|
||||
assert!(matches!(
|
||||
@@ -196,7 +196,7 @@ fn short_successful_close_commits_before_length_mismatch() {
|
||||
));
|
||||
assert!(!client.runtime.is_open());
|
||||
assert!(client.schedule.is_none());
|
||||
assert_eq!(client.applied_dscp, None);
|
||||
assert_eq!(client.applied_traffic_class, None);
|
||||
assert_eq!(client.test_hooks.close_sent_at.get(), None);
|
||||
assert!(matches!(client.close(), Err(ClientError::AlreadyClosed)));
|
||||
server.join();
|
||||
@@ -351,7 +351,7 @@ fn peer_close_dscp_cleanup_failure_preserves_events_and_closed_state() {
|
||||
));
|
||||
assert!(client.is_peer_closed());
|
||||
assert!(client.schedule.is_none());
|
||||
assert_eq!(client.applied_dscp, Some(0));
|
||||
assert_eq!(client.applied_traffic_class, Some(0));
|
||||
assert_eq!(client.test_hooks.close_send_attempts.get(), 0);
|
||||
let open = server.rx.recv_timeout(Duration::from_millis(100)).unwrap();
|
||||
let echo = server.rx.recv_timeout(Duration::from_millis(100)).unwrap();
|
||||
|
||||
@@ -42,7 +42,10 @@ fn params_from_config_maps_compatibility_fields() {
|
||||
assert_eq!(params.received_stats, ReceivedStats::Window);
|
||||
assert_eq!(params.stamp_at, StampAt::Midpoint);
|
||||
assert_eq!(params.clock, Clock::Wall);
|
||||
assert_eq!(params.dscp, 46, "config DSCP codepoint must not be shifted");
|
||||
assert_eq!(
|
||||
params.dscp, 184,
|
||||
"config DSCP codepoint 46 must be shifted into raw wire byte 184"
|
||||
);
|
||||
assert_eq!(
|
||||
params.server_fill.as_ref().map(|fill| fill.value.as_str()),
|
||||
Some("rand")
|
||||
@@ -67,7 +70,11 @@ fn params_from_config_accepts_boundary_values() {
|
||||
dscp: 63,
|
||||
..ClientConfig::default()
|
||||
};
|
||||
assert_eq!(params_from_config(&config).unwrap().dscp, 63);
|
||||
assert_eq!(
|
||||
params_from_config(&config).unwrap().dscp,
|
||||
252,
|
||||
"boundary codepoint 63 must be shifted into raw wire byte 252"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -9,9 +9,11 @@ use crate::socket_options::socket_traffic_class;
|
||||
target_os = "illumos",
|
||||
target_os = "haiku",
|
||||
)))]
|
||||
fn normal_open_applies_negotiated_dscp_after_open_and_close_clears_it() {
|
||||
fn normal_open_applies_negotiated_traffic_class_after_open_and_close_clears_it() {
|
||||
let mut params = default_params();
|
||||
params.dscp = 46;
|
||||
// Raw wire TOS/Traffic Class byte for DSCP codepoint 46 (EF): a
|
||||
// compliant server echoes back the raw byte it received, unchanged.
|
||||
params.dscp = 184;
|
||||
let server = start_fake_server(move |socket, tx| {
|
||||
let (_, peer) = recv_request(&socket, &tx);
|
||||
let reply = open_reply(FLAG_OPEN | FLAG_REPLY, TOKEN, ¶ms, None);
|
||||
@@ -48,7 +50,7 @@ fn normal_open_applies_negotiated_dscp_after_open_and_close_clears_it() {
|
||||
target_os = "illumos",
|
||||
target_os = "haiku",
|
||||
)))]
|
||||
fn normal_open_uses_negotiated_dscp_not_requested_dscp() {
|
||||
fn normal_open_uses_negotiated_traffic_class_not_requested_dscp() {
|
||||
let mut returned = default_params();
|
||||
returned.dscp = 0;
|
||||
let server = open_success_server(returned);
|
||||
@@ -82,9 +84,10 @@ fn normal_open_uses_negotiated_dscp_not_requested_dscp() {
|
||||
target_os = "illumos",
|
||||
target_os = "haiku",
|
||||
)))]
|
||||
fn failed_close_send_restores_negotiated_dscp_and_keeps_session_open() {
|
||||
fn failed_close_send_restores_negotiated_traffic_class_and_keeps_session_open() {
|
||||
let mut params = default_params();
|
||||
params.dscp = 46;
|
||||
// Raw wire TOS/Traffic Class byte for DSCP codepoint 46 (EF).
|
||||
params.dscp = 184;
|
||||
let server = start_fake_server(move |socket, tx| {
|
||||
let (_, peer) = recv_request(&socket, &tx);
|
||||
socket
|
||||
@@ -106,7 +109,7 @@ fn failed_close_send_restores_negotiated_dscp_and_keeps_session_open() {
|
||||
assert!(matches!(error, ClientError::Socket(_)));
|
||||
assert!(client.runtime.is_open());
|
||||
assert!(client.schedule.is_some());
|
||||
assert_eq!(client.applied_dscp, Some(46));
|
||||
assert_eq!(client.applied_traffic_class, Some(184));
|
||||
assert_eq!(
|
||||
socket_traffic_class(&client.socket, client.remote).unwrap() & 0xfc,
|
||||
184
|
||||
@@ -139,7 +142,7 @@ fn failed_close_keeps_send_error_primary_when_dscp_restoration_also_fails() {
|
||||
assert!(error.to_string().contains("injected close send failure"));
|
||||
assert!(client.runtime.is_open());
|
||||
assert!(client.schedule.is_some());
|
||||
assert_eq!(client.applied_dscp, Some(0));
|
||||
assert_eq!(client.applied_traffic_class, Some(0));
|
||||
client.close().unwrap();
|
||||
server.join();
|
||||
}
|
||||
@@ -152,9 +155,10 @@ fn failed_close_keeps_send_error_primary_when_dscp_restoration_also_fails() {
|
||||
target_os = "illumos",
|
||||
target_os = "haiku",
|
||||
)))]
|
||||
fn authenticated_peer_close_clears_schedule_and_negotiated_dscp() {
|
||||
fn authenticated_peer_close_clears_schedule_and_negotiated_traffic_class() {
|
||||
let mut params = default_params();
|
||||
params.dscp = 46;
|
||||
// Raw wire TOS/Traffic Class byte for DSCP codepoint 46 (EF).
|
||||
params.dscp = 184;
|
||||
let server = start_fake_server(move |socket, tx| {
|
||||
let (_, peer) = recv_request(&socket, &tx);
|
||||
socket
|
||||
@@ -195,7 +199,7 @@ fn authenticated_peer_close_clears_schedule_and_negotiated_dscp() {
|
||||
]
|
||||
));
|
||||
assert!(client.schedule.is_none());
|
||||
assert_eq!(client.applied_dscp, None);
|
||||
assert_eq!(client.applied_traffic_class, None);
|
||||
assert_eq!(
|
||||
socket_traffic_class(&client.socket, client.remote).unwrap(),
|
||||
0
|
||||
|
||||
@@ -33,13 +33,17 @@ fn strict_negotiation_rejects_changed_params() {
|
||||
..ClientConfig::default()
|
||||
};
|
||||
let requested = params_from_config(&config).unwrap();
|
||||
assert_eq!(
|
||||
requested.dscp, 184,
|
||||
"codepoint 46 must become raw wire byte 184"
|
||||
);
|
||||
let mut returned = requested.clone();
|
||||
returned.dscp = 0;
|
||||
assert_eq!(
|
||||
rejection_reason(&requested, &returned, NegotiationPolicy::Strict),
|
||||
NegotiationRestriction::DscpChanged {
|
||||
requested: requested.dscp,
|
||||
negotiated: returned.dscp,
|
||||
requested: 46,
|
||||
negotiated: 0,
|
||||
}
|
||||
.message()
|
||||
);
|
||||
@@ -183,17 +187,34 @@ fn strict_negotiation_rejects_negative_returned_length() {
|
||||
|
||||
#[test]
|
||||
fn loose_negotiation_rejects_runtime_invalid_returned_dscp() {
|
||||
let config = ClientConfig::default();
|
||||
let config = ClientConfig {
|
||||
dscp: 46,
|
||||
..ClientConfig::default()
|
||||
};
|
||||
let requested = params_from_config(&config).unwrap();
|
||||
assert_eq!(
|
||||
requested.dscp, 184,
|
||||
"codepoint 46 must become raw wire byte 184"
|
||||
);
|
||||
|
||||
for dscp in [-1, 64] {
|
||||
for dscp in [-1, 256] {
|
||||
let mut returned = requested.clone();
|
||||
returned.dscp = dscp;
|
||||
assert_eq!(
|
||||
rejection_reason(&requested, &returned, NegotiationPolicy::Loose),
|
||||
"dscp must be in range 0..=63"
|
||||
"dscp must be in range 0..=255"
|
||||
);
|
||||
}
|
||||
|
||||
// A raw returned value of 184 must be accepted even though it exceeds the
|
||||
// 0..=63 codepoint range; it is the correctly negotiated wire value for
|
||||
// codepoint 46 and is not subject to the codepoint bound at all.
|
||||
let returned = requested.clone();
|
||||
assert!(
|
||||
assert_negotiates(&requested, &returned, NegotiationPolicy::Loose)
|
||||
.restrictions
|
||||
.is_empty()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -13,7 +13,7 @@ fn no_test_success_validates_params() {
|
||||
assert_eq!(negotiated.params, params);
|
||||
assert!(client.next_send_deadline().is_none());
|
||||
assert!(client.schedule.is_none());
|
||||
assert_eq!(client.applied_dscp, None);
|
||||
assert_eq!(client.applied_traffic_class, None);
|
||||
server.join();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ fn successful_open_handshake() {
|
||||
let negotiated = assert_open_started(client.open().unwrap());
|
||||
assert_eq!(negotiated.params, params);
|
||||
assert!(client.schedule.is_some());
|
||||
assert_eq!(client.applied_dscp, Some(0));
|
||||
assert_eq!(client.applied_traffic_class, Some(0));
|
||||
server.join();
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ fn schedule_duration_overflow_cannot_partially_open() {
|
||||
assert!(failure.machine.cleanup_close_packet().is_some());
|
||||
assert!(client.runtime.prepare_open_request().is_ok());
|
||||
assert!(client.schedule.is_none());
|
||||
assert_eq!(client.applied_dscp, None);
|
||||
assert_eq!(client.applied_traffic_class, None);
|
||||
assert_eq!(client.recv_buffer.len(), previous_recv_len);
|
||||
server.join();
|
||||
}
|
||||
@@ -346,7 +346,9 @@ fn cleanup_send_failure_does_not_replace_primary_open_error() {
|
||||
#[test]
|
||||
fn receive_buffer_reservation_failure_precedes_dscp_application() {
|
||||
let mut returned = default_params();
|
||||
returned.dscp = 46;
|
||||
// Raw wire TOS/Traffic Class byte for DSCP codepoint 46 (EF), matching
|
||||
// what the client below requests so negotiation succeeds unchanged.
|
||||
returned.dscp = 184;
|
||||
let server = start_fake_server(move |socket, tx| {
|
||||
let (_, peer) = recv_request(&socket, &tx);
|
||||
socket
|
||||
@@ -376,7 +378,7 @@ fn receive_buffer_reservation_failure_precedes_dscp_application() {
|
||||
assert!(client.test_hooks.fail_open_dscp.get());
|
||||
assert!(client.runtime.prepare_open_request().is_ok());
|
||||
assert!(client.schedule.is_none());
|
||||
assert_eq!(client.applied_dscp, None);
|
||||
assert_eq!(client.applied_traffic_class, None);
|
||||
server.join();
|
||||
}
|
||||
|
||||
@@ -406,7 +408,7 @@ fn dscp_application_failure_leaves_machine_connected() {
|
||||
assert!(client.test_hooks.prepared_active_session_before_dscp.get());
|
||||
assert!(client.runtime.prepare_open_request().is_ok());
|
||||
assert!(client.schedule.is_none());
|
||||
assert_eq!(client.applied_dscp, None);
|
||||
assert_eq!(client.applied_traffic_class, None);
|
||||
server.join();
|
||||
}
|
||||
|
||||
@@ -432,7 +434,7 @@ fn read_timeout_restoration_failure_leaves_machine_connected() {
|
||||
));
|
||||
assert!(client.runtime.prepare_open_request().is_ok());
|
||||
assert!(client.schedule.is_none());
|
||||
assert_eq!(client.applied_dscp, None);
|
||||
assert_eq!(client.applied_traffic_class, None);
|
||||
server.join();
|
||||
}
|
||||
|
||||
@@ -458,6 +460,6 @@ fn dscp_rollback_failure_keeps_timeout_restoration_primary() {
|
||||
assert!(matches!(error, ClientError::ReadTimeoutRestore { .. }));
|
||||
assert!(client.runtime.prepare_open_request().is_ok());
|
||||
assert!(client.schedule.is_none());
|
||||
assert_eq!(client.applied_dscp, None);
|
||||
assert_eq!(client.applied_traffic_class, None);
|
||||
server.join();
|
||||
}
|
||||
@@ -14,7 +14,7 @@ fn echo_reply_metadata_propagates_observed_dscp_with_ancillary() {
|
||||
let (size, _) = socket.recv_from(&mut buf).unwrap();
|
||||
tx.send(buf[..size].to_vec()).unwrap();
|
||||
let seq = u32::from_le_bytes(buf[12..16].try_into().unwrap());
|
||||
crate::socket_options::apply_dscp_to_socket(&socket, peer, 46).unwrap();
|
||||
crate::socket_options::apply_traffic_class_to_socket(&socket, peer, 184).unwrap();
|
||||
let reply_packet =
|
||||
echo_reply_packet(TOKEN, seq, ¶ms, &TimestampFields::default(), None);
|
||||
socket.send_to(&reply_packet, peer).unwrap();
|
||||
|
||||
Reference in new issue
Block a user