active_rpc/transport/
mod.rs1use std::collections::VecDeque;
21use std::io::{Read, Write};
22use std::net::{TcpListener, TcpStream};
23
24use crate::error::{Error, Result};
25use crate::wire::{Envelope, WireLimits};
26
27pub mod connect;
28#[cfg(feature = "quic")]
29pub mod quic;
30pub mod shm;
31
32pub const MAX_FRAME_BYTES: usize = 64 << 20;
34
35pub trait Transport {
37 fn name(&self) -> &'static str;
39
40 fn send(&mut self, envelope: &Envelope) -> Result<()>;
42
43 fn recv(&mut self) -> Result<Option<Envelope>>;
45
46 fn bytes_written(&self) -> u64 {
48 0
49 }
50}
51
52#[derive(Default)]
57struct Mailboxes {
58 a_to_b: VecDeque<Envelope>,
59 b_to_a: VecDeque<Envelope>,
60}
61
62#[derive(Clone, Default)]
67pub struct InProcessTransport {
68 shared: Option<std::rc::Rc<std::cell::RefCell<Mailboxes>>>,
69 is_a: bool,
71 local: VecDeque<Envelope>,
73}
74
75impl std::fmt::Debug for InProcessTransport {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 f.debug_struct("InProcessTransport")
78 .field("paired", &self.shared.is_some())
79 .finish()
80 }
81}
82
83impl InProcessTransport {
84 pub fn pair() -> (InProcessTransport, InProcessTransport) {
86 let shared = std::rc::Rc::new(std::cell::RefCell::new(Mailboxes::default()));
87 (
88 InProcessTransport {
89 shared: Some(std::rc::Rc::clone(&shared)),
90 is_a: true,
91 local: VecDeque::new(),
92 },
93 InProcessTransport {
94 shared: Some(shared),
95 is_a: false,
96 local: VecDeque::new(),
97 },
98 )
99 }
100
101 pub fn queue() -> InProcessTransport {
103 InProcessTransport::default()
104 }
105}
106
107impl Transport for InProcessTransport {
108 fn name(&self) -> &'static str {
109 "in-process"
110 }
111
112 fn send(&mut self, envelope: &Envelope) -> Result<()> {
113 match &self.shared {
117 Some(shared) => {
118 let mut shared = shared.borrow_mut();
119 if self.is_a {
120 shared.a_to_b.push_back(envelope.clone());
121 } else {
122 shared.b_to_a.push_back(envelope.clone());
123 }
124 }
125 None => self.local.push_back(envelope.clone()),
126 }
127 Ok(())
128 }
129
130 fn recv(&mut self) -> Result<Option<Envelope>> {
131 match &self.shared {
132 Some(shared) => {
133 let mut shared = shared.borrow_mut();
134 Ok(if self.is_a {
135 shared.b_to_a.pop_front()
136 } else {
137 shared.a_to_b.pop_front()
138 })
139 }
140 None => Ok(self.local.pop_front()),
141 }
142 }
143
144 fn bytes_written(&self) -> u64 {
145 0
146 }
147}
148
149#[derive(Debug)]
155pub struct TcpTransport {
156 stream: TcpStream,
157 inbox: VecDeque<Envelope>,
158 written: u64,
159 limits: WireLimits,
160}
161
162impl TcpTransport {
163 pub fn new(stream: TcpStream) -> Result<Self> {
165 stream
166 .set_nodelay(true)
167 .map_err(|error| Error::Transport(error.to_string()))?;
168 Ok(Self {
169 stream,
170 inbox: VecDeque::new(),
171 written: 0,
172 limits: WireLimits::default(),
173 })
174 }
175
176 pub fn with_limits(mut self, limits: WireLimits) -> Self {
178 self.limits = limits;
179 self
180 }
181
182 pub fn connect(address: &str) -> Result<Self> {
184 let stream = TcpStream::connect(address)
185 .map_err(|error| Error::Transport(format!("connect: {error}")))?;
186 Self::new(stream)
187 }
188}
189
190impl Transport for TcpTransport {
191 fn name(&self) -> &'static str {
192 "tcp"
193 }
194
195 fn send(&mut self, envelope: &Envelope) -> Result<()> {
196 let bytes = envelope.encode()?;
197 write_frame(&mut self.stream, &bytes)?;
198 self.written += (bytes.len() + 4) as u64;
199 Ok(())
200 }
201
202 fn recv(&mut self) -> Result<Option<Envelope>> {
203 if let Some(envelope) = self.inbox.pop_front() {
204 return Ok(Some(envelope));
205 }
206 let Some(body) = read_frame(&mut self.stream, &self.limits)? else {
207 return Ok(None);
208 };
209 Ok(Some(Envelope::decode_with(&body, self.limits)?))
210 }
211
212 fn bytes_written(&self) -> u64 {
213 self.written
214 }
215}
216
217pub fn frame(len: usize) -> Result<[u8; 4]> {
219 if len > MAX_FRAME_BYTES {
220 return Err(Error::Wire("frame exceeds the transport ceiling"));
221 }
222 Ok((len as u32).to_le_bytes())
223}
224
225pub fn serve_connection<H>(mut transport: TcpTransport, mut handler: H) -> Result<u64>
230where
231 H: FnMut(Envelope) -> Envelope,
232{
233 let mut served = 0u64;
234 loop {
235 match transport.recv() {
236 Ok(Some(envelope)) => {
237 let response = handler(envelope);
238 transport.send(&response)?;
239 served += 1;
240 }
241 Ok(None) => return Ok(served),
242 Err(error) => {
243 let reply = Envelope::error(0, &error);
244 let _ = transport.send(&reply);
245 return Err(error);
246 }
247 }
248 }
249}
250
251pub fn bind_loopback() -> Result<(TcpListener, String)> {
253 let listener =
254 TcpListener::bind("127.0.0.1:0").map_err(|error| Error::Transport(error.to_string()))?;
255 let address = listener
256 .local_addr()
257 .map_err(|error| Error::Transport(error.to_string()))?
258 .to_string();
259 Ok((listener, address))
260}
261
262pub fn read_frame<R: Read>(reader: &mut R, limits: &WireLimits) -> Result<Option<Vec<u8>>> {
264 let mut header = [0u8; 4];
265 match reader.read_exact(&mut header) {
266 Ok(()) => {}
267 Err(error) if error.kind() == std::io::ErrorKind::UnexpectedEof => return Ok(None),
268 Err(error) => return Err(Error::Transport(error.to_string())),
269 }
270 let len = u32::from_le_bytes(header) as usize;
271 if len > limits.max_bytes {
272 return Err(Error::Wire("frame exceeds the size ceiling"));
273 }
274 let mut body = vec![0u8; len];
275 reader
276 .read_exact(&mut body)
277 .map_err(|error| Error::Transport(error.to_string()))?;
278 Ok(Some(body))
279}
280
281pub fn write_frame<W: Write>(writer: &mut W, body: &[u8]) -> Result<()> {
283 writer
284 .write_all(&frame(body.len())?)
285 .and_then(|_| writer.write_all(body))
286 .and_then(|_| writer.flush())
287 .map_err(|error| Error::Transport(error.to_string()))
288}