]> git.lizzy.rs Git - connect-rs.git/blob - src/tls/listener.rs
047dcae88dbbe301aea273d921c18d3a7b2b432f
[connect-rs.git] / src / tls / listener.rs
1 use crate::tls::TlsConnectionMetadata;
2 use crate::Connection;
3 use async_std::net::{SocketAddr, TcpListener, ToSocketAddrs};
4 use async_std::pin::Pin;
5 use async_std::task::{Context, Poll};
6 use async_tls::TlsAcceptor;
7 use futures::{Stream, StreamExt};
8 use log::*;
9
10 /// Listens on a bound socket for incoming TLS connections to be handled as independent
11 /// [`Connection`]s.
12 ///
13 /// Implements the [`Stream`] trait to asynchronously accept incoming TLS connections.
14 ///
15 /// # Example
16 ///
17 /// Basic usage:
18 ///
19 /// ```ignore
20 /// let mut server = TlsListener::bind("127.0.0.1:3456", config.into()).await?;
21 ///
22 /// // wait for a connection to come in and be accepted
23 /// while let Some(mut conn) = server.next().await {
24 ///     // do something with connection
25 /// }
26 /// ```
27 #[allow(dead_code)]
28 pub struct TlsListener {
29     local_addrs: SocketAddr,
30     listener: TcpListener,
31     acceptor: TlsAcceptor,
32 }
33
34 impl TlsListener {
35     /// Creates a [`TlsListener`] by binding to an IP address and port and listens for incoming TLS
36     /// connections that have successfully been accepted.
37     ///
38     /// # Example
39     ///
40     /// Basic usage:
41     ///
42     /// ```ignore
43     /// let mut server = TlsListener::bind("127.0.0.1:3456", config.into()).await?;
44     /// ```
45     pub async fn bind<A: ToSocketAddrs + std::fmt::Display>(
46         ip_addrs: A,
47         acceptor: TlsAcceptor,
48     ) -> anyhow::Result<Self> {
49         let listener = TcpListener::bind(ip_addrs).await?;
50         info!("Started TLS server at {}", listener.local_addr()?);
51
52         Ok(Self {
53             local_addrs: listener.local_addr()?,
54             listener,
55             acceptor,
56         })
57     }
58
59     /// Creates a [`Connection`] for the next `accept`ed TCP connection at the bound socket.
60     ///
61     /// # Example
62     ///
63     /// Basic usage:
64     ///
65     /// ```ignore
66     /// let mut server = TlsListener::bind("127.0.0.1:3456", config.into()).await?;
67     /// while let Some(mut conn) = server.next().await {
68     ///     // do something with connection
69     /// }
70     /// ```
71     pub async fn accept(&self) -> anyhow::Result<Connection> {
72         let (tcp_stream, peer_addr) = self.listener.accept().await?;
73         debug!("Received connection attempt from {}", peer_addr);
74
75         match self.acceptor.accept(tcp_stream).await {
76             Ok(tls_stream) => {
77                 debug!("Completed TLS handshake with {}", peer_addr);
78                 Ok(Connection::from(TlsConnectionMetadata::Listener {
79                     local_addr: self.local_addrs.clone(),
80                     peer_addr,
81                     stream: tls_stream,
82                 }))
83             }
84
85             Err(e) => {
86                 warn!("Could not encrypt connection with TLS from {}", peer_addr);
87                 Err(anyhow::Error::new(e))
88             }
89         }
90     }
91 }
92
93 impl Stream for TlsListener {
94     type Item = Connection;
95
96     fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
97         match futures::executor::block_on(self.listener.incoming().next()) {
98             Some(Ok(tcp_stream)) => {
99                 let peer_addr = tcp_stream
100                     .peer_addr()
101                     .expect("Could not retrieve peer IP address");
102                 debug!("Received connection attempt from {}", peer_addr);
103
104                 match futures::executor::block_on(self.acceptor.accept(tcp_stream)) {
105                     Ok(tls_stream) => {
106                         debug!("Completed TLS handshake with {}", peer_addr);
107                         Poll::Ready(Some(Connection::from(TlsConnectionMetadata::Listener {
108                             local_addr: self.local_addrs.clone(),
109                             peer_addr,
110                             stream: tls_stream,
111                         })))
112                     }
113
114                     Err(_e) => {
115                         warn!("Could not encrypt connection with TLS from {}", peer_addr);
116                         Poll::Pending
117                     }
118                 }
119             }
120
121             Some(Err(e)) => {
122                 error!(
123                     "Encountered error when trying to accept new connection {}",
124                     e
125                 );
126                 Poll::Pending
127             }
128
129             None => Poll::Ready(None),
130         }
131     }
132 }