mod host_bridge;
mod pool;
mod stream;
use std::path::Path;
pub use host_bridge::*;
pub use pool::*;
pub use stream::*;
#[cfg(not(target_os = "macos"))]
use nix::sys::socket::VsockAddr;
use nix::sys::socket::{AddressFamily, SockaddrLike, UnixAddr};
pub use nix::sys::time::{TimeVal, TimeValLike};
#[derive(Debug)]
pub enum IOError {
StdIoError(std::io::Error),
NixError(nix::Error),
ArithmeticSaturation,
UnknownError,
DisconnectedStream,
ConnectAddressInvalid,
ConnectTimeout,
RecvTimeout,
RecvInterrupted,
RecvConnectionClosed,
ConnectNixError(nix::Error),
SendNixError(nix::Error),
RecvNixError(nix::Error),
OversizedPayload(usize),
PoolError(PoolError),
UnexpectedProxyConnection,
MissingProxyConnection,
}
impl From<nix::Error> for IOError {
fn from(err: nix::Error) -> Self {
Self::NixError(err)
}
}
impl From<std::io::Error> for IOError {
fn from(err: std::io::Error) -> Self {
Self::StdIoError(err)
}
}
impl From<PoolError> for IOError {
fn from(value: PoolError) -> Self {
Self::PoolError(value)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SocketAddress {
#[cfg(not(target_os = "macos"))]
Vsock(VsockAddr),
Unix(UnixAddr),
}
pub const VMADDR_FLAG_TO_HOST: u8 = 0x01;
pub const VMADDR_NO_FLAGS: u8 = 0x00;
impl SocketAddress {
#[must_use]
pub fn new_unix<P: AsRef<Path>>(path: P) -> Self {
let addr = UnixAddr::new(path.as_ref()).unwrap();
Self::Unix(addr)
}
#[cfg(not(target_os = "macos"))]
#[must_use]
pub fn new_vsock(cid: u32, port: u32, flags: u8) -> Self {
Self::Vsock(Self::new_vsock_raw(cid, port, flags))
}
#[cfg(not(target_os = "macos"))]
#[allow(unsafe_code)]
#[must_use]
pub fn new_vsock_raw(cid: u32, port: u32, flags: u8) -> VsockAddr {
let vsock_addr = SockAddrVm {
svm_family: AddressFamily::Vsock as libc::sa_family_t,
svm_reserved1: 0,
svm_cid: cid,
svm_port: port,
svm_flags: flags,
svm_zero: [0; 3],
};
let vsock_addr_len = libc::socklen_t::try_from(size_of::<SockAddrVm>())
.expect("SockAddrVm size fits in socklen_t");
unsafe {
VsockAddr::from_raw(
std::ptr::from_ref(&vsock_addr).cast::<libc::sockaddr>(),
Some(vsock_addr_len),
)
.expect("constructed vsock sockaddr is valid")
}
}
#[must_use]
pub fn family(&self) -> AddressFamily {
match *self {
#[cfg(not(target_os = "macos"))]
Self::Vsock(_) => AddressFamily::Vsock,
Self::Unix(_) => AddressFamily::Unix,
}
}
#[must_use]
pub fn addr(&self) -> Box<dyn SockaddrLike> {
match *self {
#[cfg(not(target_os = "macos"))]
Self::Vsock(vsa) => Box::new(vsa),
Self::Unix(ua) => Box::new(ua),
}
}
#[must_use]
pub fn usock(&self) -> &UnixAddr {
match self {
Self::Unix(usock) => usock,
#[cfg(not(target_os = "macos"))]
Self::Vsock(_) => panic!("invalid socket address requested"),
}
}
#[must_use]
#[cfg(not(target_os = "macos"))]
pub fn vsock(&self) -> &VsockAddr {
match self {
Self::Vsock(vsock) => vsock,
Self::Unix(_) => panic!("invalid socket address requested"),
}
}
#[allow(unused)]
pub fn with_port(&self, port: u16) -> Result<SocketAddress, IOError> {
match self {
#[cfg(not(target_os = "macos"))]
Self::Vsock(vsa) => Ok(Self::new_vsock(
vsa.cid(),
port.into(),
vsock_svm_flags(vsa),
)),
Self::Unix(ua) => {
let mut path = ua
.path()
.ok_or(IOError::ConnectAddressInvalid)?
.as_os_str()
.to_owned();
path.push(format!(".{port}.appsock"));
Ok(Self::new_unix(
path.to_str().ok_or(IOError::ConnectAddressInvalid)?,
))
}
}
}
}
impl std::fmt::Display for SocketAddress {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
#[cfg(not(target_os = "macos"))]
Self::Vsock(vsock) => {
write!(f, "vsock cid: {} port: {}", vsock.cid(), vsock.port())
}
Self::Unix(usock) => {
write!(
f,
"usock path: {}",
usock
.path()
.unwrap_or(&std::path::PathBuf::from("unknown/error"))
.as_os_str()
.to_str()
.unwrap_or("unable to procure")
)
}
}
}
}
#[cfg(not(target_os = "macos"))]
#[must_use]
#[allow(unsafe_code)]
pub fn vsock_svm_flags(vsock: &VsockAddr) -> u8 {
unsafe {
let cast: SockAddrVm = std::mem::transmute(*vsock);
cast.svm_flags
}
}
#[cfg(not(target_os = "macos"))]
#[repr(C)]
#[allow(clippy::struct_field_names)]
pub(crate) struct SockAddrVm {
pub(crate) svm_family: libc::sa_family_t,
pub(crate) svm_reserved1: libc::c_ushort,
pub(crate) svm_port: libc::c_uint,
pub(crate) svm_cid: libc::c_uint,
pub(crate) svm_flags: u8,
pub(crate) svm_zero: [u8; 3],
}