tiny_std/
net.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use rusl::platform::{
    AddressFamily, NonNegativeI32, SocketAddressUnix, SocketFlags, SocketOptions, SocketType,
};
use rusl::string::unix_str::UnixStr;

use crate::error::Result;
use crate::io::{Read, Write};
use crate::unix::fd::{AsRawFd, OwnedFd, RawFd};

#[cfg(test)]
mod test;

#[derive(Debug)]
pub struct UnixStream(OwnedFd);

impl UnixStream {
    /// Creates and connects a non-blocking `UnixStream` at the specified path
    /// # Errors
    /// Various OS errors relating to permissions, and missing paths
    pub fn connect(path: &UnixStr, blocking: bool) -> Result<Self> {
        let block = blocking
            .then(SocketFlags::empty)
            .unwrap_or(SocketFlags::SOCK_NONBLOCK);
        let fd = rusl::network::socket(
            AddressFamily::AF_UNIX,
            SocketOptions::new(SocketType::SOCK_STREAM, block),
            0,
        )?;
        let addr = SocketAddressUnix::try_from_unix(path)?;

        rusl::network::connect_unix(fd, &addr)?;
        Ok(Self(OwnedFd(fd)))
    }
}

impl AsRawFd for UnixStream {
    fn as_raw_fd(&self) -> RawFd {
        self.0 .0
    }
}

impl Read for UnixStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        Ok(rusl::unistd::read(self.0 .0, buf)?)
    }
}

impl Write for UnixStream {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        Ok(rusl::unistd::write(self.0 .0, buf)?)
    }

    #[inline]
    fn flush(&mut self) -> Result<()> {
        Ok(())
    }
}

pub struct UnixListener(OwnedFd);

impl UnixListener {
    /// Creates and binds a non-blocking `UnixListener` at the specified path
    /// Use the `blocking` variable to set as blocking or non-blocking
    /// # Errors
    /// Various OS errors relating to permissions, and missing paths
    pub fn bind(path: &UnixStr, blocking: bool) -> Result<Self> {
        let block = blocking
            .then(SocketFlags::empty)
            .unwrap_or(SocketFlags::SOCK_NONBLOCK);
        let fd = rusl::network::socket(
            AddressFamily::AF_UNIX,
            SocketOptions::new(SocketType::SOCK_STREAM, block),
            0,
        )?;
        let addr = SocketAddressUnix::try_from_unix(path)?;
        rusl::network::bind_unix(fd, &addr)?;
        rusl::network::listen(fd, NonNegativeI32::MAX)?;
        Ok(Self(OwnedFd(fd)))
    }

    /// Accepts a new connection, blocking if this `UnixListener` was previously set to be blocking
    /// Use the `blocking` variable to set the incoming `UnixStream` as blocking or non-blocking
    /// # Errors
    /// Various OS errors relating to socket communication
    /// `EAGAIN` if this listener is set to non-blocking and there are no ready connections
    pub fn accept(&self, blocking: bool) -> Result<UnixStream> {
        let block = blocking
            .then(SocketFlags::empty)
            .unwrap_or(SocketFlags::SOCK_NONBLOCK);
        let client = rusl::network::accept_unix(self.0 .0, SocketFlags::SOCK_CLOEXEC | block)?.0;
        Ok(UnixStream(OwnedFd(client)))
    }
}