pingora_core/protocols/
digest.rs

1// Copyright 2024 Cloudflare, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Extra information about the connection
16
17use std::sync::Arc;
18use std::time::{Duration, SystemTime};
19
20use once_cell::sync::OnceCell;
21
22use super::l4::ext::{get_original_dest, get_recv_buf, get_tcp_info, TCP_INFO};
23use super::l4::socket::SocketAddr;
24use super::raw_connect::ProxyDigest;
25use super::tls::digest::SslDigest;
26
27/// The information can be extracted from a connection
28#[derive(Clone, Debug, Default)]
29pub struct Digest {
30    /// Information regarding the TLS of this connection if any
31    pub ssl_digest: Option<Arc<SslDigest>>,
32    /// Timing information
33    pub timing_digest: Vec<Option<TimingDigest>>,
34    /// information regarding the CONNECT proxy this connection uses.
35    pub proxy_digest: Option<Arc<ProxyDigest>>,
36    /// Information about underlying socket/fd of this connection
37    pub socket_digest: Option<Arc<SocketDigest>>,
38}
39
40/// The interface to return protocol related information
41pub trait ProtoDigest {
42    fn get_digest(&self) -> Option<&Digest> {
43        None
44    }
45}
46
47/// The timing information of the connection
48#[derive(Clone, Debug)]
49pub struct TimingDigest {
50    /// When this connection was established
51    pub established_ts: SystemTime,
52}
53
54impl Default for TimingDigest {
55    fn default() -> Self {
56        TimingDigest {
57            established_ts: SystemTime::UNIX_EPOCH,
58        }
59    }
60}
61
62#[derive(Debug)]
63/// The interface to return socket-related information
64pub struct SocketDigest {
65    #[cfg(unix)]
66    raw_fd: std::os::unix::io::RawFd,
67    #[cfg(windows)]
68    raw_sock: std::os::windows::io::RawSocket,
69    /// Remote socket address
70    pub peer_addr: OnceCell<Option<SocketAddr>>,
71    /// Local socket address
72    pub local_addr: OnceCell<Option<SocketAddr>>,
73    /// Original destination address
74    pub original_dst: OnceCell<Option<SocketAddr>>,
75}
76
77impl SocketDigest {
78    #[cfg(unix)]
79    pub fn from_raw_fd(raw_fd: std::os::unix::io::RawFd) -> SocketDigest {
80        SocketDigest {
81            raw_fd,
82            peer_addr: OnceCell::new(),
83            local_addr: OnceCell::new(),
84            original_dst: OnceCell::new(),
85        }
86    }
87
88    #[cfg(windows)]
89    pub fn from_raw_socket(raw_sock: std::os::windows::io::RawSocket) -> SocketDigest {
90        SocketDigest {
91            raw_sock,
92            peer_addr: OnceCell::new(),
93            local_addr: OnceCell::new(),
94            original_dst: OnceCell::new(),
95        }
96    }
97
98    #[cfg(unix)]
99    pub fn peer_addr(&self) -> Option<&SocketAddr> {
100        self.peer_addr
101            .get_or_init(|| SocketAddr::from_raw_fd(self.raw_fd, true))
102            .as_ref()
103    }
104
105    #[cfg(windows)]
106    pub fn peer_addr(&self) -> Option<&SocketAddr> {
107        self.peer_addr
108            .get_or_init(|| SocketAddr::from_raw_socket(self.raw_sock, true))
109            .as_ref()
110    }
111
112    #[cfg(unix)]
113    pub fn local_addr(&self) -> Option<&SocketAddr> {
114        self.local_addr
115            .get_or_init(|| SocketAddr::from_raw_fd(self.raw_fd, false))
116            .as_ref()
117    }
118
119    #[cfg(windows)]
120    pub fn local_addr(&self) -> Option<&SocketAddr> {
121        self.local_addr
122            .get_or_init(|| SocketAddr::from_raw_socket(self.raw_sock, false))
123            .as_ref()
124    }
125
126    fn is_inet(&self) -> bool {
127        self.local_addr().and_then(|p| p.as_inet()).is_some()
128    }
129
130    #[cfg(unix)]
131    pub fn tcp_info(&self) -> Option<TCP_INFO> {
132        if self.is_inet() {
133            get_tcp_info(self.raw_fd).ok()
134        } else {
135            None
136        }
137    }
138
139    #[cfg(windows)]
140    pub fn tcp_info(&self) -> Option<TCP_INFO> {
141        if self.is_inet() {
142            get_tcp_info(self.raw_sock).ok()
143        } else {
144            None
145        }
146    }
147
148    #[cfg(unix)]
149    pub fn get_recv_buf(&self) -> Option<usize> {
150        if self.is_inet() {
151            get_recv_buf(self.raw_fd).ok()
152        } else {
153            None
154        }
155    }
156
157    #[cfg(windows)]
158    pub fn get_recv_buf(&self) -> Option<usize> {
159        if self.is_inet() {
160            get_recv_buf(self.raw_sock).ok()
161        } else {
162            None
163        }
164    }
165
166    #[cfg(unix)]
167    pub fn original_dst(&self) -> Option<&SocketAddr> {
168        self.original_dst
169            .get_or_init(|| {
170                get_original_dest(self.raw_fd)
171                    .ok()
172                    .flatten()
173                    .map(SocketAddr::Inet)
174            })
175            .as_ref()
176    }
177
178    #[cfg(windows)]
179    pub fn original_dst(&self) -> Option<&SocketAddr> {
180        self.original_dst
181            .get_or_init(|| {
182                get_original_dest(self.raw_sock)
183                    .ok()
184                    .flatten()
185                    .map(SocketAddr::Inet)
186            })
187            .as_ref()
188    }
189}
190
191/// The interface to return timing information
192pub trait GetTimingDigest {
193    /// Return the timing for each layer from the lowest layer to upper
194    fn get_timing_digest(&self) -> Vec<Option<TimingDigest>>;
195    fn get_read_pending_time(&self) -> Duration {
196        Duration::ZERO
197    }
198    fn get_write_pending_time(&self) -> Duration {
199        Duration::ZERO
200    }
201}
202
203/// The interface to set or return proxy information
204pub trait GetProxyDigest {
205    fn get_proxy_digest(&self) -> Option<Arc<ProxyDigest>>;
206    fn set_proxy_digest(&mut self, _digest: ProxyDigest) {}
207}
208
209/// The interface to set or return socket information
210pub trait GetSocketDigest {
211    fn get_socket_digest(&self) -> Option<Arc<SocketDigest>>;
212    fn set_socket_digest(&mut self, _socket_digest: SocketDigest) {}
213}