lx 0.4.0

A no_std crate to use Linux system calls
Documentation
use core::{
    mem,
    mem::MaybeUninit,
    ptr,
};

use super::abi::*;
use crate::{
    result_from_value,
    AsRawFd,
    Error,
    OwnedFd,
    SockAddr,
    EINVAL,
    ENOMEM,
};

/// Accepts a connection on a socket.
///
/// # Safety
///
/// `addr` must be a NULL pointer or a pointer to a `struct sockaddr` like structure. If `addr` is
/// a NULL pointer, then `addr_len` must be a NULL pointer as well. Otherwise, it should be a
/// pointer to an `isize` containing the size of the structure that `addr` points to.
#[inline]
pub unsafe fn accept4_raw(
    fd: &impl AsRawFd,
    addr: *mut u8,
    addr_len: *mut isize,
    flags: i32,
) -> crate::Result<OwnedFd> {
    let ret = syscall_4(
        288,
        fd.as_raw_fd() as usize,
        addr as usize,
        addr_len as usize,
        flags as usize,
    ) as i32;
    result_from_value(ret).map(OwnedFd::new)
}

#[inline]
pub fn accept4(fd: &impl AsRawFd, flags: i32) -> crate::Result<OwnedFd> {
    unsafe { accept4_raw(fd, ptr::null_mut(), ptr::null_mut(), flags) }
}

#[inline]
pub fn accept4_with_peer_addr<T: SockAddr>(
    fd: &impl AsRawFd,
    flags: i32,
) -> crate::Result<(OwnedFd, T)> {
    let addr_len = isize::try_from(mem::size_of::<T>()).unwrap();

    let mut addr: MaybeUninit<T> = MaybeUninit::uninit();
    let mut out_len = addr_len;
    let fd = unsafe {
        accept4_raw(
            fd,
            addr.as_mut_ptr() as *mut u8,
            &mut out_len as *mut isize,
            flags,
        )
    }?;

    // Make sure the address type is right.
    if out_len != addr_len {
        return Err(Error::from_code(ENOMEM));
    }
    let addr = unsafe { addr.assume_init() };
    // SAFETY: The `SockAddr` trait requires the type to be laid out like a `struct sockaddr`,
    // which means that the first field is the address family.
    let family = unsafe { mem::transmute::<&T, &u16>(&addr) };
    if *family != T::family().into() {
        return Err(Error::from_code(EINVAL));
    }

    Ok((fd, addr))
}