gio_unix/
fd_message.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::os::unix::io::{AsRawFd, RawFd};
4use std::{mem, ptr};
5
6use glib::{prelude::*, translate::*};
7
8use crate::{ffi, FDMessage};
9
10pub trait FDMessageExtManual: IsA<FDMessage> + Sized {
11    /// Adds a file descriptor to @self.
12    ///
13    /// The file descriptor is duplicated using dup(). You keep your copy
14    /// of the descriptor and the copy contained in @self will be closed
15    /// when @self is finalized.
16    ///
17    /// A possible cause of failure is exceeding the per-process or
18    /// system-wide file descriptor limit.
19    /// ## `fd`
20    /// a valid open file descriptor
21    ///
22    /// # Returns
23    ///
24    /// [`true`] in case of success, else [`false`] (and @error is set)
25    #[doc(alias = "g_unix_fd_message_append_fd")]
26    fn append_fd<T: AsRawFd>(&self, fd: T) -> Result<(), glib::Error> {
27        unsafe {
28            let mut error = ptr::null_mut();
29            ffi::g_unix_fd_message_append_fd(
30                self.as_ref().to_glib_none().0,
31                fd.as_raw_fd(),
32                &mut error,
33            );
34            if error.is_null() {
35                Ok(())
36            } else {
37                Err(from_glib_full(error))
38            }
39        }
40    }
41    /// Returns the array of file descriptors that is contained in this
42    /// object.
43    ///
44    /// After this call, the descriptors are no longer contained in
45    /// @self. Further calls will return an empty list (unless more
46    /// descriptors have been added).
47    ///
48    /// The return result of this function must be freed with g_free().
49    /// The caller is also responsible for closing all of the file
50    /// descriptors.
51    ///
52    /// If @length is non-[`None`] then it is set to the number of file
53    /// descriptors in the returned array. The returned array is also
54    /// terminated with -1.
55    ///
56    /// This function never returns [`None`]. In case there are no file
57    /// descriptors contained in @self, an empty array is returned.
58    ///
59    /// # Returns
60    ///
61    /// an array of file
62    ///     descriptors
63    #[doc(alias = "g_unix_fd_message_steal_fds")]
64    fn steal_fds(&self) -> Vec<RawFd> {
65        unsafe {
66            let mut length = mem::MaybeUninit::uninit();
67            let ret = FromGlibContainer::from_glib_full_num(
68                ffi::g_unix_fd_message_steal_fds(
69                    self.as_ref().to_glib_none().0,
70                    length.as_mut_ptr(),
71                ),
72                length.assume_init() as usize,
73            );
74            ret
75        }
76    }
77}
78
79impl<O: IsA<FDMessage>> FDMessageExtManual for O {}
80
81#[cfg(test)]
82mod tests {
83    use std::{
84        io,
85        os::unix::io::{AsRawFd, FromRawFd, OwnedFd},
86    };
87
88    use crate::prelude::*;
89    use gio::prelude::UnixFDListExt;
90    use gio::Cancellable;
91    use gio::Socket;
92    use glib::prelude::Cast;
93
94    #[test]
95    fn socket_messages() {
96        let mut fds = [0 as libc::c_int; 2];
97        let (out_sock, in_sock) = unsafe {
98            let ret = libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr());
99            if ret != 0 {
100                panic!("{}", io::Error::last_os_error());
101            }
102            (
103                Socket::from_fd(OwnedFd::from_raw_fd(fds[0])).unwrap(),
104                Socket::from_fd(OwnedFd::from_raw_fd(fds[1])).unwrap(),
105            )
106        };
107
108        let fd_msg = crate::FDMessage::new();
109        fd_msg.append_fd(out_sock.as_raw_fd()).unwrap();
110        let vs = [gio::OutputVector::new(&[0])];
111        let ctrl_msgs = [fd_msg.upcast()];
112        let mut out_msg = [gio::OutputMessage::new(
113            gio::SocketAddress::NONE,
114            vs.as_slice(),
115            ctrl_msgs.as_slice(),
116        )];
117        let written = gio::prelude::SocketExtManual::send_messages(
118            &out_sock,
119            out_msg.as_mut_slice(),
120            0,
121            Cancellable::NONE,
122        )
123        .unwrap();
124        assert_eq!(written, 1);
125        assert_eq!(out_msg[0].bytes_sent(), 1);
126
127        let mut v = [0u8];
128        let mut vs = [gio::InputVector::new(v.as_mut_slice())];
129        let mut ctrl_msgs = gio::SocketControlMessages::new();
130        let mut in_msg = [gio::InputMessage::new(
131            None,
132            vs.as_mut_slice(),
133            Some(&mut ctrl_msgs),
134        )];
135        let received = gio::prelude::SocketExtManual::receive_messages(
136            &in_sock,
137            in_msg.as_mut_slice(),
138            0,
139            Cancellable::NONE,
140        )
141        .unwrap();
142
143        assert_eq!(received, 1);
144        assert_eq!(in_msg[0].bytes_received(), 1);
145        assert_eq!(ctrl_msgs.len(), 1);
146        let fds = ctrl_msgs[0]
147            .downcast_ref::<crate::FDMessage>()
148            .unwrap()
149            .fd_list();
150        assert_eq!(fds.length(), 1);
151    }
152}