interprocess_docfix/os/unix/udsocket/socket.rs
1#[cfg(uds_supported)]
2use super::c_wrappers;
3use super::{
4 imports::*,
5 util::{check_ancillary_unsound, fill_out_msghdr_r, mk_msghdr_r, mk_msghdr_w},
6 AncillaryData, AncillaryDataBuf, EncodedAncillaryData, PathDropGuard, ToUdSocketPath,
7 UdSocketPath,
8};
9#[cfg(any(doc, target_os = "linux"))]
10use crate::{ReliableReadMsg, Sealed};
11use std::{
12 convert::TryInto,
13 fmt::{self, Debug, Formatter},
14 io::{self, IoSlice, IoSliceMut},
15 iter,
16 mem::{size_of_val, zeroed},
17};
18use to_method::To;
19
20/// A datagram socket in the Unix domain.
21///
22/// All such sockets have the `SOCK_DGRAM` socket type; in other words, this is the Unix domain version of a UDP socket.
23pub struct UdSocket {
24 // TODO make this not 'static
25 _drop_guard: PathDropGuard<'static>,
26 fd: FdOps,
27}
28impl UdSocket {
29 /// Creates a new socket that can be referred to by the specified path.
30 ///
31 /// If the socket path exceeds the [maximum socket path length] (which includes the first 0 byte when using the [socket namespace]), an error is returned. Errors can also be produced for different reasons, i.e. errors should always be handled regardless of whether the path is known to be short enough or not.
32 ///
33 /// After the socket is dropped, the socket file will be left over. Use [`bind_with_drop_guard()`](Self::bind_with_drop_guard) to mitigate this automatically, even during panics (if unwinding is enabled).
34 ///
35 /// # Example
36 /// See [`ToUdSocketPath`] for an example of using various string types to specify socket paths.
37 ///
38 /// # System calls
39 /// - `socket`
40 /// - `bind`
41 ///
42 /// [maximum socket path length]: const.MAX_UDSOCKET_PATH_LEN.html " "
43 /// [socket namespace]: enum.UdSocketPath.html#namespaced " "
44 /// [`ToUdSocketPath`]: trait.ToUdSocketPath.html " "
45 pub fn bind<'a>(path: impl ToUdSocketPath<'a>) -> io::Result<Self> {
46 Self::_bind(path.to_socket_path()?, false)
47 }
48 /// Creates a new socket that can be referred to by the specified path, remembers the address, and installs a drop guard that will delete the socket file once the socket is dropped.
49 ///
50 /// See the documentation of [`bind()`](Self::bind).
51 pub fn bind_with_drop_guard<'a>(path: impl ToUdSocketPath<'a>) -> io::Result<Self> {
52 Self::_bind(path.to_socket_path()?, true)
53 }
54 fn _bind(path: UdSocketPath<'_>, keep_drop_guard: bool) -> io::Result<Self> {
55 let addr = path.borrow().try_to::<sockaddr_un>()?;
56
57 let fd = c_wrappers::create_uds(SOCK_DGRAM, false)?;
58 unsafe {
59 // SAFETY: addr is well-constructed
60 c_wrappers::bind(&fd, &addr)?;
61 }
62 c_wrappers::set_passcred(&fd, true)?;
63
64 let dg = if keep_drop_guard && matches!(path, UdSocketPath::File(..)) {
65 PathDropGuard {
66 path: path.to_owned(),
67 enabled: true,
68 }
69 } else {
70 PathDropGuard::dummy()
71 };
72
73 Ok(Self {
74 fd,
75 _drop_guard: dg,
76 })
77 }
78 /// Selects the Unix domain socket to send packets to. You can also just use [`.send_to()`](Self::send_to) instead, but supplying the address to the kernel once is more efficient.
79 ///
80 /// # Example
81 /// ```no_run
82 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
83 /// # #[cfg(unix)] {
84 /// use interprocess::os::unix::udsocket::UdSocket;
85 ///
86 /// let conn = UdSocket::bind("/tmp/side_a.sock")?;
87 /// conn.set_destination("/tmp/side_b.sock")?;
88 /// // Communicate with datagrams here!
89 /// # }
90 /// # Ok(()) }
91 /// ```
92 /// See [`ToUdSocketPath`] for an example of using various string types to specify socket paths.
93 ///
94 /// # System calls
95 /// - `connect`
96 pub fn set_destination<'a>(&self, path: impl ToUdSocketPath<'a>) -> io::Result<()> {
97 let path = path.to_socket_path()?;
98 self._set_destination(&path)
99 }
100 fn _set_destination(&self, path: &UdSocketPath<'_>) -> io::Result<()> {
101 let addr = path.borrow().try_to::<sockaddr_un>()?;
102
103 unsafe {
104 // SAFETY: addr is well-constructed
105 c_wrappers::connect(&self.fd, &addr)?;
106 }
107
108 Ok(())
109 }
110 /// Incorrect API; do not use.
111 // TODO banish
112 #[deprecated = "\
113creates unusable socket that is not bound to any address, use `.set_destination()` instead"]
114 pub fn connect<'a>(path: impl ToUdSocketPath<'a>) -> io::Result<Self> {
115 let path = path.to_socket_path()?;
116 Self::_connect(&path, false)
117 }
118 fn _connect(path: &UdSocketPath<'_>, keep_drop_guard: bool) -> io::Result<Self> {
119 let fd = c_wrappers::create_uds(SOCK_DGRAM, false)?;
120 c_wrappers::set_passcred(&fd, true)?;
121
122 let dg = if keep_drop_guard && matches!(path, UdSocketPath::File(..)) {
123 PathDropGuard {
124 path: path.to_owned(),
125 enabled: true,
126 }
127 } else {
128 PathDropGuard::dummy()
129 };
130
131 let socket = Self {
132 fd,
133 _drop_guard: dg,
134 };
135 socket._set_destination(path)?;
136
137 Ok(socket)
138 }
139
140 // TODO banish
141 fn add_fake_trunc_flag(x: usize) -> (usize, bool) {
142 (x, false)
143 }
144
145 /// Receives a single datagram from the socket, returning the size of the received datagram.
146 ///
147 /// *Note: there is an additional meaningless boolean return value which is always `false`. It used to signify whether the datagram was truncated or not, but the functionality was implemented incorrectly and only on Linux, leading to its removal in version 1.2.0. In the next breaking release, 2.0.0, the return value will be changed to just `io::Result<usize>`.*
148 ///
149 /// # System calls
150 /// - `read`
151 pub fn recv(&self, buf: &mut [u8]) -> io::Result<(usize, bool)> {
152 self.fd.read(buf).map(Self::add_fake_trunc_flag)
153 }
154
155 /// Receives a single datagram from the socket, making use of [scatter input] and returning the size of the received datagram.
156 ///
157 /// *Note: there is an additional meaningless boolean return value which is always `false`. It used to signify whether the datagram was truncated or not, but the functionality was implemented incorrectly and only on Linux, leading to its removal in version 1.2.0. In the next breaking release, 2.0.0, the return value will be changed to just `io::Result<usize>`.*
158 ///
159 /// # System calls
160 /// - `readv`
161 ///
162 /// [scatter input]: https://en.wikipedia.org/wiki/Vectored_I/O " "
163 pub fn recv_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<(usize, bool)> {
164 self.fd.read_vectored(bufs).map(Self::add_fake_trunc_flag)
165 }
166
167 /// Receives a single datagram and ancillary data from the socket. The return value is in the following order:
168 /// - How many bytes of the datagram were received
169 /// - *Deprecated `bool` field (always `false`), see note*
170 /// - How many bytes of ancillary data were received
171 /// - *Another deprecated `bool` field (always `false`), see note*
172 ///
173 /// *Note: there are two additional meaningless boolean return values which are always `false`. They used to signify whether the datagram, and the ancillary data respectively, were truncated or not, but the functionality was implemented incorrectly and only on Linux, leading to its removal in version 1.2.0. In the next breaking release, 2.0.0, the return value will be changed to just `io::Result<usize>`.*
174 ///
175 /// # System calls
176 /// - `recvmsg`
177 ///
178 /// [scatter input]: https://en.wikipedia.org/wiki/Vectored_I/O " "
179 pub fn recv_ancillary<'a: 'b, 'b>(
180 &self,
181 buf: &mut [u8],
182 abuf: &'b mut AncillaryDataBuf<'a>,
183 ) -> io::Result<(usize, bool, usize, bool)> {
184 check_ancillary_unsound()?;
185 self.recv_ancillary_vectored(&mut [IoSliceMut::new(buf)], abuf)
186 }
187
188 /// Receives a single datagram and ancillary data from the socket, making use of [scatter input]. The return value is in the following order:
189 /// - How many bytes of the datagram were received
190 /// - *Deprecated `bool` field (always `false`), see note*
191 /// - How many bytes of ancillary data were received
192 /// - *Another deprecated `bool` field (always `false`), see note*
193 ///
194 /// *Note: there are two additional meaningless boolean return values which are always `false`. They used to signify whether the datagram, and the ancillary data respectively, were truncated or not, but the functionality was implemented incorrectly and only on Linux, leading to its removal in version 1.2.0. In the next breaking release, 2.0.0, the return value will be changed to just `io::Result<(usize, usize)>`.*
195 ///
196 /// # System calls
197 /// - `recvmsg`
198 ///
199 /// [scatter input]: https://en.wikipedia.org/wiki/Vectored_I/O " "
200 #[allow(clippy::useless_conversion)]
201 pub fn recv_ancillary_vectored<'a: 'b, 'b>(
202 &self,
203 bufs: &mut [IoSliceMut<'_>],
204 abuf: &'b mut AncillaryDataBuf<'a>,
205 ) -> io::Result<(usize, bool, usize, bool)> {
206 check_ancillary_unsound()?;
207 let mut hdr = mk_msghdr_r(bufs, abuf.as_mut())?;
208 let (success, bytes_read) = unsafe {
209 let result = libc::recvmsg(self.as_raw_fd(), &mut hdr as *mut _, 0);
210 (result != -1, result as usize)
211 };
212 if success {
213 Ok((bytes_read, false, hdr.msg_controllen as _, false))
214 } else {
215 Err(io::Error::last_os_error())
216 }
217 }
218
219 /// Receives a single datagram and the source address from the socket, returning how much of the buffer was filled out and whether a part of the datagram was discarded because the buffer was too small.
220 ///
221 /// # System calls
222 /// - `recvmsg`
223 /// - Future versions of `interprocess` may use `recvfrom` instead; for now, this method is a wrapper around [`recv_from_vectored`].
224 ///
225 /// [`recv_from_vectored`]: #method.recv_from_vectored " "
226 // TODO use recvfrom
227 pub fn recv_from<'a: 'b, 'b>(
228 &self,
229 buf: &mut [u8],
230 addr_buf: &'b mut UdSocketPath<'a>,
231 ) -> io::Result<(usize, bool)> {
232 self.recv_from_vectored(&mut [IoSliceMut::new(buf)], addr_buf)
233 }
234
235 /// Receives a single datagram and the source address from the socket, making use of [scatter input] and returning how much of the buffer was filled out and whether a part of the datagram was discarded because the buffer was too small.
236 ///
237 /// # System calls
238 /// - `recvmsg`
239 ///
240 /// [scatter input]: https://en.wikipedia.org/wiki/Vectored_I/O " "
241 pub fn recv_from_vectored<'a: 'b, 'b>(
242 &self,
243 bufs: &mut [IoSliceMut<'_>],
244 addr_buf: &'b mut UdSocketPath<'a>,
245 ) -> io::Result<(usize, bool)> {
246 self.recv_from_ancillary_vectored(bufs, &mut AncillaryDataBuf::Owned(Vec::new()), addr_buf)
247 .map(|x| (x.0, x.1))
248 }
249
250 /// Receives a single datagram, ancillary data and the source address from the socket. The return value is in the following order:
251 /// - How many bytes of the datagram were received
252 /// - *Deprecated `bool` field (always `false`), see note*
253 /// - How many bytes of ancillary data were received
254 /// - *Another deprecated `bool` field (always `false`), see note*
255 ///
256 /// *Note: there are two additional meaningless boolean return values which are always `false`. They used to signify whether the datagram, and the ancillary data respectively, were truncated or not, but the functionality was implemented incorrectly and only on Linux, leading to its removal in version 1.2.0. In the next breaking release, 2.0.0, the return value will be changed to just `io::Result<(usize, usize)>`.*
257 ///
258 /// # System calls
259 /// - `recvmsg`
260 pub fn recv_from_ancillary<'a: 'b, 'b, 'c: 'd, 'd>(
261 &self,
262 buf: &mut [u8],
263 abuf: &'b mut AncillaryDataBuf<'a>,
264 addr_buf: &'d mut UdSocketPath<'c>,
265 ) -> io::Result<(usize, bool, usize, bool)> {
266 if !abuf.as_ref().is_empty() {
267 // Branching required because recv_from_vectored always uses
268 // recvmsg (no non-ancillary counterpart)
269 check_ancillary_unsound()?;
270 }
271 self.recv_from_ancillary_vectored(&mut [IoSliceMut::new(buf)], abuf, addr_buf)
272 }
273
274 /// Receives a single datagram, ancillary data and the source address from the socket, making use of [scatter input]. The return value is in the following order:
275 /// - How many bytes of the datagram were received
276 /// - Whether a part of the datagram was discarded because the buffer was too small
277 /// - How many bytes of ancillary data were received
278 /// - Whether some ancillary data was discarded because the buffer was too small
279 ///
280 /// # System calls
281 /// - `recvmsg`
282 ///
283 /// [scatter input]: https://en.wikipedia.org/wiki/Vectored_I/O " "
284 pub fn recv_from_ancillary_vectored<'a: 'b, 'b, 'c: 'd, 'd>(
285 &self,
286 bufs: &mut [IoSliceMut<'_>],
287 abuf: &'b mut AncillaryDataBuf<'a>,
288 addr_buf: &'d mut UdSocketPath<'c>,
289 ) -> io::Result<(usize, bool, usize, bool)> {
290 check_ancillary_unsound()?;
291 // SAFETY: msghdr consists of integers and pointers, all of which are nullable
292 let mut hdr = unsafe { zeroed::<msghdr>() };
293 // Same goes for sockaddr_un
294 let mut addr_buf_staging = unsafe { zeroed::<sockaddr_un>() };
295 // It's a void* so the doublecast is mandatory
296 hdr.msg_name = &mut addr_buf_staging as *mut _ as *mut _;
297 hdr.msg_namelen = size_of_val(&addr_buf_staging)
298 .try_to::<u32>()
299 .unwrap()
300 .try_into()
301 .unwrap();
302 fill_out_msghdr_r(&mut hdr, bufs, abuf.as_mut())?;
303 let (success, bytes_read) = unsafe {
304 let result = libc::recvmsg(self.as_raw_fd(), &mut hdr as *mut _, 0);
305 (result != -1, result as usize)
306 };
307 let path_length = hdr.msg_namelen as usize;
308 if success {
309 addr_buf.write_sockaddr_un_to_self(&addr_buf_staging, path_length);
310 Ok((bytes_read, false, hdr.msg_controllen as _, false))
311 } else {
312 Err(io::Error::last_os_error())
313 }
314 }
315
316 /// Returns the size of the next datagram available on the socket without discarding it.
317 ///
318 /// This method is only available on Linux since kernel version 2.2. On lower kernel versions, it will fail; on other platforms, it's absent and thus any usage of it will result in a compile-time error.
319 ///
320 /// # System calls
321 /// - `recv`
322 #[cfg(any(doc, target_os = "linux"))]
323 #[cfg_attr(feature = "doc_cfg", doc(cfg(target_os = "linux")))]
324 pub fn peek_msg_size(&self) -> io::Result<usize> {
325 let mut buffer = [0_u8; 0];
326 let (success, size) = unsafe {
327 let size = libc::recv(
328 self.as_raw_fd(),
329 buffer.as_mut_ptr() as *mut _,
330 buffer.len(),
331 libc::MSG_TRUNC | libc::MSG_PEEK,
332 );
333 (size != -1, size as usize)
334 };
335 if success {
336 Ok(size)
337 } else {
338 Err(io::Error::last_os_error())
339 }
340 }
341
342 /// Sends a datagram into the socket.
343 ///
344 /// # System calls
345 /// - `write`
346 pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
347 self.fd.write(buf)
348 }
349 /// Sends a datagram into the socket, making use of [gather output] for the main data.
350 ///
351 ///
352 /// # System calls
353 /// - `sendmsg`
354 /// - Future versions of `interprocess` may use `writev` instead; for now, this method is a wrapper around [`send_ancillary_vectored`].
355 ///
356 /// [gather output]: https://en.wikipedia.org/wiki/Vectored_I/O " "
357 /// [`send_ancillary_vectored`]: #method.send_ancillary_vectored " "
358 pub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
359 self.send_ancillary_vectored(bufs, iter::empty())
360 .map(|x| x.0)
361 }
362 /// Sends a datagram and ancillary data into the socket.
363 ///
364 /// The ancillary data buffer is automatically converted from the supplied value, if possible. For that reason, slices and `Vec`s of `AncillaryData` can be passed directly.
365 ///
366 /// # System calls
367 /// - `sendmsg`
368 pub fn send_ancillary<'a>(
369 &self,
370 buf: &[u8],
371 ancillary_data: impl IntoIterator<Item = AncillaryData<'a>>,
372 ) -> io::Result<(usize, usize)> {
373 check_ancillary_unsound()?;
374 self.send_ancillary_vectored(&[IoSlice::new(buf)], ancillary_data)
375 }
376 /// Sends a datagram and ancillary data into the socket, making use of [gather output] for the main data.
377 ///
378 /// The ancillary data buffer is automatically converted from the supplied value, if possible. For that reason, slices and `Vec`s of `AncillaryData` can be passed directly.
379 ///
380 /// # System calls
381 /// - `sendmsg`
382 ///
383 /// [gather output]: https://en.wikipedia.org/wiki/Vectored_I/O " "
384 pub fn send_ancillary_vectored<'a>(
385 &self,
386 bufs: &[IoSlice<'_>],
387 ancillary_data: impl IntoIterator<Item = AncillaryData<'a>>,
388 ) -> io::Result<(usize, usize)> {
389 check_ancillary_unsound()?;
390 let abuf = ancillary_data
391 .into_iter()
392 .collect::<EncodedAncillaryData<'_>>();
393 let hdr = mk_msghdr_w(bufs, abuf.as_ref())?;
394 let (success, bytes_written) = unsafe {
395 let result = libc::sendmsg(self.as_raw_fd(), &hdr as *const _, 0);
396 (result != -1, result as usize)
397 };
398 if success {
399 Ok((bytes_written, hdr.msg_controllen as _))
400 } else {
401 Err(io::Error::last_os_error())
402 }
403 }
404
405 /// Enables or disables the nonblocking mode for the socket. By default, it is disabled.
406 ///
407 /// In nonblocking mode, calls to the `recv…` methods and the `Read` trait methods will never wait for at least one message to become available; calls to `send…` methods and the `Write` trait methods will never wait for the other side to remove enough bytes from the buffer for the write operation to be performed. Those operations will instead return a [`WouldBlock`] error immediately, allowing the thread to perform other useful operations in the meantime.
408 ///
409 /// [`accept`]: #method.accept " "
410 /// [`incoming`]: #method.incoming " "
411 /// [`WouldBlock`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.WouldBlock " "
412 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
413 c_wrappers::set_nonblocking(&self.fd, nonblocking)
414 }
415 /// Checks whether the socket is currently in nonblocking mode or not.
416 pub fn is_nonblocking(&self) -> io::Result<bool> {
417 c_wrappers::get_nonblocking(&self.fd)
418 }
419
420 /// Fetches the credentials of the other end of the connection without using ancillary data. The returned structure contains the process identifier, user identifier and group identifier of the peer.
421 #[cfg(any(doc, uds_peercred))]
422 #[cfg_attr( // uds_peercred template
423 feature = "doc_cfg",
424 doc(cfg(any(
425 all(
426 target_os = "linux",
427 any(
428 target_env = "gnu",
429 target_env = "musl",
430 target_env = "musleabi",
431 target_env = "musleabihf"
432 )
433 ),
434 target_os = "emscripten",
435 target_os = "redox",
436 target_os = "haiku"
437 )))
438 )]
439 pub fn get_peer_credentials(&self) -> io::Result<ucred> {
440 c_wrappers::get_peer_ucred(&self.fd)
441 }
442}
443
444impl Debug for UdSocket {
445 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
446 f.debug_struct("UdSocket")
447 .field("fd", &self.as_raw_fd())
448 .field("has_drop_guard", &self._drop_guard.enabled)
449 .finish()
450 }
451}
452
453#[cfg(any(doc, target_os = "linux"))]
454#[cfg_attr(feature = "doc_cfg", doc(cfg(target_os = "linux")))]
455impl ReliableReadMsg for UdSocket {
456 fn read_msg(&mut self, buf: &mut [u8]) -> io::Result<Result<usize, Vec<u8>>> {
457 let msg_size = self.peek_msg_size()?;
458 if msg_size > buf.len() {
459 let mut new_buffer = vec![0; msg_size];
460 let len = self.recv(&mut new_buffer)?.0;
461 new_buffer.truncate(len);
462 Ok(Err(new_buffer))
463 } else {
464 Ok(Ok(self.recv(buf)?.0))
465 }
466 }
467 fn try_read_msg(&mut self, buf: &mut [u8]) -> io::Result<Result<usize, usize>> {
468 let msg_size = self.peek_msg_size()?;
469 if msg_size > buf.len() {
470 Ok(Err(msg_size))
471 } else {
472 Ok(Ok(self.recv(buf)?.0))
473 }
474 }
475}
476#[cfg(any(doc, target_os = "linux"))]
477impl Sealed for UdSocket {}
478
479impl AsRawFd for UdSocket {
480 #[cfg(unix)]
481 fn as_raw_fd(&self) -> c_int {
482 self.fd.as_raw_fd()
483 }
484}
485impl IntoRawFd for UdSocket {
486 #[cfg(unix)]
487 fn into_raw_fd(self) -> c_int {
488 self.fd.into_raw_fd()
489 }
490}
491impl FromRawFd for UdSocket {
492 #[cfg(unix)]
493 unsafe fn from_raw_fd(fd: c_int) -> Self {
494 let fd = unsafe { FdOps::from_raw_fd(fd) };
495 Self {
496 fd,
497 _drop_guard: PathDropGuard::dummy(),
498 }
499 }
500}