1 use std::io; 2 use std::path::Path; 3 4 use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; 5 6 use crate::net::{UnixDatagram, UnixListener, UnixStream}; 7 8 cfg_net_unix! { 9 /// A Unix socket that has not yet been converted to a [`UnixStream`], [`UnixDatagram`], or 10 /// [`UnixListener`]. 11 /// 12 /// `UnixSocket` wraps an operating system socket and enables the caller to 13 /// configure the socket before establishing a connection or accepting 14 /// inbound connections. The caller is able to set socket option and explicitly 15 /// bind the socket with a socket address. 16 /// 17 /// The underlying socket is closed when the `UnixSocket` value is dropped. 18 /// 19 /// `UnixSocket` should only be used directly if the default configuration used 20 /// by [`UnixStream::connect`], [`UnixDatagram::bind`], and [`UnixListener::bind`] 21 /// does not meet the required use case. 22 /// 23 /// Calling `UnixStream::connect(path)` effectively performs the same function as: 24 /// 25 /// ```no_run 26 /// use tokio::net::UnixSocket; 27 /// use std::error::Error; 28 /// 29 /// #[tokio::main] 30 /// async fn main() -> Result<(), Box<dyn Error>> { 31 /// let dir = tempfile::tempdir().unwrap(); 32 /// let path = dir.path().join("bind_path"); 33 /// let socket = UnixSocket::new_stream()?; 34 /// 35 /// let stream = socket.connect(path).await?; 36 /// 37 /// Ok(()) 38 /// } 39 /// ``` 40 /// 41 /// Calling `UnixDatagram::bind(path)` effectively performs the same function as: 42 /// 43 /// ```no_run 44 /// use tokio::net::UnixSocket; 45 /// use std::error::Error; 46 /// 47 /// #[tokio::main] 48 /// async fn main() -> Result<(), Box<dyn Error>> { 49 /// let dir = tempfile::tempdir().unwrap(); 50 /// let path = dir.path().join("bind_path"); 51 /// let socket = UnixSocket::new_datagram()?; 52 /// socket.bind(path)?; 53 /// 54 /// let datagram = socket.datagram()?; 55 /// 56 /// Ok(()) 57 /// } 58 /// ``` 59 /// 60 /// Calling `UnixListener::bind(path)` effectively performs the same function as: 61 /// 62 /// ```no_run 63 /// use tokio::net::UnixSocket; 64 /// use std::error::Error; 65 /// 66 /// #[tokio::main] 67 /// async fn main() -> Result<(), Box<dyn Error>> { 68 /// let dir = tempfile::tempdir().unwrap(); 69 /// let path = dir.path().join("bind_path"); 70 /// let socket = UnixSocket::new_stream()?; 71 /// socket.bind(path)?; 72 /// 73 /// let listener = socket.listen(1024)?; 74 /// 75 /// Ok(()) 76 /// } 77 /// ``` 78 /// 79 /// Setting socket options not explicitly provided by `UnixSocket` may be done by 80 /// accessing the [`RawFd`]/[`RawSocket`] using [`AsRawFd`]/[`AsRawSocket`] and 81 /// setting the option with a crate like [`socket2`]. 82 /// 83 /// [`RawFd`]: std::os::fd::RawFd 84 /// [`RawSocket`]: https://doc.rust-lang.org/std/os/windows/io/type.RawSocket.html 85 /// [`AsRawFd`]: std::os::fd::AsRawFd 86 /// [`AsRawSocket`]: https://doc.rust-lang.org/std/os/windows/io/trait.AsRawSocket.html 87 /// [`socket2`]: https://docs.rs/socket2/ 88 #[derive(Debug)] 89 pub struct UnixSocket { 90 inner: socket2::Socket, 91 } 92 } 93 94 impl UnixSocket { ty(&self) -> socket2::Type95 fn ty(&self) -> socket2::Type { 96 self.inner.r#type().unwrap() 97 } 98 99 /// Creates a new Unix datagram socket. 100 /// 101 /// Calls `socket(2)` with `AF_UNIX` and `SOCK_DGRAM`. 102 /// 103 /// # Returns 104 /// 105 /// On success, the newly created [`UnixSocket`] is returned. If an error is 106 /// encountered, it is returned instead. new_datagram() -> io::Result<UnixSocket>107 pub fn new_datagram() -> io::Result<UnixSocket> { 108 UnixSocket::new(socket2::Type::DGRAM) 109 } 110 111 /// Creates a new Unix stream socket. 112 /// 113 /// Calls `socket(2)` with `AF_UNIX` and `SOCK_STREAM`. 114 /// 115 /// # Returns 116 /// 117 /// On success, the newly created [`UnixSocket`] is returned. If an error is 118 /// encountered, it is returned instead. new_stream() -> io::Result<UnixSocket>119 pub fn new_stream() -> io::Result<UnixSocket> { 120 UnixSocket::new(socket2::Type::STREAM) 121 } 122 new(ty: socket2::Type) -> io::Result<UnixSocket>123 fn new(ty: socket2::Type) -> io::Result<UnixSocket> { 124 #[cfg(any( 125 target_os = "android", 126 target_os = "dragonfly", 127 target_os = "freebsd", 128 target_os = "fuchsia", 129 target_os = "illumos", 130 target_os = "linux", 131 target_os = "netbsd", 132 target_os = "openbsd" 133 ))] 134 let ty = ty.nonblocking(); 135 let inner = socket2::Socket::new(socket2::Domain::UNIX, ty, None)?; 136 #[cfg(not(any( 137 target_os = "android", 138 target_os = "dragonfly", 139 target_os = "freebsd", 140 target_os = "fuchsia", 141 target_os = "illumos", 142 target_os = "linux", 143 target_os = "netbsd", 144 target_os = "openbsd" 145 )))] 146 inner.set_nonblocking(true)?; 147 Ok(UnixSocket { inner }) 148 } 149 150 /// Binds the socket to the given address. 151 /// 152 /// This calls the `bind(2)` operating-system function. bind(&self, path: impl AsRef<Path>) -> io::Result<()>153 pub fn bind(&self, path: impl AsRef<Path>) -> io::Result<()> { 154 let addr = socket2::SockAddr::unix(path)?; 155 self.inner.bind(&addr) 156 } 157 158 /// Converts the socket into a `UnixListener`. 159 /// 160 /// `backlog` defines the maximum number of pending connections are queued 161 /// by the operating system at any given time. Connection are removed from 162 /// the queue with [`UnixListener::accept`]. When the queue is full, the 163 /// operating-system will start rejecting connections. 164 /// 165 /// Calling this function on a socket created by [`new_datagram`] will return an error. 166 /// 167 /// This calls the `listen(2)` operating-system function, marking the socket 168 /// as a passive socket. 169 /// 170 /// [`new_datagram`]: `UnixSocket::new_datagram` listen(self, backlog: u32) -> io::Result<UnixListener>171 pub fn listen(self, backlog: u32) -> io::Result<UnixListener> { 172 if self.ty() == socket2::Type::DGRAM { 173 return Err(io::Error::new( 174 io::ErrorKind::Other, 175 "listen cannot be called on a datagram socket", 176 )); 177 } 178 179 self.inner.listen(backlog as i32)?; 180 let mio = { 181 use std::os::unix::io::{FromRawFd, IntoRawFd}; 182 183 let raw_fd = self.inner.into_raw_fd(); 184 unsafe { mio::net::UnixListener::from_raw_fd(raw_fd) } 185 }; 186 187 UnixListener::new(mio) 188 } 189 190 /// Establishes a Unix connection with a peer at the specified socket address. 191 /// 192 /// The `UnixSocket` is consumed. Once the connection is established, a 193 /// connected [`UnixStream`] is returned. If the connection fails, the 194 /// encountered error is returned. 195 /// 196 /// Calling this function on a socket created by [`new_datagram`] will return an error. 197 /// 198 /// This calls the `connect(2)` operating-system function. 199 /// 200 /// [`new_datagram`]: `UnixSocket::new_datagram` connect(self, path: impl AsRef<Path>) -> io::Result<UnixStream>201 pub async fn connect(self, path: impl AsRef<Path>) -> io::Result<UnixStream> { 202 if self.ty() == socket2::Type::DGRAM { 203 return Err(io::Error::new( 204 io::ErrorKind::Other, 205 "connect cannot be called on a datagram socket", 206 )); 207 } 208 209 let addr = socket2::SockAddr::unix(path)?; 210 if let Err(err) = self.inner.connect(&addr) { 211 if err.raw_os_error() != Some(libc::EINPROGRESS) { 212 return Err(err); 213 } 214 } 215 let mio = { 216 use std::os::unix::io::{FromRawFd, IntoRawFd}; 217 218 let raw_fd = self.inner.into_raw_fd(); 219 unsafe { mio::net::UnixStream::from_raw_fd(raw_fd) } 220 }; 221 222 UnixStream::connect_mio(mio).await 223 } 224 225 /// Converts the socket into a [`UnixDatagram`]. 226 /// 227 /// Calling this function on a socket created by [`new_stream`] will return an error. 228 /// 229 /// [`new_stream`]: `UnixSocket::new_stream` datagram(self) -> io::Result<UnixDatagram>230 pub fn datagram(self) -> io::Result<UnixDatagram> { 231 if self.ty() == socket2::Type::STREAM { 232 return Err(io::Error::new( 233 io::ErrorKind::Other, 234 "datagram cannot be called on a stream socket", 235 )); 236 } 237 let mio = { 238 use std::os::unix::io::{FromRawFd, IntoRawFd}; 239 240 let raw_fd = self.inner.into_raw_fd(); 241 unsafe { mio::net::UnixDatagram::from_raw_fd(raw_fd) } 242 }; 243 244 UnixDatagram::from_mio(mio) 245 } 246 } 247 248 impl AsRawFd for UnixSocket { as_raw_fd(&self) -> RawFd249 fn as_raw_fd(&self) -> RawFd { 250 self.inner.as_raw_fd() 251 } 252 } 253 254 impl AsFd for UnixSocket { as_fd(&self) -> BorrowedFd<'_>255 fn as_fd(&self) -> BorrowedFd<'_> { 256 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } 257 } 258 } 259 260 impl FromRawFd for UnixSocket { from_raw_fd(fd: RawFd) -> UnixSocket261 unsafe fn from_raw_fd(fd: RawFd) -> UnixSocket { 262 let inner = socket2::Socket::from_raw_fd(fd); 263 UnixSocket { inner } 264 } 265 } 266 267 impl IntoRawFd for UnixSocket { into_raw_fd(self) -> RawFd268 fn into_raw_fd(self) -> RawFd { 269 self.inner.into_raw_fd() 270 } 271 } 272