use std::{net::SocketAddr, time::Duration};
#[derive(Debug, Clone, Default)]
pub struct TcpSocketOpts {
pub send_buffer_size: Option<u32>,
pub recv_buffer_size: Option<u32>,
pub nodelay: bool,
pub fastopen: bool,
pub keepalive: Option<Duration>,
pub mptcp: bool,
}
#[derive(Debug, Clone, Default)]
pub struct UdpSocketOpts {
pub mtu: Option<usize>,
pub allow_fragmentation: bool,
}
#[derive(Debug, Clone, Default)]
pub struct ConnectOpts {
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fwmark: Option<u32>,
#[cfg(target_os = "freebsd")]
pub user_cookie: Option<u32>,
#[cfg(target_os = "android")]
pub vpn_protect_path: Option<std::path::PathBuf>,
#[cfg(target_os = "android")]
pub vpn_socket_protect: Option<std::sync::Arc<Box<dyn android::SocketProtect + Send + Sync>>>,
pub bind_local_addr: Option<SocketAddr>,
pub bind_interface: Option<String>,
pub tcp: TcpSocketOpts,
pub udp: UdpSocketOpts,
}
#[derive(Clone, Debug, Default)]
pub struct AcceptOpts {
pub tcp: TcpSocketOpts,
pub udp: UdpSocketOpts,
pub ipv6_only: bool,
}
#[cfg(target_os = "android")]
impl ConnectOpts {
pub fn set_vpn_socket_protect<F>(&mut self, f: F)
where
F: android::MakeSocketProtect + Send + Sync + 'static,
F::SocketProtectType: android::SocketProtect + Send + Sync + 'static,
{
self.vpn_socket_protect = Some(std::sync::Arc::new(Box::new(f.make_socket_protect())));
}
}
#[cfg(target_os = "android")]
pub mod android {
use sealed::sealed;
use std::{fmt, io, os::unix::io::RawFd};
#[sealed]
pub trait SocketProtect {
fn protect(&self, fd: RawFd) -> io::Result<()>;
}
impl fmt::Debug for dyn SocketProtect + Send + Sync {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SocketProtect").finish_non_exhaustive()
}
}
#[sealed]
pub trait MakeSocketProtect {
type SocketProtectType: SocketProtect;
fn make_socket_protect(self) -> Self::SocketProtectType;
}
pub struct SocketProtectFn<F> {
f: F,
}
#[sealed]
impl<F> SocketProtect for SocketProtectFn<F>
where
F: Fn(RawFd) -> io::Result<()> + Send + Sync + 'static,
{
fn protect(&self, fd: RawFd) -> io::Result<()> {
(self.f)(fd)
}
}
#[sealed]
impl<F> MakeSocketProtect for F
where
F: Fn(RawFd) -> io::Result<()> + Send + Sync + 'static,
{
type SocketProtectType = SocketProtectFn<F>;
fn make_socket_protect(self) -> Self::SocketProtectType {
SocketProtectFn { f: self }
}
}
}