1#[cfg(unix)]
7use std::os::unix::net::{SocketAddr as UnixSocketAddr, UnixListener, UnixStream};
8use std::{
9 io::{self, Read, Write},
10 net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs},
11 time::Duration,
12};
13
14#[path = "transport/memory.rs"]
15mod memory;
16#[path = "transport/proactor.rs"]
17mod proactor;
18pub use memory::MemoryPipe;
19
20pub use crate::http2;
22
23pub trait SyncTransport: Read + Write {
30 fn set_nonblocking(&mut self, nonblocking: bool) -> io::Result<()>;
35
36 fn set_read_timeout(&mut self, timeout: Option<Duration>) -> io::Result<()>;
41
42 fn set_write_timeout(&mut self, timeout: Option<Duration>) -> io::Result<()>;
47
48 fn read_timeout(&self) -> io::Result<Option<Duration>>;
53
54 fn write_timeout(&self) -> io::Result<Option<Duration>>;
59
60 fn peer_endpoint(&self) -> io::Result<String>;
65}
66
67#[derive(Debug, Clone, Copy)]
69pub struct TcpTransportOptions {
70 pub keepalive: Option<Duration>,
72 pub send_buffer_size: Option<usize>,
74 pub recv_buffer_size: Option<usize>,
76 pub nonblocking: bool,
78}
79
80impl Default for TcpTransportOptions {
81 fn default() -> Self {
82 Self {
83 keepalive: Some(Duration::from_secs(60)),
84 send_buffer_size: None,
85 recv_buffer_size: None,
86 nonblocking: false,
87 }
88 }
89}
90
91#[derive(Debug)]
93pub struct TcpTransport(TcpStream);
94
95impl TcpTransport {
96 pub fn connect(address: impl ToSocketAddrs) -> io::Result<Self> {
101 Self::connect_with_options(address, TcpTransportOptions::default())
102 }
103
104 pub fn from_std(stream: TcpStream) -> io::Result<Self> {
109 Self::from_std_with_options(stream, TcpTransportOptions::default())
110 }
111
112 pub fn connect_with_options(
117 address: impl ToSocketAddrs,
118 options: TcpTransportOptions,
119 ) -> io::Result<Self> {
120 let mut last = io::Error::new(io::ErrorKind::InvalidInput, "no socket addresses resolved");
121 for address in address.to_socket_addrs()? {
122 let result = (|| {
123 let socket = socket2::Socket::new(
124 socket2::Domain::for_address(address),
125 socket2::Type::STREAM,
126 Some(socket2::Protocol::TCP),
127 )?;
128 proactor::connect(&socket, address.into())?;
129 Self::from_std_with_options(socket.into(), options)
130 })();
131 match result {
132 Ok(transport) => return Ok(transport),
133 Err(error) => last = error,
134 }
135 }
136 Err(last)
137 }
138
139 pub fn from_std_with_options(
144 stream: TcpStream,
145 options: TcpTransportOptions,
146 ) -> io::Result<Self> {
147 for size in [options.send_buffer_size, options.recv_buffer_size]
148 .into_iter()
149 .flatten()
150 {
151 if size == 0 || size > i32::MAX as usize {
152 return Err(io::Error::new(
153 io::ErrorKind::InvalidInput,
154 "socket buffer size must fit a positive c_int",
155 ));
156 }
157 }
158 stream.set_nodelay(true)?;
159 let socket = socket2::SockRef::from(&stream);
160 socket.set_keepalive(options.keepalive.is_some())?;
161 if let Some(interval) = options.keepalive {
162 if interval.is_zero() {
163 return Err(io::Error::new(
164 io::ErrorKind::InvalidInput,
165 "keepalive interval must be positive",
166 ));
167 }
168 socket.set_tcp_keepalive(&socket2::TcpKeepalive::new().with_time(interval))?;
169 }
170 if let Some(size) = options.send_buffer_size {
171 socket.set_send_buffer_size(size)?;
172 }
173 if let Some(size) = options.recv_buffer_size {
174 socket.set_recv_buffer_size(size)?;
175 }
176 stream.set_nonblocking(options.nonblocking)?;
177 Ok(Self(stream))
178 }
179
180 fn endpoint(&self) -> io::Result<String> {
181 Ok(self.0.peer_addr()?.to_string())
182 }
183
184 pub fn peer_addr(&self) -> io::Result<SocketAddr> {
189 self.0.peer_addr()
190 }
191
192 pub fn local_addr(&self) -> io::Result<SocketAddr> {
197 self.0.local_addr()
198 }
199}
200
201macro_rules! impl_stream_transport {
202 ($transport:ident, $stream:ty) => {
203 impl $transport {
204 pub fn get_ref(&self) -> &$stream {
206 &self.0
207 }
208
209 pub fn into_inner(self) -> $stream {
211 self.0
212 }
213 }
214
215 impl io::Read for $transport {
216 fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
217 proactor::read(
218 &self.0,
219 buffer,
220 self.0.read_timeout()?,
221 proactor::is_nonblocking(&self.0)?,
222 )
223 }
224 }
225
226 impl io::Write for $transport {
227 fn write(&mut self, buffer: &[u8]) -> io::Result<usize> {
228 proactor::write(
229 &self.0,
230 buffer,
231 self.0.write_timeout()?,
232 proactor::is_nonblocking(&self.0)?,
233 )
234 }
235
236 fn flush(&mut self) -> io::Result<()> {
237 Ok(())
238 }
239 }
240
241 impl SyncTransport for $transport {
242 fn set_nonblocking(&mut self, nonblocking: bool) -> io::Result<()> {
243 self.0.set_nonblocking(nonblocking)
244 }
245
246 fn set_read_timeout(&mut self, timeout: Option<Duration>) -> io::Result<()> {
247 self.0.set_read_timeout(timeout)
248 }
249
250 fn set_write_timeout(&mut self, timeout: Option<Duration>) -> io::Result<()> {
251 self.0.set_write_timeout(timeout)
252 }
253
254 fn read_timeout(&self) -> io::Result<Option<Duration>> {
255 self.0.read_timeout()
256 }
257
258 fn write_timeout(&self) -> io::Result<Option<Duration>> {
259 self.0.write_timeout()
260 }
261
262 fn peer_endpoint(&self) -> io::Result<String> {
263 self.endpoint()
264 }
265 }
266 };
267}
268
269impl_stream_transport!(TcpTransport, TcpStream);
270
271#[derive(Debug)]
273pub struct TcpTransportListener(TcpListener);
274
275impl TcpTransportListener {
276 pub fn bind(address: impl ToSocketAddrs) -> io::Result<Self> {
281 let mut last_error =
282 io::Error::new(io::ErrorKind::InvalidInput, "no socket addresses resolved");
283 for address in address.to_socket_addrs()? {
284 let result = (|| {
285 let socket = socket2::Socket::new(
286 socket2::Domain::for_address(address),
287 socket2::Type::STREAM,
288 Some(socket2::Protocol::TCP),
289 )?;
290 socket.set_reuse_address(true)?;
291 socket.bind(&address.into())?;
292 socket.listen(128)?;
293 Ok(Self(socket.into()))
294 })();
295 match result {
296 Ok(listener) => return Ok(listener),
297 Err(error) => last_error = error,
298 }
299 }
300 Err(last_error)
301 }
302}
303
304#[cfg(unix)]
306#[derive(Debug)]
307pub struct UnixTransport(UnixStream);
308
309#[cfg(unix)]
310impl UnixTransport {
311 pub fn connect(path: impl AsRef<std::path::Path>) -> io::Result<Self> {
316 let address = socket2::SockAddr::unix(path)?;
317 let socket = socket2::Socket::new(socket2::Domain::UNIX, socket2::Type::STREAM, None)?;
318 proactor::connect(&socket, address)?;
319 Self::from_std(socket.into())
320 }
321
322 pub fn from_std(stream: UnixStream) -> io::Result<Self> {
327 Ok(Self(stream))
328 }
329
330 fn endpoint(&self) -> io::Result<String> {
331 let address = self.0.peer_addr()?;
332 Ok(match address.as_pathname() {
333 Some(path) => format!("unix:{}", path.display()),
334 None => format!("unix:{address:?}"),
335 })
336 }
337}
338
339#[cfg(unix)]
340impl_stream_transport!(UnixTransport, UnixStream);
341
342#[cfg(unix)]
344#[derive(Debug)]
345pub struct UnixTransportListener(UnixListener);
346
347#[cfg(unix)]
348impl UnixTransportListener {
349 pub fn bind(path: impl AsRef<std::path::Path>) -> io::Result<Self> {
354 Ok(Self(UnixListener::bind(path)?))
355 }
356}
357
358macro_rules! impl_listener {
359 ($wrapper:ident, $listener:ty, $stream:ty, $transport:ident, $address:ty) => {
360 impl $wrapper {
361 pub fn from_std(listener: $listener) -> Self {
363 Self(listener)
364 }
365
366 pub fn accept(&self) -> io::Result<($transport, $address)> {
371 let fd = proactor::accept(&self.0)?;
372 let stream = <$stream>::from(fd);
373 let address = stream.peer_addr()?;
374 Ok(($transport::from_std(stream)?, address))
375 }
376
377 pub fn local_addr(&self) -> io::Result<$address> {
382 self.0.local_addr()
383 }
384
385 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
390 self.0.set_nonblocking(nonblocking)
391 }
392 }
393 };
394}
395impl_listener!(
396 TcpTransportListener,
397 TcpListener,
398 TcpStream,
399 TcpTransport,
400 SocketAddr
401);
402#[cfg(unix)]
403impl_listener!(
404 UnixTransportListener,
405 UnixListener,
406 UnixStream,
407 UnixTransport,
408 UnixSocketAddr
409);
410
411#[cfg(test)]
412#[path = "../tests/unit/transport.rs"]
413mod tests;