Skip to content

Commit dc3096a

Browse files
author
pseusys
committed
futures collected
1 parent 5f7e439 commit dc3096a

1 file changed

Lines changed: 39 additions & 13 deletions

File tree

typhoon/src/session/client.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
mod tests;
44

55
/// Client-side session manager implementation.
6+
use std::future::Future;
67
use std::mem::take;
8+
use std::pin::Pin;
79
use std::sync::Arc;
810
use std::sync::atomic::{AtomicU32, Ordering};
911

@@ -12,7 +14,7 @@ use log::{debug, warn};
1214
use crate::bytes::{ByteBuffer, ByteBufferMut, DynamicByteBuffer};
1315
use crate::cache::SharedValue;
1416
use crate::crypto::ClientCryptoTool;
15-
use crate::flow::FlowManager;
17+
use crate::flow::{FlowControllerError, FlowManager};
1618
use crate::session::client_health::ClientHealthProvider;
1719
use crate::session::common::SessionManager;
1820
use crate::session::error::SessionControllerError;
@@ -22,6 +24,8 @@ use crate::tailor::{ClientConnectionHandler, IdentityType, PacketFlags, Tailor};
2224
use crate::utils::random::{SupportRng, get_rng};
2325
use crate::utils::sync::{AsyncExecutor, Mutex, create_watch};
2426

27+
type RecvFut = Pin<Box<dyn Future<Output = Result<DynamicByteBuffer, FlowControllerError>> + Send>>;
28+
2529
struct ClientSessionManagerInternalSend<T: IdentityType + Clone> {
2630
cipher: SharedValue<ClientCryptoTool<T>>,
2731
}
@@ -31,16 +35,18 @@ struct ClientSessionManagerInternalReceive<T: IdentityType + Clone> {
3135
}
3236

3337
/// Client-side session manager that encrypts data and manages health checking.
34-
pub struct ClientSessionManager<T: IdentityType + Clone + 'static, AE: AsyncExecutor + 'static, FM: FlowManager + Send + Sync + 'static, CC: ClientConnectionHandler + 'static> {
38+
pub struct ClientSessionManager<T: IdentityType + Clone + 'static, AE: AsyncExecutor + 'static, FM: FlowManager + Clone + Send + Sync + 'static, CC: ClientConnectionHandler + 'static> {
3539
health_provider: ClientHealthProvider<T, AE, Self, CC>,
3640
send_internal: Mutex<ClientSessionManagerInternalSend<T>>,
3741
receive_internal: Mutex<ClientSessionManagerInternalReceive<T>>,
3842
incremental_counter: AtomicU32,
3943
flows: Vec<FM>,
4044
settings: Arc<Settings<AE>>,
45+
/// Persistent per-flow receive futures and their flow indices, reused across `receive_packet` calls.
46+
recv_state: Mutex<Option<(Vec<RecvFut>, Vec<usize>)>>,
4147
}
4248

43-
impl<T: IdentityType + Clone, AE: AsyncExecutor, FM: FlowManager + Send + Sync, CC: ClientConnectionHandler + 'static> ClientSessionManager<T, AE, FM, CC> {
49+
impl<T: IdentityType + Clone, AE: AsyncExecutor, FM: FlowManager + Clone + Send + Sync, CC: ClientConnectionHandler + 'static> ClientSessionManager<T, AE, FM, CC> {
4450
/// Create a new client session manager without starting the handshake.
4551
/// Call `start()` after the background receive loop is running.
4652
pub fn new(cipher: SharedValue<ClientCryptoTool<T>>, flows: Vec<FM>, settings: Arc<Settings<AE>>, initial_data_generator: CC) -> Result<Arc<Self>, SessionControllerError> {
@@ -65,6 +71,7 @@ impl<T: IdentityType + Clone, AE: AsyncExecutor, FM: FlowManager + Send + Sync,
6571
incremental_counter: AtomicU32::new(0),
6672
flows,
6773
settings,
74+
recv_state: Mutex::new(None),
6875
}
6976
});
7077

@@ -91,7 +98,7 @@ impl<T: IdentityType + Clone, AE: AsyncExecutor, FM: FlowManager + Send + Sync,
9198
}
9299
}
93100

94-
impl<T: IdentityType + Clone, AE: AsyncExecutor, FM: FlowManager + Send + Sync, CC: ClientConnectionHandler + 'static> SessionManager for ClientSessionManager<T, AE, FM, CC> {
101+
impl<T: IdentityType + Clone, AE: AsyncExecutor, FM: FlowManager + Clone + Send + Sync + 'static, CC: ClientConnectionHandler + 'static> SessionManager for ClientSessionManager<T, AE, FM, CC> {
95102
async fn send_packet(&self, packet: DynamicByteBuffer, generated: bool) -> Result<(), SessionControllerError> {
96103
let full_packet = if generated {
97104
packet
@@ -130,15 +137,34 @@ impl<T: IdentityType + Clone, AE: AsyncExecutor, FM: FlowManager + Send + Sync,
130137
let recv_buf = self.settings.pool().allocate_for_recv();
131138
self.flows[0].receive_packet(recv_buf).await.map_err(SessionControllerError::FlowError)?
132139
} else {
133-
let futs: Vec<_> = self
134-
.flows
135-
.iter()
136-
.map(|flow| {
137-
let buf = self.settings.pool().allocate_for_recv();
138-
Box::pin(flow.receive_packet(buf))
140+
// Take the persistent future state (releasing the lock before awaiting).
141+
let (futs, mut flow_indices) = {
142+
let mut guard = self.recv_state.lock().await;
143+
guard.take().unwrap_or_else(|| {
144+
let mut futs: Vec<RecvFut> = Vec::with_capacity(self.flows.len());
145+
let mut indices: Vec<usize> = Vec::with_capacity(self.flows.len());
146+
for (i, flow) in self.flows.iter().enumerate() {
147+
let f = flow.clone();
148+
let buf = self.settings.pool().allocate_for_recv();
149+
futs.push(Box::pin(async move { f.receive_packet(buf).await }));
150+
indices.push(i);
151+
}
152+
(futs, indices)
139153
})
140-
.collect();
141-
futures::future::select_all(futs).await.0.map_err(SessionControllerError::FlowError)?
154+
};
155+
156+
let (result, completed_pos, mut remaining_futs) = futures::future::select_all(futs).await;
157+
let completed_flow_idx = flow_indices.remove(completed_pos);
158+
159+
// Replenish a new future for the flow that just completed.
160+
let f = self.flows[completed_flow_idx].clone();
161+
let buf = self.settings.pool().allocate_for_recv();
162+
remaining_futs.push(Box::pin(async move { f.receive_packet(buf).await }));
163+
flow_indices.push(completed_flow_idx);
164+
165+
*self.recv_state.lock().await = Some((remaining_futs, flow_indices));
166+
167+
result.map_err(SessionControllerError::FlowError)?
142168
};
143169

144170
// The flow manager returns: encrypted_payload || plaintext_tailor (full TAILOR_LENGTH + T::length() bytes).
@@ -171,7 +197,7 @@ impl<T: IdentityType + Clone, AE: AsyncExecutor, FM: FlowManager + Send + Sync,
171197
}
172198
}
173199

174-
impl<T: IdentityType + Clone, AE: AsyncExecutor, FM: FlowManager + Send + Sync, CC: ClientConnectionHandler + 'static> Drop for ClientSessionManager<T, AE, FM, CC> {
200+
impl<T: IdentityType + Clone, AE: AsyncExecutor, FM: FlowManager + Clone + Send + Sync + 'static, CC: ClientConnectionHandler + 'static> Drop for ClientSessionManager<T, AE, FM, CC> {
175201
fn drop(&mut self) {
176202
drop(take(&mut self.flows));
177203
}

0 commit comments

Comments
 (0)