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