Skip to main content

phantom_protocol/transport/
multiplexer.rs

1//! Stream Demultiplexer
2//!
3//! Routes decrypted inbound payloads to their target streams based on the
4//! `stream_id` carried in the `PhantomPacket` header. A lightweight, zero-copy
5//! routing table (`DashMap<stream_id, mpsc::Sender>`) keyed by `u32` stream id:
6//! the recv pump looks up the sender and hands off the `Bytes` payload without
7//! copying. Stream id 0 is reserved for the session-level control channel;
8//! unknown stream ids are dropped with a log warning.
9
10use crate::transport::types::SequenceNumber;
11use bytes::Bytes;
12use dashmap::DashMap;
13use std::sync::atomic::{AtomicU32, Ordering};
14use tokio::sync::mpsc;
15
16/// Messages routed to a stream by the demultiplexer.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum StreamMessage {
19    /// Normal data payload
20    Data(Bytes),
21    /// Acknowledgment of a specific sequence number
22    Ack(SequenceNumber),
23    /// Stream closure signal
24    Close,
25}
26
27/// A lightweight stream demultiplexer that routes packets to registered streams.
28///
29/// # Design
30///
31/// ```text
32///   UDP Socket → StreamDemultiplexer → Stream[0] (reliable)
33///                                    → Stream[1] (reliable)
34///                                    → Stream[2] (unreliable)
35///                                    → control channel
36/// ```
37///
38/// Each stream is identified by a `u32` stream ID extracted from the packet header.
39/// Unrecognized stream IDs are dropped (with a log warning).
40pub struct StreamDemultiplexer {
41    /// Active stream senders: stream_id → sender channel
42    streams: DashMap<u32, mpsc::Sender<StreamMessage>>,
43    /// Control channel for session-level messages (stream_id = 0)
44    control_tx: mpsc::Sender<Bytes>,
45    /// Next stream ID to allocate
46    next_stream_id: AtomicU32,
47}
48
49/// Handle returned when a stream is registered with the demultiplexer.
50pub struct StreamHandle {
51    /// The stream ID assigned to this stream
52    pub stream_id: u32,
53    /// Receiver end for incoming packets
54    pub rx: mpsc::Receiver<StreamMessage>,
55}
56
57impl StreamDemultiplexer {
58    /// Create a new demultiplexer with a control channel.
59    ///
60    /// The control channel (stream_id = 0) receives session-level packets
61    /// such as keepalives, migration signals, and stream management.
62    pub fn new(control_buffer: usize) -> (Self, mpsc::Receiver<Bytes>) {
63        let (control_tx, control_rx) = mpsc::channel(control_buffer);
64        let mux = Self {
65            streams: DashMap::new(),
66            control_tx,
67            next_stream_id: AtomicU32::new(2), // 0 = control, 1 = raw-app session channel
68        };
69        (mux, control_rx)
70    }
71
72    /// Register a new stream and get back a handle with the assigned ID.
73    ///
74    /// `buffer_size` controls the depth of the per-stream receive buffer.
75    pub fn open_stream(&self, buffer_size: usize) -> StreamHandle {
76        let stream_id = self.next_stream_id.fetch_add(1, Ordering::Relaxed);
77        let (tx, rx) = mpsc::channel(buffer_size);
78        self.streams.insert(stream_id, tx);
79        StreamHandle { stream_id, rx }
80    }
81
82    /// Register a stream with a specific ID (e.g., for accepting remote-initiated streams).
83    pub fn register_stream(&self, stream_id: u32, buffer_size: usize) -> StreamHandle {
84        let (tx, rx) = mpsc::channel(buffer_size);
85        self.streams.insert(stream_id, tx);
86        // Update next_stream_id if necessary to avoid collisions
87        let _ = self
88            .next_stream_id
89            .fetch_max(stream_id + 1, Ordering::Relaxed);
90        StreamHandle { stream_id, rx }
91    }
92
93    /// Remove a stream from the routing table.
94    pub fn close_stream(&self, stream_id: u32) {
95        self.streams.remove(&stream_id);
96    }
97
98    /// Route data payload to the appropriate stream.
99    ///
100    /// Returns `true` if the packet was successfully delivered,
101    /// `false` if the stream was not found or the buffer was full.
102    pub fn route_data(&self, stream_id: u32, payload: Bytes) -> bool {
103        if stream_id == 0 {
104            // Control channel
105            return self.control_tx.try_send(payload).is_ok();
106        }
107
108        if let Some(sender) = self.streams.get(&stream_id) {
109            sender.try_send(StreamMessage::Data(payload)).is_ok()
110        } else {
111            log::warn!(
112                "StreamDemultiplexer: dropping data for unknown stream_id={}",
113                stream_id
114            );
115            false
116        }
117    }
118
119    /// Route data asynchronously (waits if buffer is full).
120    pub async fn route_data_async(&self, stream_id: u32, payload: Bytes) -> bool {
121        if stream_id == 0 {
122            return self.control_tx.send(payload).await.is_ok();
123        }
124
125        if let Some(sender) = self.streams.get(&stream_id) {
126            sender.send(StreamMessage::Data(payload)).await.is_ok()
127        } else {
128            log::warn!(
129                "StreamDemultiplexer: dropping data for unknown stream_id={}",
130                stream_id
131            );
132            false
133        }
134    }
135
136    /// Route an ACK signal to a stream **without blocking**. Returns
137    /// `false` if the stream is unknown or its buffer is full — the recv pump
138    /// uses this on its never-block path, where a vestigial/absent stream
139    /// consumer must not stall inbound ACK/control processing.
140    pub fn route_ack(&self, stream_id: u32, seq: SequenceNumber) -> bool {
141        if stream_id == 0 {
142            return false;
143        }
144        if let Some(sender) = self.streams.get(&stream_id) {
145            sender.try_send(StreamMessage::Ack(seq)).is_ok()
146        } else {
147            false
148        }
149    }
150
151    /// Route a stream-closure signal **without blocking** (see [`Self::route_ack`]).
152    pub fn route_close(&self, stream_id: u32) -> bool {
153        if stream_id == 0 {
154            return false;
155        }
156        if let Some(sender) = self.streams.get(&stream_id) {
157            sender.try_send(StreamMessage::Close).is_ok()
158        } else {
159            false
160        }
161    }
162
163    /// Route an ACK signal to a stream asynchronously.
164    pub async fn route_ack_async(&self, stream_id: u32, seq: SequenceNumber) -> bool {
165        if stream_id == 0 {
166            return false;
167        }
168
169        if let Some(sender) = self.streams.get(&stream_id) {
170            sender.send(StreamMessage::Ack(seq)).await.is_ok()
171        } else {
172            log::warn!(
173                "StreamDemultiplexer: dropping ACK for unknown stream_id={}",
174                stream_id
175            );
176            false
177        }
178    }
179
180    /// Route a stream closure signal asynchronously.
181    pub async fn route_close_async(&self, stream_id: u32) -> bool {
182        if stream_id == 0 {
183            return false;
184        }
185
186        if let Some(sender) = self.streams.get(&stream_id) {
187            sender.send(StreamMessage::Close).await.is_ok()
188        } else {
189            log::warn!(
190                "StreamDemultiplexer: dropping CLOSE for unknown stream_id={}",
191                stream_id
192            );
193            false
194        }
195    }
196
197    /// Number of active streams (excluding control channel).
198    pub fn active_stream_count(&self) -> usize {
199        self.streams.len()
200    }
201
202    /// Check if a stream is registered.
203    pub fn has_stream(&self, stream_id: u32) -> bool {
204        self.streams.contains_key(&stream_id)
205    }
206}
207
208#[cfg(test)]
209mod tests {
210    use super::*;
211
212    #[tokio::test]
213    async fn test_demux_open_and_route() {
214        let (demux, _ctrl_rx) = StreamDemultiplexer::new(16);
215
216        let handle = demux.open_stream(16);
217        let sid = handle.stream_id;
218        let mut rx = handle.rx;
219
220        assert!(demux.has_stream(sid));
221        assert_eq!(demux.active_stream_count(), 1);
222
223        // Route a packet
224        let data = Bytes::from_static(b"hello stream");
225        assert!(demux.route_data(sid, data.clone()));
226
227        // Receive it
228        let received = rx.recv().await.unwrap();
229        assert_eq!(received, StreamMessage::Data(data));
230    }
231
232    #[tokio::test]
233    async fn test_demux_control_channel() {
234        let (demux, mut ctrl_rx) = StreamDemultiplexer::new(16);
235
236        let data = Bytes::from_static(b"control msg");
237        assert!(demux.route_data(0, data.clone()));
238
239        let received = ctrl_rx.recv().await.unwrap();
240        assert_eq!(received, data);
241    }
242
243    #[tokio::test]
244    async fn test_demux_unknown_stream() {
245        let (demux, _ctrl_rx) = StreamDemultiplexer::new(16);
246
247        // Route to non-existent stream
248        let data = Bytes::from_static(b"lost");
249        assert!(!demux.route_data(999, data));
250    }
251
252    #[tokio::test]
253    async fn test_demux_close_stream() {
254        let (demux, _ctrl_rx) = StreamDemultiplexer::new(16);
255
256        let handle = demux.open_stream(16);
257        let sid = handle.stream_id;
258        assert!(demux.has_stream(sid));
259
260        demux.close_stream(sid);
261        assert!(!demux.has_stream(sid));
262        assert_eq!(demux.active_stream_count(), 0);
263    }
264
265    #[tokio::test]
266    async fn test_demux_multiple_streams() {
267        let (demux, _ctrl_rx) = StreamDemultiplexer::new(16);
268
269        let h1 = demux.open_stream(16);
270        let h2 = demux.open_stream(16);
271        let h3 = demux.open_stream(16);
272
273        assert_ne!(h1.stream_id, h2.stream_id);
274        assert_ne!(h2.stream_id, h3.stream_id);
275        assert_eq!(demux.active_stream_count(), 3);
276    }
277}