tonic/transport/server/conn.rs
1/*
2 *
3 * Copyright 2025 gRPC authors.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 */
24
25use std::net::SocketAddr;
26use tokio::net::TcpStream;
27
28#[cfg(feature = "tls-connect-info")]
29use std::sync::Arc;
30#[cfg(feature = "tls-connect-info")]
31use tokio_rustls::rustls::pki_types::CertificateDer;
32#[cfg(feature = "tls-connect-info")]
33use tokio_rustls::server::TlsStream;
34
35/// Trait that connected IO resources implement and use to produce info about the connection.
36///
37/// The goal for this trait is to allow users to implement
38/// custom IO types that can still provide the same connection
39/// metadata.
40///
41/// # Example
42///
43/// The `ConnectInfo` returned will be accessible through [request extensions][ext]:
44///
45/// ```
46/// use tonic::{Request, transport::server::Connected};
47///
48/// // A `Stream` that yields connections
49/// struct MyConnector {}
50///
51/// // Return metadata about the connection as `MyConnectInfo`
52/// impl Connected for MyConnector {
53/// type ConnectInfo = MyConnectInfo;
54///
55/// fn connect_info(&self) -> Self::ConnectInfo {
56/// MyConnectInfo {}
57/// }
58/// }
59///
60/// #[derive(Clone)]
61/// struct MyConnectInfo {
62/// // Metadata about your connection
63/// }
64///
65/// // The connect info can be accessed through request extensions:
66/// # fn foo(request: Request<()>) {
67/// let connect_info: &MyConnectInfo = request
68/// .extensions()
69/// .get::<MyConnectInfo>()
70/// .expect("bug in tonic");
71/// # }
72/// ```
73///
74/// [ext]: crate::Request::extensions
75pub trait Connected {
76 /// The connection info type the IO resources generates.
77 // all these bounds are necessary to set this as a request extension
78 type ConnectInfo: Clone + Send + Sync + 'static;
79
80 /// Create type holding information about the connection.
81 fn connect_info(&self) -> Self::ConnectInfo;
82}
83
84/// Connection info for standard TCP streams.
85///
86/// This type will be accessible through [request extensions][ext] if you're using the default
87/// non-TLS connector.
88///
89/// See [`Connected`] for more details.
90///
91/// [ext]: crate::Request::extensions
92#[derive(Debug, Clone)]
93pub struct TcpConnectInfo {
94 /// Returns the local address of this connection.
95 pub local_addr: Option<SocketAddr>,
96 /// Returns the remote (peer) address of this connection.
97 pub remote_addr: Option<SocketAddr>,
98}
99
100impl TcpConnectInfo {
101 /// Return the local address the IO resource is connected.
102 pub fn local_addr(&self) -> Option<SocketAddr> {
103 self.local_addr
104 }
105
106 /// Return the remote address the IO resource is connected too.
107 pub fn remote_addr(&self) -> Option<SocketAddr> {
108 self.remote_addr
109 }
110}
111
112impl Connected for TcpStream {
113 type ConnectInfo = TcpConnectInfo;
114
115 fn connect_info(&self) -> Self::ConnectInfo {
116 TcpConnectInfo {
117 local_addr: self.local_addr().ok(),
118 remote_addr: self.peer_addr().ok(),
119 }
120 }
121}
122
123impl Connected for tokio::io::DuplexStream {
124 type ConnectInfo = ();
125
126 fn connect_info(&self) -> Self::ConnectInfo {}
127}
128
129#[cfg(feature = "tls-connect-info")]
130impl<T> Connected for TlsStream<T>
131where
132 T: Connected,
133{
134 type ConnectInfo = TlsConnectInfo<T::ConnectInfo>;
135
136 fn connect_info(&self) -> Self::ConnectInfo {
137 let (inner, session) = self.get_ref();
138 let inner = inner.connect_info();
139
140 let certs = session
141 .peer_certificates()
142 .map(|certs| certs.to_owned().into());
143
144 TlsConnectInfo { inner, certs }
145 }
146}
147
148/// Connection info for TLS streams.
149///
150/// This type will be accessible through [request extensions][ext] if you're using a TLS connector.
151///
152/// See [`Connected`] for more details.
153///
154/// [ext]: crate::Request::extensions
155#[cfg(feature = "tls-connect-info")]
156#[derive(Debug, Clone)]
157pub struct TlsConnectInfo<T> {
158 inner: T,
159 certs: Option<Arc<Vec<CertificateDer<'static>>>>,
160}
161
162#[cfg(feature = "tls-connect-info")]
163impl<T> TlsConnectInfo<T> {
164 /// Get a reference to the underlying connection info.
165 pub fn get_ref(&self) -> &T {
166 &self.inner
167 }
168
169 /// Get a mutable reference to the underlying connection info.
170 pub fn get_mut(&mut self) -> &mut T {
171 &mut self.inner
172 }
173
174 /// Return the set of connected peer TLS certificates.
175 pub fn peer_certs(&self) -> Option<Arc<Vec<CertificateDer<'static>>>> {
176 self.certs.clone()
177 }
178}