smb_server_transport/lib.rs
1//! Async SMB message transport abstraction.
2//!
3//! A [`Transport`] moves complete SMB frames (the bytes between NBSS
4//! headers, i.e. starting at the `\xFFSMB` / `\xFESMB` magic) over some
5//! network or in-memory channel. The server dispatch is written against this
6//! trait so it can be exercised without real sockets.
7
8#![forbid(unsafe_code)]
9#![deny(missing_docs)]
10#![warn(missing_debug_implementations)]
11
12pub mod mem;
13#[cfg(test)]
14mod tests;
15pub mod tcp;
16
17use async_trait::async_trait;
18
19/// One complete SMB frame received from the wire.
20#[derive(Debug)]
21pub struct Frame(pub Vec<u8>);
22
23/// Errors surfaced by transports.
24#[derive(Debug, thiserror::Error)]
25pub enum TransportError {
26 /// Underlying I/O failure.
27 #[error("transport i/o: {0}")]
28 Io(#[from] std::io::Error),
29}
30
31/// Abstract bidirectional frame transport.
32///
33/// Implementations must preserve frame boundaries: each value returned by
34/// [`Transport::recv`] is exactly one SMB frame.
35///
36/// Futures are `?Send`: the io_uring TCP transport owns `!Send` resources and
37/// runs entirely on one thread under a `tokio_uring` runtime.
38#[async_trait(?Send)]
39pub trait Transport {
40 /// Receive the next frame. `Ok(None)` signals a clean end of stream.
41 async fn recv(&mut self) -> Result<Option<Frame>, TransportError>;
42
43 /// Transmit one frame.
44 async fn send(&mut self, data: &[u8]) -> Result<(), TransportError>;
45
46 /// Human-readable peer description for logs.
47 fn peer(&self) -> String;
48
49 /// Split into independent read and write halves.
50 ///
51 /// The server drives the read half from its accept loop while a dedicated
52 /// writer task drains an outbound queue into the write half. This lets
53 /// background work (async STATUS_PENDING completions, oplock/lease breaks,
54 /// CHANGE_NOTIFY) emit unsolicited frames without cancelling the blocking
55 /// `recv` — critical because `recv` is not cancel-safe.
56 fn split(self: Box<Self>) -> (Box<dyn FrameSource>, Box<dyn FrameSink>);
57}
58
59/// Read half of a split [`Transport`].
60#[async_trait(?Send)]
61pub trait FrameSource {
62 /// Receive the next frame. `Ok(None)` signals a clean end of stream.
63 async fn recv(&mut self) -> Result<Option<Frame>, TransportError>;
64
65 /// Human-readable peer description for logs.
66 fn peer(&self) -> String;
67}
68
69/// Write half of a split [`Transport`]. Owned by the per-connection writer task.
70#[async_trait(?Send)]
71pub trait FrameSink {
72 /// Transmit one frame.
73 async fn send(&mut self, data: &[u8]) -> Result<(), TransportError>;
74}