Harden stream cleanup state
This commit is contained in:
+115
-22
@@ -2133,11 +2133,7 @@ async fn handle_stream_open_reject(
|
||||
}
|
||||
client.endpoint = peer;
|
||||
client.last_seen = Instant::now();
|
||||
client.stream_writers.remove(&reject.stream_id);
|
||||
client.stream_pending_opens.remove(&reject.stream_id);
|
||||
client.opened_streams.remove(&reject.stream_id);
|
||||
client.stream_send_credit.remove(&reject.stream_id);
|
||||
client.stream_pending_data.remove(&reject.stream_id);
|
||||
cleanup_client_stream(client, reject.stream_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2192,15 +2188,7 @@ async fn handle_stream_close(
|
||||
// Connection migration on any authenticated, fresh packet (spec §11).
|
||||
client.endpoint = peer;
|
||||
client.last_seen = Instant::now();
|
||||
client.stream_writers.remove(&close.stream_id);
|
||||
client.stream_pending_opens.remove(&close.stream_id);
|
||||
client.opened_streams.remove(&close.stream_id);
|
||||
client.stream_send_credit.remove(&close.stream_id);
|
||||
client.stream_pending_data.remove(&close.stream_id);
|
||||
client.stream_next_send_offset.remove(&close.stream_id);
|
||||
client.stream_sent_data.remove(&close.stream_id);
|
||||
client.stream_next_recv_offset.remove(&close.stream_id);
|
||||
client.stream_recv_pending.remove(&close.stream_id);
|
||||
cleanup_client_stream(client, close.stream_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3280,6 +3268,18 @@ fn accept_stream_data(client: &mut ClientState, data: StreamData) -> (Vec<Vec<u8
|
||||
(writes, consumed, *expected)
|
||||
}
|
||||
|
||||
fn cleanup_client_stream(client: &mut ClientState, stream_id: u64) {
|
||||
client.stream_writers.remove(&stream_id);
|
||||
client.stream_pending_opens.remove(&stream_id);
|
||||
client.opened_streams.remove(&stream_id);
|
||||
client.stream_send_credit.remove(&stream_id);
|
||||
client.stream_pending_data.remove(&stream_id);
|
||||
client.stream_next_send_offset.remove(&stream_id);
|
||||
client.stream_sent_data.remove(&stream_id);
|
||||
client.stream_next_recv_offset.remove(&stream_id);
|
||||
client.stream_recv_pending.remove(&stream_id);
|
||||
}
|
||||
|
||||
fn ack_stream_data(client: &mut ClientState, stream_id: u64, received_offset: u64) {
|
||||
let Some(sent) = client.stream_sent_data.get_mut(&stream_id) else {
|
||||
return;
|
||||
@@ -3340,14 +3340,7 @@ async fn send_stream_close_to_client(
|
||||
{
|
||||
let mut locked = state.lock().expect("server state poisoned");
|
||||
if let Some(client) = locked.client_mut(&client_id) {
|
||||
client.stream_writers.remove(&stream_id);
|
||||
client.opened_streams.remove(&stream_id);
|
||||
client.stream_send_credit.remove(&stream_id);
|
||||
client.stream_pending_data.remove(&stream_id);
|
||||
client.stream_next_send_offset.remove(&stream_id);
|
||||
client.stream_sent_data.remove(&stream_id);
|
||||
client.stream_next_recv_offset.remove(&stream_id);
|
||||
client.stream_recv_pending.remove(&stream_id);
|
||||
cleanup_client_stream(client, stream_id);
|
||||
}
|
||||
}
|
||||
let body = protocol::to_body(&StreamClose { stream_id })?;
|
||||
@@ -4053,6 +4046,106 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cleanup_client_stream_removes_all_per_stream_state_only_for_target() {
|
||||
let stream_id = 42;
|
||||
let other_stream_id = 43;
|
||||
let mut client = test_client_state([7u8; 32]);
|
||||
let (writer_tx, _writer_rx) = mpsc::channel(1);
|
||||
client.stream_writers.insert(stream_id, writer_tx);
|
||||
client.opened_streams.insert(stream_id);
|
||||
client.opened_streams.insert(other_stream_id);
|
||||
client.stream_send_credit.insert(stream_id, 12);
|
||||
client.stream_send_credit.insert(other_stream_id, 34);
|
||||
client
|
||||
.stream_pending_data
|
||||
.insert(stream_id, VecDeque::from([vec![1]]));
|
||||
client
|
||||
.stream_pending_data
|
||||
.insert(other_stream_id, VecDeque::from([vec![2]]));
|
||||
client.stream_pending_opens.insert(
|
||||
stream_id,
|
||||
PendingStreamOpen {
|
||||
target_host: "127.0.0.1".to_string(),
|
||||
target_port: 1234,
|
||||
last_sent: Instant::now(),
|
||||
attempts: 1,
|
||||
},
|
||||
);
|
||||
client.stream_pending_opens.insert(
|
||||
other_stream_id,
|
||||
PendingStreamOpen {
|
||||
target_host: "127.0.0.1".to_string(),
|
||||
target_port: 1235,
|
||||
last_sent: Instant::now(),
|
||||
attempts: 1,
|
||||
},
|
||||
);
|
||||
client.stream_next_send_offset.insert(stream_id, 55);
|
||||
client.stream_next_send_offset.insert(other_stream_id, 66);
|
||||
client.stream_sent_data.insert(
|
||||
stream_id,
|
||||
BTreeMap::from([(
|
||||
0,
|
||||
PendingStreamChunk {
|
||||
offset: 0,
|
||||
bytes: vec![3],
|
||||
last_sent: Instant::now(),
|
||||
attempts: 1,
|
||||
},
|
||||
)]),
|
||||
);
|
||||
client.stream_sent_data.insert(
|
||||
other_stream_id,
|
||||
BTreeMap::from([(
|
||||
0,
|
||||
PendingStreamChunk {
|
||||
offset: 0,
|
||||
bytes: vec![4],
|
||||
last_sent: Instant::now(),
|
||||
attempts: 1,
|
||||
},
|
||||
)]),
|
||||
);
|
||||
client.stream_next_recv_offset.insert(stream_id, 77);
|
||||
client.stream_next_recv_offset.insert(other_stream_id, 88);
|
||||
client
|
||||
.stream_recv_pending
|
||||
.insert(stream_id, BTreeMap::from([(77, vec![5])]));
|
||||
client
|
||||
.stream_recv_pending
|
||||
.insert(other_stream_id, BTreeMap::from([(88, vec![6])]));
|
||||
|
||||
cleanup_client_stream(&mut client, stream_id);
|
||||
|
||||
assert!(!client.stream_writers.contains_key(&stream_id));
|
||||
assert!(!client.opened_streams.contains(&stream_id));
|
||||
assert!(!client.stream_send_credit.contains_key(&stream_id));
|
||||
assert!(!client.stream_pending_data.contains_key(&stream_id));
|
||||
assert!(!client.stream_pending_opens.contains_key(&stream_id));
|
||||
assert!(!client.stream_next_send_offset.contains_key(&stream_id));
|
||||
assert!(!client.stream_sent_data.contains_key(&stream_id));
|
||||
assert!(!client.stream_next_recv_offset.contains_key(&stream_id));
|
||||
assert!(!client.stream_recv_pending.contains_key(&stream_id));
|
||||
|
||||
assert!(client.opened_streams.contains(&other_stream_id));
|
||||
assert!(client.stream_send_credit.contains_key(&other_stream_id));
|
||||
assert!(client.stream_pending_data.contains_key(&other_stream_id));
|
||||
assert!(client.stream_pending_opens.contains_key(&other_stream_id));
|
||||
assert!(
|
||||
client
|
||||
.stream_next_send_offset
|
||||
.contains_key(&other_stream_id)
|
||||
);
|
||||
assert!(client.stream_sent_data.contains_key(&other_stream_id));
|
||||
assert!(
|
||||
client
|
||||
.stream_next_recv_offset
|
||||
.contains_key(&other_stream_id)
|
||||
);
|
||||
assert!(client.stream_recv_pending.contains_key(&other_stream_id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn client_index_stays_in_sync_with_session_clients() {
|
||||
let (pty_tx, _pty_rx) = mpsc::unbounded_channel();
|
||||
|
||||
Reference in New Issue
Block a user