compio_quic/
incoming.rs

1use std::{
2    future::{Future, IntoFuture},
3    net::{IpAddr, SocketAddr},
4    pin::Pin,
5    task::{Context, Poll},
6};
7
8use futures_util::FutureExt;
9use quinn_proto::ServerConfig;
10use thiserror::Error;
11
12use crate::{Connecting, Connection, ConnectionError, EndpointRef};
13
14#[derive(Debug)]
15pub(crate) struct IncomingInner {
16    pub(crate) incoming: quinn_proto::Incoming,
17    pub(crate) endpoint: EndpointRef,
18}
19
20/// An incoming connection for which the server has not yet begun its part
21/// of the handshake.
22#[derive(Debug)]
23pub struct Incoming(Option<IncomingInner>);
24
25impl Incoming {
26    pub(crate) fn new(incoming: quinn_proto::Incoming, endpoint: EndpointRef) -> Self {
27        Self(Some(IncomingInner { incoming, endpoint }))
28    }
29
30    /// Attempt to accept this incoming connection (an error may still
31    /// occur).
32    pub fn accept(mut self) -> Result<Connecting, ConnectionError> {
33        let inner = self.0.take().unwrap();
34        Ok(inner.endpoint.accept(inner.incoming, None)?)
35    }
36
37    /// Accept this incoming connection using a custom configuration.
38    ///
39    /// See [`accept()`] for more details.
40    ///
41    /// [`accept()`]: Incoming::accept
42    pub fn accept_with(
43        mut self,
44        server_config: ServerConfig,
45    ) -> Result<Connecting, ConnectionError> {
46        let inner = self.0.take().unwrap();
47        Ok(inner.endpoint.accept(inner.incoming, Some(server_config))?)
48    }
49
50    /// Reject this incoming connection attempt.
51    pub fn refuse(mut self) {
52        let inner = self.0.take().unwrap();
53        inner.endpoint.refuse(inner.incoming);
54    }
55
56    /// Respond with a retry packet, requiring the client to retry with
57    /// address validation.
58    ///
59    /// Errors if `remote_address_validated()` is true.
60    #[allow(clippy::result_large_err)]
61    pub fn retry(mut self) -> Result<(), RetryError> {
62        let inner = self.0.take().unwrap();
63        inner
64            .endpoint
65            .retry(inner.incoming)
66            .map_err(|e| RetryError(Self::new(e.into_incoming(), inner.endpoint)))
67    }
68
69    /// Ignore this incoming connection attempt, not sending any packet in
70    /// response.
71    pub fn ignore(mut self) {
72        let inner = self.0.take().unwrap();
73        inner.endpoint.ignore(inner.incoming);
74    }
75
76    /// The local IP address which was used when the peer established
77    /// the connection.
78    pub fn local_ip(&self) -> Option<IpAddr> {
79        self.0.as_ref().unwrap().incoming.local_ip()
80    }
81
82    /// The peer's UDP address.
83    pub fn remote_address(&self) -> SocketAddr {
84        self.0.as_ref().unwrap().incoming.remote_address()
85    }
86
87    /// Whether the socket address that is initiating this connection has
88    /// been validated.
89    ///
90    /// This means that the sender of the initial packet has proved that
91    /// they can receive traffic sent to `self.remote_address()`.
92    pub fn remote_address_validated(&self) -> bool {
93        self.0.as_ref().unwrap().incoming.remote_address_validated()
94    }
95}
96
97impl Drop for Incoming {
98    fn drop(&mut self) {
99        // Implicit reject, similar to Connection's implicit close
100        if let Some(inner) = self.0.take() {
101            inner.endpoint.refuse(inner.incoming);
102        }
103    }
104}
105
106/// Error for attempting to retry an [`Incoming`] which already bears an
107/// address validation token from a previous retry.
108#[derive(Debug, Error)]
109#[error("retry() with validated Incoming")]
110pub struct RetryError(Incoming);
111
112impl RetryError {
113    /// Get the [`Incoming`]
114    pub fn into_incoming(self) -> Incoming {
115        self.0
116    }
117}
118
119/// Basic adapter to let [`Incoming`] be `await`-ed like a [`Connecting`].
120#[derive(Debug)]
121pub struct IncomingFuture(Result<Connecting, ConnectionError>);
122
123impl Future for IncomingFuture {
124    type Output = Result<Connection, ConnectionError>;
125
126    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
127        match &mut self.0 {
128            Ok(connecting) => connecting.poll_unpin(cx),
129            Err(e) => Poll::Ready(Err(e.clone())),
130        }
131    }
132}
133
134impl IntoFuture for Incoming {
135    type IntoFuture = IncomingFuture;
136    type Output = Result<Connection, ConnectionError>;
137
138    fn into_future(self) -> Self::IntoFuture {
139        IncomingFuture(self.accept())
140    }
141}