1 | use crate::io_source::IoSource; |
2 | use crate::{event, sys, Interest, Registry, Token}; |
3 | |
4 | use std::net::Shutdown; |
5 | use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; |
6 | use std::os::unix::net; |
7 | use std::path::Path; |
8 | use std::{fmt, io}; |
9 | |
10 | /// A Unix datagram socket. |
11 | pub struct UnixDatagram { |
12 | inner: IoSource<net::UnixDatagram>, |
13 | } |
14 | |
15 | impl 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 | |
184 | impl 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 | |
208 | impl fmt::Debug for UnixDatagram { |
209 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
210 | self.inner.fmt(f) |
211 | } |
212 | } |
213 | |
214 | impl IntoRawFd for UnixDatagram { |
215 | fn into_raw_fd(self) -> RawFd { |
216 | self.inner.into_inner().into_raw_fd() |
217 | } |
218 | } |
219 | |
220 | impl AsRawFd for UnixDatagram { |
221 | fn as_raw_fd(&self) -> RawFd { |
222 | self.inner.as_raw_fd() |
223 | } |
224 | } |
225 | |
226 | impl 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 | |