hyprwire 0.2.6

A fast and consistent wire protocol for IPC
Documentation
use crate::trace;
use nix::sys::socket;
use std::os::fd::AsRawFd;
use std::os::unix::net;

pub(crate) struct SocketRawParsedMessage {
    pub(crate) data: Box<[u8]>,
    pub(crate) fds: Vec<i32>,
}

impl SocketRawParsedMessage {
    pub(crate) fn read_from_socket(stream: &net::UnixStream) -> nix::Result<Self> {
        const BUFFER_SIZE: usize = 8192;
        const MAX_FDS_PER_MSG: usize = 255;

        let mut data = Vec::new();
        let mut fds = Vec::new();

        loop {
            let mut buffer = [0u8; BUFFER_SIZE];
            let mut iov = [std::io::IoSliceMut::new(&mut buffer)];
            let mut cmsg_buf = nix::cmsg_space!([i32; MAX_FDS_PER_MSG]);

            let msg = match socket::recvmsg::<()>(
                stream.as_raw_fd(),
                &mut iov,
                Some(&mut cmsg_buf),
                socket::MsgFlags::empty(),
            ) {
                Ok(msg) => msg,
                Err(nix::errno::Errno::EAGAIN) => break,
                Err(e) => return Err(e),
            };

            let bytes_received = msg.bytes;
            if bytes_received == 0 {
                break;
            }

            for cmsg in msg.cmsgs().map_err(|_| nix::errno::Errno::ENOBUFS)? {
                if let socket::ControlMessageOwned::ScmRights(received_fds) = cmsg {
                    trace! {
                        eprintln!(
                            "[hw] trace: SocketRawParsedMessage::read_from_socket: got {} fds on the control wire",
                            received_fds.len()
                        )
                    }
                    fds.extend(received_fds);
                }
            }

            data.extend_from_slice(&buffer[..bytes_received]);

            if bytes_received < BUFFER_SIZE {
                break;
            }
        }

        Ok(Self {
            data: data.into_boxed_slice(),
            fds,
        })
    }
}