Skip to main content

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::{FDMessage, ffi};
9
10pub trait FDMessageExtManual: IsA<FDMessage> + Sized {
11    #[doc(alias = "g_unix_fd_message_append_fd")]
12    fn append_fd<T: AsRawFd>(&self, fd: T) -> Result<(), glib::Error> {
13        unsafe {
14            let mut error = ptr::null_mut();
15            ffi::g_unix_fd_message_append_fd(
16                self.as_ref().to_glib_none().0,
17                fd.as_raw_fd(),
18                &mut error,
19            );
20            if error.is_null() {
21                Ok(())
22            } else {
23                Err(from_glib_full(error))
24            }
25        }
26    }
27    #[doc(alias = "g_unix_fd_message_steal_fds")]
28    fn steal_fds(&self) -> Vec<RawFd> {
29        unsafe {
30            let mut length = mem::MaybeUninit::uninit();
31
32            FromGlibContainer::from_glib_full_num(
33                ffi::g_unix_fd_message_steal_fds(
34                    self.as_ref().to_glib_none().0,
35                    length.as_mut_ptr(),
36                ),
37                length.assume_init() as usize,
38            )
39        }
40    }
41}
42
43impl<O: IsA<FDMessage>> FDMessageExtManual for O {}
44
45#[cfg(test)]
46mod tests {
47    use std::{
48        io,
49        os::unix::io::{AsRawFd, FromRawFd, OwnedFd},
50    };
51
52    use crate::prelude::*;
53    use gio::Cancellable;
54    use gio::Socket;
55    use gio::prelude::UnixFDListExt;
56    use glib::prelude::Cast;
57
58    #[test]
59    fn socket_messages() {
60        let mut fds = [0 as libc::c_int; 2];
61        let (out_sock, in_sock) = unsafe {
62            let ret = libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr());
63            if ret != 0 {
64                panic!("{}", io::Error::last_os_error());
65            }
66            (
67                Socket::from_fd(OwnedFd::from_raw_fd(fds[0])).unwrap(),
68                Socket::from_fd(OwnedFd::from_raw_fd(fds[1])).unwrap(),
69            )
70        };
71
72        let fd_msg = crate::FDMessage::new();
73        fd_msg.append_fd(out_sock.as_raw_fd()).unwrap();
74        let vs = [gio::OutputVector::new(&[0])];
75        let ctrl_msgs = [fd_msg.upcast()];
76        let mut out_msg = [gio::OutputMessage::new(
77            gio::SocketAddress::NONE,
78            vs.as_slice(),
79            ctrl_msgs.as_slice(),
80        )];
81        let written = gio::prelude::SocketExtManual::send_messages(
82            &out_sock,
83            out_msg.as_mut_slice(),
84            0,
85            Cancellable::NONE,
86        )
87        .unwrap();
88        assert_eq!(written, 1);
89        assert_eq!(out_msg[0].bytes_sent(), 1);
90
91        let mut v = [0u8];
92        let mut vs = [gio::InputVector::new(v.as_mut_slice())];
93        let mut ctrl_msgs = gio::SocketControlMessages::new();
94        let mut in_msg = [gio::InputMessage::new(
95            None,
96            vs.as_mut_slice(),
97            Some(&mut ctrl_msgs),
98        )];
99        let received = gio::prelude::SocketExtManual::receive_messages(
100            &in_sock,
101            in_msg.as_mut_slice(),
102            0,
103            Cancellable::NONE,
104        )
105        .unwrap();
106
107        assert_eq!(received, 1);
108        assert_eq!(in_msg[0].bytes_received(), 1);
109        assert_eq!(ctrl_msgs.len(), 1);
110        let fds = ctrl_msgs[0]
111            .downcast_ref::<crate::FDMessage>()
112            .unwrap()
113            .fd_list();
114        assert_eq!(fds.length(), 1);
115    }
116}