mio/net/uds/
datagram.rs

1use crate::io_source::IoSource;
2use crate::{event, sys, Interest, Registry, Token};
3
4use std::net::Shutdown;
5use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
6use std::os::unix::net;
7use std::path::Path;
8use std::{fmt, io};
9
10/// A Unix datagram socket.
11pub struct UnixDatagram {
12    inner: IoSource<net::UnixDatagram>,
13}
14
15impl UnixDatagram {
16    /// Creates a Unix datagram socket bound to the given path.
17    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
18        sys::uds::datagram::bind(path.as_ref()).map(UnixDatagram::from_std)
19    }
20
21    /// Creates a new `UnixDatagram` from a standard `net::UnixDatagram`.
22    ///
23    /// This function is intended to be used to wrap a Unix datagram from the
24    /// standard library in the Mio equivalent. The conversion assumes nothing
25    /// about the underlying datagram; it is left up to the user to set it in
26    /// non-blocking mode.
27    pub fn from_std(socket: net::UnixDatagram) -> UnixDatagram {
28        UnixDatagram {
29            inner: IoSource::new(socket),
30        }
31    }
32
33    /// Connects the socket to the specified address.
34    ///
35    /// This may return a `WouldBlock` in which case the socket connection
36    /// cannot be completed immediately.
37    pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
38        self.inner.connect(path)
39    }
40
41    /// Creates a Unix Datagram socket which is not bound to any address.
42    pub fn unbound() -> io::Result<UnixDatagram> {
43        sys::uds::datagram::unbound().map(UnixDatagram::from_std)
44    }
45
46    /// Create an unnamed pair of connected sockets.
47    pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
48        sys::uds::datagram::pair().map(|(socket1, socket2)| {
49            (
50                UnixDatagram::from_std(socket1),
51                UnixDatagram::from_std(socket2),
52            )
53        })
54    }
55
56    /// Returns the address of this socket.
57    pub fn local_addr(&self) -> io::Result<sys::SocketAddr> {
58        sys::uds::datagram::local_addr(&self.inner)
59    }
60
61    /// Returns the address of this socket's peer.
62    ///
63    /// The `connect` method will connect the socket to a peer.
64    pub fn peer_addr(&self) -> io::Result<sys::SocketAddr> {
65        sys::uds::datagram::peer_addr(&self.inner)
66    }
67
68    /// Receives data from the socket.
69    ///
70    /// On success, returns the number of bytes read and the address from
71    /// whence the data came.
72    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, sys::SocketAddr)> {
73        self.inner
74            .do_io(|inner| sys::uds::datagram::recv_from(inner, buf))
75    }
76
77    /// Receives data from the socket.
78    ///
79    /// On success, returns the number of bytes read.
80    pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
81        self.inner.do_io(|inner| inner.recv(buf))
82    }
83
84    /// Sends data on the socket to the specified address.
85    ///
86    /// On success, returns the number of bytes written.
87    pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
88        self.inner.do_io(|inner| inner.send_to(buf, path))
89    }
90
91    /// Sends data on the socket to the socket's peer.
92    ///
93    /// The peer address may be set by the `connect` method, and this method
94    /// will return an error if the socket has not already been connected.
95    ///
96    /// On success, returns the number of bytes written.
97    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
98        self.inner.do_io(|inner| inner.send(buf))
99    }
100
101    /// Returns the value of the `SO_ERROR` option.
102    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
103        self.inner.take_error()
104    }
105
106    /// Shut down the read, write, or both halves of this connection.
107    ///
108    /// This function will cause all pending and future I/O calls on the
109    /// specified portions to immediately return with an appropriate value
110    /// (see the documentation of `Shutdown`).
111    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
112        self.inner.shutdown(how)
113    }
114
115    /// Execute an I/O operation ensuring that the socket receives more events
116    /// if it hits a [`WouldBlock`] error.
117    ///
118    /// # Notes
119    ///
120    /// This method is required to be called for **all** I/O operations to
121    /// ensure the user will receive events once the socket is ready again after
122    /// returning a [`WouldBlock`] error.
123    ///
124    /// [`WouldBlock`]: io::ErrorKind::WouldBlock
125    ///
126    /// # Examples
127    ///
128    /// ```
129    /// # use std::error::Error;
130    /// #
131    /// # fn main() -> Result<(), Box<dyn Error>> {
132    /// use std::io;
133    /// use std::os::unix::io::AsRawFd;
134    /// use mio::net::UnixDatagram;
135    ///
136    /// let (dgram1, dgram2) = UnixDatagram::pair()?;
137    ///
138    /// // Wait until the dgram is writable...
139    ///
140    /// // Write to the dgram using a direct libc call, of course the
141    /// // `io::Write` implementation would be easier to use.
142    /// let buf = b"hello";
143    /// let n = dgram1.try_io(|| {
144    ///     let buf_ptr = &buf as *const _ as *const _;
145    ///     let res = unsafe { libc::send(dgram1.as_raw_fd(), buf_ptr, buf.len(), 0) };
146    ///     if res != -1 {
147    ///         Ok(res as usize)
148    ///     } else {
149    ///         // If EAGAIN or EWOULDBLOCK is set by libc::send, the closure
150    ///         // should return `WouldBlock` error.
151    ///         Err(io::Error::last_os_error())
152    ///     }
153    /// })?;
154    /// eprintln!("write {} bytes", n);
155    ///
156    /// // Wait until the dgram is readable...
157    ///
158    /// // Read from the dgram using a direct libc call, of course the
159    /// // `io::Read` implementation would be easier to use.
160    /// let mut buf = [0; 512];
161    /// let n = dgram2.try_io(|| {
162    ///     let buf_ptr = &mut buf as *mut _ as *mut _;
163    ///     let res = unsafe { libc::recv(dgram2.as_raw_fd(), buf_ptr, buf.len(), 0) };
164    ///     if res != -1 {
165    ///         Ok(res as usize)
166    ///     } else {
167    ///         // If EAGAIN or EWOULDBLOCK is set by libc::recv, the closure
168    ///         // should return `WouldBlock` error.
169    ///         Err(io::Error::last_os_error())
170    ///     }
171    /// })?;
172    /// eprintln!("read {} bytes", n);
173    /// # Ok(())
174    /// # }
175    /// ```
176    pub fn try_io<F, T>(&self, f: F) -> io::Result<T>
177    where
178        F: FnOnce() -> io::Result<T>,
179    {
180        self.inner.do_io(|_| f())
181    }
182}
183
184impl event::Source for UnixDatagram {
185    fn register(
186        &mut self,
187        registry: &Registry,
188        token: Token,
189        interests: Interest,
190    ) -> io::Result<()> {
191        self.inner.register(registry, token, interests)
192    }
193
194    fn reregister(
195        &mut self,
196        registry: &Registry,
197        token: Token,
198        interests: Interest,
199    ) -> io::Result<()> {
200        self.inner.reregister(registry, token, interests)
201    }
202
203    fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
204        self.inner.deregister(registry)
205    }
206}
207
208impl fmt::Debug for UnixDatagram {
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        self.inner.fmt(f)
211    }
212}
213
214impl IntoRawFd for UnixDatagram {
215    fn into_raw_fd(self) -> RawFd {
216        self.inner.into_inner().into_raw_fd()
217    }
218}
219
220impl AsRawFd for UnixDatagram {
221    fn as_raw_fd(&self) -> RawFd {
222        self.inner.as_raw_fd()
223    }
224}
225
226impl FromRawFd for UnixDatagram {
227    /// Converts a `RawFd` to a `UnixDatagram`.
228    ///
229    /// # Notes
230    ///
231    /// The caller is responsible for ensuring that the socket is in
232    /// non-blocking mode.
233    unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
234        UnixDatagram::from_std(FromRawFd::from_raw_fd(fd))
235    }
236}