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(socket:FromRawFd::from_raw_fd(fd))
235 }
236}
237