pingora_core/protocols/
digest.rsuse std::sync::Arc;
use std::time::{Duration, SystemTime};
use once_cell::sync::OnceCell;
use super::l4::ext::{get_original_dest, get_recv_buf, get_tcp_info, TCP_INFO};
use super::l4::socket::SocketAddr;
use super::raw_connect::ProxyDigest;
use super::tls::digest::SslDigest;
#[derive(Clone, Debug, Default)]
pub struct Digest {
pub ssl_digest: Option<Arc<SslDigest>>,
pub timing_digest: Vec<Option<TimingDigest>>,
pub proxy_digest: Option<Arc<ProxyDigest>>,
pub socket_digest: Option<Arc<SocketDigest>>,
}
pub trait ProtoDigest {
fn get_digest(&self) -> Option<&Digest> {
None
}
}
#[derive(Clone, Debug)]
pub struct TimingDigest {
pub established_ts: SystemTime,
}
impl Default for TimingDigest {
fn default() -> Self {
TimingDigest {
established_ts: SystemTime::UNIX_EPOCH,
}
}
}
#[derive(Debug)]
pub struct SocketDigest {
#[cfg(unix)]
raw_fd: std::os::unix::io::RawFd,
#[cfg(windows)]
raw_sock: std::os::windows::io::RawSocket,
pub peer_addr: OnceCell<Option<SocketAddr>>,
pub local_addr: OnceCell<Option<SocketAddr>>,
pub original_dst: OnceCell<Option<SocketAddr>>,
}
impl SocketDigest {
#[cfg(unix)]
pub fn from_raw_fd(raw_fd: std::os::unix::io::RawFd) -> SocketDigest {
SocketDigest {
raw_fd,
peer_addr: OnceCell::new(),
local_addr: OnceCell::new(),
original_dst: OnceCell::new(),
}
}
#[cfg(windows)]
pub fn from_raw_socket(raw_sock: std::os::windows::io::RawSocket) -> SocketDigest {
SocketDigest {
raw_sock,
peer_addr: OnceCell::new(),
local_addr: OnceCell::new(),
original_dst: OnceCell::new(),
}
}
#[cfg(unix)]
pub fn peer_addr(&self) -> Option<&SocketAddr> {
self.peer_addr
.get_or_init(|| SocketAddr::from_raw_fd(self.raw_fd, true))
.as_ref()
}
#[cfg(windows)]
pub fn peer_addr(&self) -> Option<&SocketAddr> {
self.peer_addr
.get_or_init(|| SocketAddr::from_raw_socket(self.raw_sock, true))
.as_ref()
}
#[cfg(unix)]
pub fn local_addr(&self) -> Option<&SocketAddr> {
self.local_addr
.get_or_init(|| SocketAddr::from_raw_fd(self.raw_fd, false))
.as_ref()
}
#[cfg(windows)]
pub fn local_addr(&self) -> Option<&SocketAddr> {
self.local_addr
.get_or_init(|| SocketAddr::from_raw_socket(self.raw_sock, false))
.as_ref()
}
fn is_inet(&self) -> bool {
self.local_addr().and_then(|p| p.as_inet()).is_some()
}
#[cfg(unix)]
pub fn tcp_info(&self) -> Option<TCP_INFO> {
if self.is_inet() {
get_tcp_info(self.raw_fd).ok()
} else {
None
}
}
#[cfg(windows)]
pub fn tcp_info(&self) -> Option<TCP_INFO> {
if self.is_inet() {
get_tcp_info(self.raw_sock).ok()
} else {
None
}
}
#[cfg(unix)]
pub fn get_recv_buf(&self) -> Option<usize> {
if self.is_inet() {
get_recv_buf(self.raw_fd).ok()
} else {
None
}
}
#[cfg(windows)]
pub fn get_recv_buf(&self) -> Option<usize> {
if self.is_inet() {
get_recv_buf(self.raw_sock).ok()
} else {
None
}
}
#[cfg(unix)]
pub fn original_dst(&self) -> Option<&SocketAddr> {
self.original_dst
.get_or_init(|| {
get_original_dest(self.raw_fd)
.ok()
.flatten()
.map(SocketAddr::Inet)
})
.as_ref()
}
#[cfg(windows)]
pub fn original_dst(&self) -> Option<&SocketAddr> {
self.original_dst
.get_or_init(|| {
get_original_dest(self.raw_sock)
.ok()
.flatten()
.map(SocketAddr::Inet)
})
.as_ref()
}
}
pub trait GetTimingDigest {
fn get_timing_digest(&self) -> Vec<Option<TimingDigest>>;
fn get_read_pending_time(&self) -> Duration {
Duration::ZERO
}
fn get_write_pending_time(&self) -> Duration {
Duration::ZERO
}
}
pub trait GetProxyDigest {
fn get_proxy_digest(&self) -> Option<Arc<ProxyDigest>>;
fn set_proxy_digest(&mut self, _digest: ProxyDigest) {}
}
pub trait GetSocketDigest {
fn get_socket_digest(&self) -> Option<Arc<SocketDigest>>;
fn set_socket_digest(&mut self, _socket_digest: SocketDigest) {}
}