slings 0.3.47

A small async runtime based on io-uring for Rust
Documentation
pub(crate) mod listener;
pub(crate) mod packet;
pub(crate) mod socketaddr;
pub(crate) mod stream;

pub(crate) use listener::Listener;
pub(crate) use packet::Packet;
pub(crate) use stream::Stream;

use std::io;
use std::mem;
use std::net::SocketAddr;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::path::Path;

use socket2::SockAddr;

pub(crate) struct SocketStorage {
    pub(crate) storage: libc::sockaddr_storage,
    pub(crate) socklen: libc::socklen_t,
}

pub(crate) struct Socket {
    fd: RawFd,
}

fn get_domain(socket_addr: SocketAddr) -> libc::c_int {
    match socket_addr {
        SocketAddr::V4(_) => libc::AF_INET,
        SocketAddr::V6(_) => libc::AF_INET6,
    }
}

impl Socket {
    pub(crate) fn new(socket_addr: SocketAddr, socket_type: libc::c_int) -> io::Result<Socket> {
        let socket_type = socket_type | libc::SOCK_CLOEXEC;
        let domain = get_domain(socket_addr);
        let fd = socket2::Socket::new(domain.into(), socket_type.into(), None)?.into_raw_fd();
        Ok(Socket { fd })
    }

    pub(crate) fn new_unix(socket_type: libc::c_int) -> io::Result<Socket> {
        let socket_type = socket_type | libc::SOCK_CLOEXEC;
        let domain = libc::AF_UNIX;
        let fd = socket2::Socket::new(domain.into(), socket_type.into(), None)?.into_raw_fd();
        Ok(Socket { fd })
    }

    pub(crate) fn bind(socket_addr: SocketAddr, socket_type: libc::c_int) -> io::Result<Socket> {
        Self::bind_internal(
            socket_addr.into(),
            get_domain(socket_addr).into(),
            socket_type.into(),
        )
    }

    pub(crate) fn bind_unix<P: AsRef<Path>>(
        path: P,
        socket_type: libc::c_int,
    ) -> io::Result<Socket> {
        let addr = socket2::SockAddr::unix(path.as_ref())?;
        Socket::bind_internal(addr, libc::AF_UNIX.into(), socket_type.into())
    }

    fn bind_internal(
        socket_addr: socket2::SockAddr,
        domain: socket2::Domain,
        socket_type: socket2::Type,
    ) -> io::Result<Socket> {
        let sys_listener = socket2::Socket::new(domain, socket_type, None)?;
        sys_listener.set_reuse_port(true)?;
        sys_listener.set_reuse_address(true)?;
        sys_listener.bind(&socket_addr)?;
        let fd = sys_listener.into_raw_fd();
        Ok(Self { fd })
    }

    pub(crate) fn listen(&self, backlog: libc::c_int) -> io::Result<()> {
        syscall!(listen(self.as_raw_fd(), backlog))?;
        Ok(())
    }

    pub(crate) fn local_addr(&self) -> io::Result<SocketAddr> {
        sockname(|buf, len| syscall!(getsockname(self.as_raw_fd(), buf, len)))
    }

    pub(crate) fn peer_addr(&self) -> io::Result<SocketAddr> {
        sockname(|buf, len| syscall!(getpeername(self.as_raw_fd(), buf, len)))
    }

    pub(crate) fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
        setsockopt(
            self.as_raw_fd(),
            libc::IPPROTO_TCP,
            libc::TCP_NODELAY,
            nodelay as libc::c_int,
        )
    }
}

fn setsockopt<T>(
    sock: libc::c_int,
    opt: libc::c_int,
    val: libc::c_int,
    payload: T,
) -> io::Result<()> {
    let payload = &payload as *const T as *const libc::c_void;
    syscall!(setsockopt(
        sock,
        opt,
        val,
        payload,
        mem::size_of::<T>() as libc::socklen_t,
    ))?;
    Ok(())
}

pub(crate) fn sockname<F>(f: F) -> io::Result<SocketAddr>
where
    F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> io::Result<libc::c_int>,
{
    let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
    let mut len = mem::size_of_val(&storage) as libc::socklen_t;
    f(&mut storage as *mut _ as *mut _, &mut len)?;
    let (_, addr) = unsafe {
        SockAddr::try_init(move |addr_storage, length| {
            *(addr_storage as *mut _) = storage;
            *length = len;
            Ok(())
        })?
    };
    addr.as_socket()
        .ok_or_else(|| io::ErrorKind::InvalidInput.into())
}

impl Drop for Socket {
    fn drop(&mut self) {
        let _ = unsafe { libc::close(self.fd) };
    }
}

impl AsRawFd for Socket {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl From<RawFd> for Socket {
    fn from(fd: RawFd) -> Self {
        Socket { fd }
    }
}

impl FromRawFd for Socket {
    unsafe fn from_raw_fd(fd: RawFd) -> Self {
        Socket { fd }
    }
}