ruyi 0.1.6

An event-driven framework for non-blocking, asynchronous I/O in Rust
Documentation
use std::io;
use std::mem;
use std::net::{SocketAddr, TcpStream, TcpListener};
use std::os::unix::io::{AsRawFd, FromRawFd};

use libc;

use super::IoVec;

#[inline]
pub fn new_v4() -> io::Result<TcpStream> {
    let res = unsafe {
        libc::socket(
            libc::AF_INET,
            libc::SOCK_STREAM | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC,
            0,
        )
    };
    let fd = super::cvt(res)?;
    Ok(unsafe { TcpStream::from_raw_fd(fd) })
}

#[inline]
pub fn new_v6() -> io::Result<TcpStream> {
    let res = unsafe {
        libc::socket(
            libc::AF_INET6,
            libc::SOCK_STREAM | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC,
            0,
        )
    };
    let fd = super::cvt(res)?;
    Ok(unsafe { TcpStream::from_raw_fd(fd) })
}

#[inline]
pub fn connect(addr: &SocketAddr) -> io::Result<(TcpStream, bool)> {
    let (sock, addr, len) = match *addr {
        SocketAddr::V4(ref a) => {
            (
                new_v4()?,
                a as *const _ as *const _,
                mem::size_of_val(a) as libc::socklen_t,
            )
        }
        SocketAddr::V6(ref a) => {
            (
                new_v6()?,
                a as *const _ as *const _,
                mem::size_of_val(a) as libc::socklen_t,
            )
        }
    };
    let res = unsafe { libc::connect(sock.as_raw_fd(), addr, len) };
    match super::cvt(res) {
        Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => Ok((sock, false)),
        Ok(..) => Ok((sock, true)),
        Err(e) => Err(e),
    }
}

#[inline]
pub fn readv(sock: &TcpStream, iov_ptr: *const IoVec, len: usize) -> io::Result<usize> {
    super::readv(sock.as_raw_fd(), iov_ptr, len)
}

#[inline]
pub fn writev(sock: &TcpStream, iov_ptr: *const IoVec, len: usize) -> io::Result<usize> {
    super::writev(sock.as_raw_fd(), iov_ptr, len)
}

#[inline]
fn sockaddr_to_addr(storage: &libc::sockaddr_storage, len: usize) -> io::Result<SocketAddr> {
    match storage.ss_family as libc::c_int {
        libc::AF_INET => {
            debug_assert!(len >= mem::size_of::<libc::sockaddr_in>());
            let addr = unsafe { *(storage as *const _ as *const libc::sockaddr_in) };
            Ok(SocketAddr::V4(unsafe { mem::transmute(addr) }))
        }
        libc::AF_INET6 => {
            debug_assert!(len >= mem::size_of::<libc::sockaddr_in6>());
            let addr = unsafe { *(storage as *const _ as *const libc::sockaddr_in6) };
            Ok(SocketAddr::V6(unsafe { mem::transmute(addr) }))
        }
        _ => Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "invalid argument",
        )),
    }
}

#[inline]
pub fn accept(listener: &TcpListener) -> io::Result<(TcpStream, SocketAddr)> {
    let mut storage: libc::sockaddr_storage = unsafe { mem::uninitialized() };
    let mut len = mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
    let res = unsafe {
        libc::accept4(
            listener.as_raw_fd(),
            &mut storage as *mut _ as *mut _,
            &mut len,
            libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC,
        )
    };
    let fd = super::cvt(res)?;
    let sock = unsafe { TcpStream::from_raw_fd(fd) };
    let addr = sockaddr_to_addr(&storage, len as usize)?;
    Ok((sock, addr))
}