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}