diff --git a/tonic/src/transport/server/incoming.rs b/tonic/src/transport/server/incoming.rs index 686aef197..c8434fd34 100644 --- a/tonic/src/transport/server/incoming.rs +++ b/tonic/src/transport/server/incoming.rs @@ -127,12 +127,48 @@ enum SelectOutput { Done, } -pub(crate) struct TcpIncoming { +/// Binds a socket address for a [Router](super::Router) +/// +/// An incoming stream, usable with [Router::serve_with_incoming](super::Router::serve_with_incoming), +/// of `AsyncRead + AsyncWrite` that communicate with clients that connect to a socket address. +#[derive(Debug)] +pub struct TcpIncoming { inner: AddrIncoming, } impl TcpIncoming { - pub(crate) fn new( + /// Creates an instance by binding (opening) the specified socket address + /// to which the specified TCP 'nodelay' and 'keepalive' parameters are applied. + /// Returns a TcpIncoming if the socket address was successfully bound. + /// + /// # Examples + /// ```no_run + /// # use tower_service::Service; + /// # use http::{request::Request, response::Response}; + /// # use tonic::{body::BoxBody, transport::{Body, NamedService, Server, server::TcpIncoming}}; + /// # use core::convert::Infallible; + /// # use std::error::Error; + /// # fn main() { } // Cannot have type parameters, hence instead define: + /// # fn run(some_service: S) -> Result<(), Box> + /// # where + /// # S: Service, Response = Response, Error = Infallible> + NamedService + Clone + Send + 'static, + /// # S::Future: Send + 'static, + /// # { + /// // Find a free port + /// let mut port = 1322; + /// let tinc = loop { + /// let addr = format!("127.0.0.1:{}", port).parse().unwrap(); + /// match TcpIncoming::new(addr, true, None) { + /// Ok(t) => break t, + /// Err(_) => port += 1 + /// } + /// }; + /// Server::builder() + /// .add_service(some_service) + /// .serve_with_incoming(tinc); + /// # Ok(()) + /// # } + pub fn new( addr: SocketAddr, nodelay: bool, keepalive: Option, @@ -151,3 +187,17 @@ impl Stream for TcpIncoming { Pin::new(&mut self.inner).poll_accept(cx) } } + +#[cfg(test)] +mod tests { + use crate::transport::server::TcpIncoming; + #[tokio::test] + async fn one_tcpincoming_at_a_time() { + let addr = "127.0.0.1:1322".parse().unwrap(); + { + let _t1 = TcpIncoming::new(addr, true, None).unwrap(); + let _t2 = TcpIncoming::new(addr, true, None).unwrap_err(); + } + let _t3 = TcpIncoming::new(addr, true, None).unwrap(); + } +} diff --git a/tonic/src/transport/server/mod.rs b/tonic/src/transport/server/mod.rs index 8754b6e2e..b05f78049 100644 --- a/tonic/src/transport/server/mod.rs +++ b/tonic/src/transport/server/mod.rs @@ -24,7 +24,7 @@ use super::service::TlsAcceptor; #[cfg(unix)] pub use unix::UdsConnectInfo; -use incoming::TcpIncoming; +pub use incoming::TcpIncoming; #[cfg(feature = "tls")] pub(crate) use tokio_rustls::server::TlsStream;