Skip to main content

uds_fork/
traits.rs

1
2use std::
3{
4    ffi::c_void, io::{self, IoSlice, IoSliceMut}, os::
5    {
6        fd::{AsFd, OwnedFd}, 
7        unix::{io::{AsRawFd, FromRawFd}, net::{UnixDatagram, UnixListener, UnixStream}} 
8    }
9};
10
11use libc::{MSG_PEEK, recvfrom, sendto};
12
13use crate::addr::UnixSocketAddr;
14use crate::helpers::*;
15use crate::ancillary::*;
16use crate::credentials::*;
17
18/// Extension trait for `std::os::unix::net::UnixStream` and nonblocking equivalents.
19pub trait UnixStreamExt: AsFd + AsRawFd + FromRawFd 
20{
21    /// Get the address of this socket, as a type that fully supports abstract addresses.
22    fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error> 
23    {
24        get_unix_local_addr(self)
25    }
26
27    /// Returns the address of the other end of this stream,
28    /// as a type that fully supports abstract addresses.
29    fn peer_unix_addr(&self) -> Result<UnixSocketAddr, io::Error> 
30    {
31        get_unix_peer_addr(self)
32    }
33
34    /// Creates a connection to a listening path-based or abstract named socket.
35    fn connect_to_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error> where Self: Sized;
36
37    /// Creates a path-based or abstract-named socket and connects to a listening socket.
38    fn connect_from_to_unix_addr(from: &UnixSocketAddr, to: &UnixSocketAddr) -> Result<Self, io::Error> 
39        where Self: Sized;
40
41    /// Sends file descriptors in addition to bytes.
42    fn send_fds(&self, bytes: &[u8], fds: Vec<OwnedFd>) -> Result<usize, io::Error> 
43    {
44        send_ancillary(self, None, 0, &[IoSlice::new(bytes)], fds, None)
45    }
46
47    /// Receives file descriptors in addition to bytes.
48    fn recv_fds(&self, buf: &mut[u8], fd_buf: &mut Vec<OwnedFd>) -> Result<(usize, usize), io::Error> 
49    {
50        recv_fds(self, None, &mut[IoSliceMut::new(buf)], Some(fd_buf))
51            .map(|(bytes, _, fds)| (bytes, fds) )
52    }
53
54    /// Returns the credentials of the process that created the other end of this stream.
55    fn initial_peer_credentials(&self) -> Result<ConnCredentials, io::Error> 
56    {
57        peer_credentials(self)
58    }
59    /// Returns the SELinux security context of the process that created the other end of this stream.
60    ///
61    /// Will return an error on other operating systems than Linux or Android,
62    /// and also if running under kubernetes.
63    /// On success the number of bytes used is returned. (like `Read`)
64    ///
65    /// The default security context is `unconfined`, without any trailing NUL.  
66    /// A buffor of 50 bytes is probably always big enough.
67    fn initial_peer_selinux_context(&self, buffer: &mut[u8]) -> Result<usize, io::Error> 
68    {
69        selinux_context(self, buffer)
70    }
71}
72
73impl UnixStreamExt for UnixStream 
74{
75    fn connect_to_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error> 
76    {
77        let socket = Socket::<SocketStream>::new(false)?;
78        socket.set_unix_peer_addr(addr)?;
79        
80        return Ok(Self::from( <Socket<SocketStream> as Into<OwnedFd>>::into(socket)));
81    }
82
83    fn connect_from_to_unix_addr(from: &UnixSocketAddr,  to: &UnixSocketAddr) -> Result<Self, io::Error> 
84    {
85        let socket = Socket::<SocketStream>::new(false)?;
86        socket.set_unix_local_addr(from)?;
87        socket.set_unix_peer_addr(to)?;
88        
89        return Ok(Self::from( <Socket<SocketStream> as Into<OwnedFd>>::into(socket)));
90    }
91}
92
93#[cfg(feature = "mio")]
94impl UnixStreamExt for mio::net::UnixStream 
95{
96    fn connect_to_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error> 
97    {
98        let socket = Socket::<SocketStream>::new(true)?;
99        socket.set_unix_peer_addr(addr)?;
100
101        return Ok(Self::from( <Socket<SocketStream> as Into<OwnedFd>>::into(socket)));
102    }
103
104    fn connect_from_to_unix_addr(from: &UnixSocketAddr,  to: &UnixSocketAddr) -> Result<Self, io::Error> 
105    {
106        let socket = Socket::<SocketStream>::new(true)?;
107        socket.set_unix_local_addr(from)?;
108        socket.set_unix_peer_addr(to)?;
109
110        return Ok(Self::from( <Socket<SocketStream> as Into<OwnedFd>>::into(socket)));
111    }
112}
113
114/// Extension trait for using [`UnixSocketAddr`](struct.UnixSocketAddr.html) with `UnixListener` types.
115pub trait UnixListenerExt: AsFd + AsRawFd + FromRawFd 
116{
117    /// The type represeting the stream connection returned by `accept_unix_addr()`.
118    type Conn: FromRawFd;
119
120    /// Creates a socket bound to a `UnixSocketAddr` and starts listening on it.
121    fn bind_unix_addr(on: &UnixSocketAddr) -> Result<Self, io::Error> 
122        where Self: Sized;
123
124    /// Returns the address this socket is listening on.
125    fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error> 
126    {
127        get_unix_local_addr(self)
128    }
129
130    /// Accepts a connection and returns the client's address as
131    /// an `uds_fork::UnixSocketAddr`.
132    fn accept_unix_addr(&self) -> Result<(Self::Conn, UnixSocketAddr), io::Error>;
133}
134
135impl UnixListenerExt for UnixListener 
136{
137    type Conn = UnixStream;
138
139    fn bind_unix_addr(on: &UnixSocketAddr) -> Result<Self, io::Error> 
140    {
141        let socket = Socket::<SocketStream>::new(false)?;
142        socket.set_unix_local_addr(on)?;
143
144        socket.start_listening()?;
145        
146        return 
147            Ok(Self::from( <Socket<SocketStream> as Into<OwnedFd>>::into(socket)));
148    }
149
150    fn accept_unix_addr(&self) -> Result<(Self::Conn, UnixSocketAddr), io::Error> 
151    {
152        let (socket, addr) = Socket::<SocketStream>::accept_from(self, false)?;
153        let conn = 
154                Self::Conn::from(<Socket<SocketStream> as Into<OwnedFd>>::into(socket));
155        
156        return Ok((conn, addr));
157    }
158}
159
160
161#[cfg(feature = "mio")]
162impl UnixListenerExt for mio::net::UnixListener 
163{
164    type Conn = mio::net::UnixStream;
165
166    fn bind_unix_addr(on: &UnixSocketAddr) -> Result<Self, io::Error> 
167    {
168        let socket = Socket::<SocketStream>::new(true)?;
169        socket.set_unix_local_addr(on)?;
170
171        socket.start_listening()?;
172
173        return 
174            Ok(Self::from( <Socket<SocketStream> as Into<OwnedFd>>::into(socket)));
175    }
176
177    fn accept_unix_addr(&self) -> Result<(Self::Conn, UnixSocketAddr), io::Error> 
178    {
179        let (socket, addr) = Socket::<SocketStream>::accept_from(self, true)?;
180    
181        let conn = 
182                Self::Conn::from(<Socket<SocketStream> as Into<OwnedFd>>::into(socket));
183
184        Ok((conn, addr))
185    }
186}
187
188/// Extension trait for `std::os::unix::net::UnixDatagram` and nonblocking equivalents.
189pub trait UnixDatagramExt: AsFd + AsRawFd + FromRawFd 
190{
191    /// Create a socket bound to a path or abstract name.
192    ///
193    /// # Examples
194    ///
195    #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
196    #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
197    /// # use std::os::unix::net::UnixDatagram;
198    /// # use uds_fork::{UnixDatagramExt, UnixSocketAddr};
199    /// #
200    /// # fn main() -> Result<(), std::io::Error> {
201    /// let addr = UnixSocketAddr::new("@abstract")?;
202    /// let socket = UnixDatagram::bind_unix_addr(&addr)?;
203    /// # let _ = socket.send_to_unix_addr(b"where are you", &addr);
204    /// # Ok(())
205    /// # }
206    /// ```
207    ///
208    /// This is equivalent of:
209    ///
210    /// ```
211    /// # use std::os::unix::net::UnixDatagram;
212    /// # use uds_fork::{UnixDatagramExt, UnixSocketAddr};
213    /// #
214    /// # fn main() -> Result<(), std::io::Error> {
215    /// # let addr = UnixSocketAddr::new("/tmp/me")?;
216    /// let socket = UnixDatagram::unbound()?;
217    /// socket.bind_to_unix_addr(&addr)?;
218    /// # let _ = std::fs::remove_file("/tmp/me");
219    /// # Ok(())
220    /// # }
221    /// ```
222    fn bind_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error> 
223        where Self: Sized;
224
225    /// Returns the address of this socket, as a type that fully supports abstract addresses.
226    fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error> 
227    {
228        get_unix_local_addr(self)
229    }
230
231    /// Returns the address of the connected socket, as a type that fully supports abstract addresses.
232    fn peer_unix_addr(&self) -> Result<UnixSocketAddr, io::Error> 
233    {
234        get_unix_peer_addr(self)
235    }
236
237    /// Creates a path or abstract name for the socket.
238    fn bind_to_unix_addr(&self,  addr: &UnixSocketAddr) -> Result<(), io::Error> 
239    {
240        set_unix_local_addr(self, addr)
241    }
242
243    /// Connects the socket to a path-based or abstract named socket.
244    fn connect_to_unix_addr(&self,  addr: &UnixSocketAddr) -> Result<(), io::Error> 
245    {
246        set_unix_peer_addr(self, addr)
247    }
248
249    /// Sends to the specified address, using an address type that
250    /// supports abstract addresses.
251    ///
252    /// # Examples
253    ///
254    /// Send to an abstract address:
255    ///
256    #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
257    #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
258    /// # use std::os::unix::net::UnixDatagram;
259    /// # use uds_fork::{UnixDatagramExt, UnixSocketAddr};
260    /// #
261    /// let socket = UnixDatagram::unbound().expect("create datagram socket");
262    /// let _ = socket.send_to_unix_addr(
263    ///     b"Is there anyone there?",
264    ///     &UnixSocketAddr::from_abstract("somewhere").expect("OS supports abstract addresses"),
265    /// );
266    /// ```
267    fn send_to_unix_addr(&self,  datagram: &[u8],  addr: &UnixSocketAddr) -> Result<usize, io::Error> 
268    {
269        let (sockaddr, socklen) = addr.as_raw_general();
270        
271        return 
272            unsafe {
273                cvt_r!(
274                    sendto(
275                        self.as_raw_fd(),
276                        datagram.as_ptr() as *const c_void,
277                        datagram.len(),
278                        MSG_NOSIGNAL,
279                        sockaddr,
280                        socklen,
281                    )
282                )
283                .map(|signed| signed as usize )
284            };
285    }
286    /// Sends a datagram created from multiple segments to the specified address,
287    /// using an address type that supports abstract addresses.
288    ///
289    /// # Examples
290    ///
291    /// Send a datagram with a fixed header:
292    ///
293    /// ```
294    /// # use std::os::unix::net::UnixDatagram;
295    /// # use std::io::IoSlice;
296    /// # use uds_fork::{UnixDatagramExt, UnixSocketAddr};
297    /// #
298    /// let socket = UnixDatagram::unbound().expect("create datagram socket");
299    /// let to = UnixSocketAddr::new("/var/run/someone.sock").unwrap();
300    /// let msg = [
301    ///     IoSlice::new(b"hello "),
302    ///     IoSlice::new(to.as_pathname().unwrap().to_str().unwrap().as_bytes()),
303    /// ];
304    /// let _ = socket.send_vectored_to_unix_addr(&msg, &to);
305    /// ```
306    fn send_vectored_to_unix_addr(&self,  datagram: &[IoSlice],  addr: &UnixSocketAddr) -> Result<usize, io::Error> 
307    {
308        send_ancillary(self, Some(addr), 0, datagram, Vec::new(), None)
309    }
310
311    /// Receives from any peer, storing its address in a type that exposes
312    /// abstract addresses.
313    ///
314    /// # Examples
315    ///
316    /// Respond to the received datagram, regardsless of where it was sent from:
317    ///
318    /// ```
319    /// use std::os::unix::net::UnixDatagram;
320    /// use uds_fork::{UnixSocketAddr, UnixDatagramExt};
321    ///
322    /// let dir = tempfile::tempdir().unwrap();
323    /// let mut file_path = dir.path().join("echo.sock");
324    /// 
325    /// let server = UnixDatagram::bind(&file_path).expect("create server socket");
326    ///
327    /// let mut cli_file_path = dir.path().join("echo_client.sock");
328    /// 
329    /// let client_addr = UnixSocketAddr::new("@echo_client")
330    ///     .or(UnixSocketAddr::new(cli_file_path.as_os_str().to_str().unwrap()))
331    ///     .unwrap();
332    /// let client = UnixDatagram::unbound().expect("create client ocket");
333    /// client.bind_to_unix_addr(&client_addr).expect("create client socket");
334    /// client.connect_to_unix_addr(&UnixSocketAddr::new(file_path.as_os_str().to_str().unwrap()).unwrap())
335    ///     .expect("connect to server");
336    /// client.send(b"hello").expect("send");
337    ///
338    /// let mut buf = [0; 1024];
339    /// let (len, from) = server.recv_from_unix_addr(&mut buf).expect("receive");
340    /// server.send_to_unix_addr(&buf[..len], &from).expect("respond");
341    ///
342    /// let len = client.recv(&mut buf).expect("receive response");
343    /// assert_eq!(&buf[..len], "hello".as_bytes());
344    ///
345    /// let _ = std::fs::remove_file(&file_path);
346    /// if let Some(client_path) = client_addr.as_pathname() {
347    ///     let _ = std::fs::remove_file(client_path);
348    /// }
349    /// ```
350    fn recv_from_unix_addr(&self,  buf: &mut[u8]) -> Result<(usize, UnixSocketAddr), io::Error> 
351    {
352        UnixSocketAddr::new_from_ffi(
353            |addr, len| 
354            {
355                unsafe {
356                    cvt_r!(
357                        recvfrom(
358                            self.as_raw_fd(),
359                            buf.as_ptr() as *mut c_void,
360                            buf.len(),
361                            MSG_NOSIGNAL,
362                            addr,
363                            len,
364                        )
365                    )
366                    .map(|signed| signed as usize )
367                }
368            }
369        )
370    }
371    /// Uses multiple buffers to receive from any peer, storing its address in
372    /// a type that exposes abstract addresses.
373    fn recv_vectored_from_unix_addr(&self,  bufs: &mut[IoSliceMut]) -> Result<(usize, UnixSocketAddr), io::Error> 
374    {
375        let mut addr = UnixSocketAddr::default();
376
377        recv_fds(self, Some(&mut addr), bufs, None)
378            .map(|(bytes, _, _)| (bytes, addr) )
379    }
380    
381    /// Reads the next datagram without removing it from the queue.
382    ///
383    /// # Examples
384    ///
385    /// Discard datagram if it's the wrong protocol:
386    ///
387    /// ```
388    /// # use std::os::unix::net::UnixDatagram;
389    /// # use uds_fork::{UnixSocketAddr, UnixDatagramExt};
390    /// #
391    /// let checker = UnixDatagram::bind("/tmp/checker.sock").expect("create receiver socket");
392    ///
393    /// let client = UnixDatagram::unbound().expect("create client ocket");
394    /// client.send_to(b"hello", "/tmp/checker.sock").expect("send");
395    ///
396    /// let mut header = [0; 4];
397    /// let (len, _from) = checker.peek_from_unix_addr(&mut header).expect("receive");
398    /// if len != 4  ||  header != *b"WTFP" {
399    ///     let _ = checker.recv(&mut header); // discard
400    /// } else {
401    ///     // call function that receives and processes it
402    /// }
403    /// #
404    /// # let _ = std::fs::remove_file("/tmp/checker.sock");
405    /// ```
406    fn peek_from_unix_addr(&self,  buf: &mut[u8]) -> Result<(usize, UnixSocketAddr), io::Error> 
407    {
408        UnixSocketAddr::new_from_ffi(
409            |addr, len| 
410            {
411            unsafe 
412            {
413                cvt_r!(
414                    recvfrom(
415                        self.as_raw_fd(),
416                        buf.as_ptr() as *mut c_void,
417                        buf.len(),
418                        MSG_PEEK | MSG_NOSIGNAL,
419                        addr,
420                        len,
421                    )
422                )
423                .map(|signed| signed as usize )
424            }
425        })
426    }
427
428    /// Uses multiple buffers to read the next datagram without removing it
429    /// from the queue.
430    ///
431    /// # Examples
432    ///
433    #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
434    #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
435    /// use std::os::unix::net::UnixDatagram;
436    /// use std::io::IoSliceMut;
437    /// use tempfile::TempDir;
438    /// use uds_fork::{UnixDatagramExt, UnixSocketAddr};
439    /// 
440    /// let dir = tempfile::tempdir().unwrap();
441    /// let mut path = dir.path().join("datagram_server.sock");
442    /// 
443    /// let server = UnixDatagram::bind(&path).unwrap();
444    ///
445    /// // get a random abstract address on Linux
446    /// let client = UnixDatagram::unbound().unwrap();
447    /// client.bind_to_unix_addr(&UnixSocketAddr::new_unspecified()).unwrap();
448    /// client.connect(&path).unwrap();
449    /// client.send(b"headerbodybody").unwrap();
450    ///
451    /// let (mut buf_a, mut buf_b) = ([0; 6], [0; 12]);
452    /// let mut vector = [IoSliceMut::new(&mut buf_a), IoSliceMut::new(&mut buf_b)];
453    /// let (bytes, addr) = server.peek_vectored_from_unix_addr(&mut vector).unwrap();
454    /// assert_eq!(addr, client.local_unix_addr().unwrap());
455    /// assert_eq!(bytes, 14);
456    /// assert_eq!(&buf_a, b"header");
457    /// assert_eq!(&buf_b[..8], b"bodybody");
458    /// #
459    /// ```
460    fn peek_vectored_from_unix_addr(&self,  bufs: &mut[IoSliceMut]) -> Result<(usize, UnixSocketAddr), io::Error> 
461    {
462        let mut addr = UnixSocketAddr::default();
463
464        recv_ancillary(self,Some(&mut addr),MSG_PEEK | MSG_NOSIGNAL, bufs,&mut[])
465            .map(|(bytes, _)| (bytes, addr) )
466    }
467
468    /// Sends file descriptors along with the datagram, on an unconnected socket.
469    fn send_fds_to(&self, datagram: &[u8], fds: Vec<OwnedFd>, addr: &UnixSocketAddr) -> Result<usize, io::Error> 
470    {
471        send_ancillary(self, Some(addr), 0, &[IoSlice::new(datagram)], fds, None)
472    }
473
474    /// Sends file descriptors along with the datagram, on a connected socket.
475    fn send_fds(&self, datagram: &[u8], fds: Vec<OwnedFd>) -> Result<usize, io::Error> 
476    {
477        send_ancillary(self, None, 0, &[IoSlice::new(datagram)], fds, None)
478    }
479
480    /// Receives file descriptors along with the datagram, on an unconnected socket
481    fn recv_fds_from(&self,  buf: &mut[u8],  fd_buf: &mut Vec<OwnedFd>) -> Result<(usize, usize, UnixSocketAddr), io::Error> 
482    {
483        let mut addr = UnixSocketAddr::default();
484        recv_fds(self, Some(&mut addr), &mut[IoSliceMut::new(buf)], Some(fd_buf))
485            .map(|(bytes, _, fds)| (bytes, fds, addr) )
486    }
487
488    /// Receives file descriptors along with the datagram, on a connected socket
489    fn recv_fds(&self,  buf: &mut[u8],  fd_buf: &mut Vec<OwnedFd>) -> Result<(usize, usize), io::Error> 
490    {
491        recv_fds(self, None, &mut[IoSliceMut::new(buf)], Some(fd_buf))
492            .map(|(bytes, _, fds)| (bytes, fds) )
493    }
494
495    /// Returns the credentials of the process that created a socket pair.
496    ///
497    /// This information is only available on Linux, and only for sockets that
498    /// was created with `pair()` or the underlying `socketpair()`.
499    /// For sockets that have merely been "connected" to an address
500    /// or not connected at all, an error of kind `NotConnected`
501    /// or `InvalidInput` is returned.
502    ///
503    /// The use cases of this function gotta be very narrow:
504    ///
505    /// * It will return the credentials of the current process unless
506    ///   the side of the socket this method is called on was received via
507    ///   FD-passing or inherited from a parent.
508    /// * If it was created by the direct parent process,
509    ///   one might as well use `getppid()` and go from there?
510    /// * A returned pid can be repurposed by the OS before the call returns.
511    /// * uids or groups will be those in effect when the pair was created,
512    ///   and will not reflect changes in privileges.
513    ///
514    /// Despite these limitations, the feature is supported by Linux at least
515    /// (but not macOS or FreeBSD), so might as well expose it.
516    fn initial_pair_credentials(&self) -> Result<ConnCredentials, io::Error> 
517    {
518        peer_credentials(self)
519    }
520    /// Returns the SELinux security context of the process that created a socket pair.
521    ///
522    /// Has the same limitations and gotchas as `initial_pair_credentials()`,
523    /// and will return an error on other OSes than Linux or Android
524    /// or if running under kubernetes.
525    ///
526    /// The default security context is the string `unconfined`.
527    fn initial_pair_selinux_context(&self,  buffer: &mut[u8]) -> Result<usize, io::Error> 
528    {
529        selinux_context(self, buffer)
530    }
531}
532
533impl UnixDatagramExt for UnixDatagram 
534{
535    fn bind_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error> 
536    {
537        return 
538            UnixDatagram::unbound()
539                .map_or_else(
540                    |e| Err(e), 
541                    |socket|
542                        socket
543                            .bind_to_unix_addr(addr)
544                            .map_or_else(
545                                |e| Err(e), 
546                                |_| Ok(socket)
547                            )
548                );
549    }
550}
551
552#[cfg(feature = "mio")]
553impl UnixDatagramExt for mio::net::UnixDatagram 
554{
555    fn bind_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error> 
556    {
557        return 
558            mio::net::UnixDatagram
559                ::unbound()
560                    .map_or_else(
561                        |e| Err(e), 
562                        |socket|
563                            socket
564                                .bind_to_unix_addr(addr)
565                                .map_or_else(
566                                    |e| Err(e), 
567                                    |_| Ok(socket)
568                                )
569                    );
570    }
571}