hyprwire 0.3.0

A fast and consistent wire protocol for IPC
Documentation
use crate::client::client_socket;
use crate::server::server_client;
use crate::{socket, steady_millis, trace};
use hyprwire_core::message;
use hyprwire_core::message::Message;
use hyprwire_core::message::wire::{
    bind_protocol, fatal_protocol_error, generic_protocol_message, handshake_ack, handshake_begin,
    handshake_protocols, hello, new_object, roundtrip_done, roundtrip_request,
};
use std::os::fd::AsRawFd;

pub enum Role<'a> {
    Client(&'a client_socket::ClientSocket),
    Server(&'a server_client::ServerClientState),
}

impl<'a> Role<'a> {
    fn state(&self) -> &crate::ConnectionState {
        match self {
            Self::Client(client) => &client.state,
            Self::Server(client) => &client.state,
        }
    }

    fn label(&self) -> &'static str {
        match self {
            Role::Client(_) => "server",
            Role::Server(_) => "client",
        }
    }
}

pub fn handle_message<D: 'static>(
    raw: &mut socket::SocketRawParsedMessage,
    role: &Role,
    dispatch: &mut D,
) -> Result<(), message::Error> {
    let mut needle = 0;
    while needle < raw.data.len() {
        let Ok(message) = message::MessageType::try_from(raw.data[needle]) else {
            crate::log_error!(
                "server at fd {} core protocol error: invalid message recvd (invalid type code)",
                role.state().stream.as_raw_fd()
            );

            return Err(message::Error::InvalidMessage);
        };

        needle += match (role, message) {
            (Role::Client(client), message::MessageType::HandshakeBegin) => {
                let msg = handshake_begin::HandshakeBegin::from_bytes(&raw.data, needle)
                    .inspect_err(|_| {
                        crate::log_error!(
                            "server at fd {} core protocol error...",
                            client.state.stream.as_raw_fd()
                        );
                    })?;

                if !msg.versions().contains(&crate::PROTOCOL_VERSION) {
                    crate::log_error!(
                        "server at fd {} core protocol error: version negotiation failed",
                        client.state.stream.as_raw_fd()
                    );
                    client.state.error.set(true);
                    return Err(message::Error::VersionNegotiationFailed);
                }

                trace! {
                    crate::log_debug!("[hw] trace: [{} @ {:.3}] -> parse error: {}", client.state.stream.as_raw_fd(), steady_millis(), msg.parse_data())
                }

                client
                    .state
                    .send_message(&handshake_ack::HandshakeAck::new(crate::PROTOCOL_VERSION));

                Ok(msg.data().len())
            }
            (Role::Client(client), message::MessageType::HandshakeProtocols) => {
                let msg = handshake_protocols::HandshakeProtocols::from_bytes(&raw.data, needle).inspect_err(|_| {
                    crate::log_error!(
                        "server at fd {} core protocol error: malformed message recvd (HandshakeProtocols)",
                        client.state.stream.as_raw_fd()
                    );
                })?;

                trace! {
                    crate::log_debug!("[hw] trace: [{} @ {:.3}] <- {}", client.state.stream.as_raw_fd(), steady_millis(), msg.parse_data())
                }

                client.server_specs(msg.protocols());
                client.handshake_done.set(true);

                Ok(msg.data().len())
            }
            (Role::Client(client), message::MessageType::NewObject) => {
                let msg = new_object::NewObject::from_bytes(&raw.data, needle).inspect_err(|_| {
                    crate::log_error!(
                        "server at fd {} core protocol error: malformed message recvd (NewObject)",
                        client.state.stream.as_raw_fd()
                    );
                })?;

                trace! {
                    crate::log_debug!("[hw] trace: [{} @ {:.3}] <- {}", client.state.stream.as_raw_fd(), steady_millis(), msg.parse_data())
                }

                client.on_seq(msg.seq(), msg.id());

                Ok(msg.data().len())
            }
            (Role::Client(client), message::MessageType::GenericProtocolMessage) => {
                let msg = generic_protocol_message::GenericProtocolMessage::from_bytes(&raw.data, &mut raw.fds, needle)
                    .inspect_err(|e| {
                        match e {
                            message::Error::ArrayTooLong => {
                                trace! { crate::log_debug!("GenericProtocolMessage: failed demarshaling array message, array max size is 10000.") };
                            }
                            message::Error::MalformedMessage => {
                                trace! { crate::log_debug!("[hw] trace: GenericProtocolMessage: failed demarshaling array message") };
                            }
                            _ => {}
                        }
                        crate::log_error!(
                            "server at fd {} core protocol error: malformed message recvd (GenericProtocolMessage)",
                            client.state.stream.as_raw_fd()
                        );
                    })?;

                trace! {
                    crate::log_debug!("[hw] trace: [{} @ {:.3}] <- {}", client.state.stream.as_raw_fd(), steady_millis(), msg.parse_data())
                }

                let msg_len = msg.data().len();
                client.on_generic(&msg, dispatch);

                Ok(msg_len)
            }
            (Role::Client(client), message::MessageType::FatalProtocolError) => {
                let msg = fatal_protocol_error::FatalProtocolError::from_bytes(&raw.data, needle)
                    .inspect_err(|_| {
                        crate::log_error!(
                        "server at fd {} core protocol error: malformed message recvd (FatalProtocolError)",
                        client.state.stream.as_raw_fd()
                    );
                    })?;

                crate::log_error!(
                    "fatal protocol error: object {} error {}: {}",
                    msg.object_id(),
                    msg.error_id(),
                    msg.error_msg()
                );
                client.state.error.set(true);

                Ok(msg.data().len())
            }
            (Role::Client(client), message::MessageType::RoundtripDone) => {
                let msg = roundtrip_done::RoundtripDone::from_bytes(&raw.data, needle)
                    .inspect_err(|_| {
                        crate::log_error!(
                        "server at fd {} core protocol error: malformed message recvd (RoundtripDone)",
                        client.state.stream.as_raw_fd()
                    );
                    })?;

                trace! {
                    crate::log_debug!("[hw] trace: [{} @ {:.3}] <- {}", client.state.stream.as_raw_fd(), steady_millis(), msg.parse_data())
                }

                client.last_ackd_roundtrip_seq.set(msg.seq());

                Ok(msg.data().len())
            }
            (Role::Server(client), message::MessageType::Sup) => {
                let msg = hello::Hello::from_bytes(&raw.data, needle).inspect_err(|_| {
                    crate::log_error!(
                        "client at fd {} core protocol error: malformed message recvd (Sup)",
                        client.state.stream.as_raw_fd()
                    );
                })?;

                trace! {
                    crate::log_debug!("[hw] trace: [{} @ {:.3}] <- {}", client.state.stream.as_raw_fd(), steady_millis(), msg.parse_data())
                }

                client.dispatch_first_poll();
                client
                    .state
                    .send_message(&handshake_begin::HandshakeBegin::new(&[1]));

                Ok(msg.data().len())
            }
            (Role::Server(client), message::MessageType::HandshakeAck) => {
                let msg = handshake_ack::HandshakeAck::from_bytes(&raw.data, needle).inspect_err(|_| {
                    crate::log_error!(
                        "client at fd {} core protocol error: malformed message recvd (HandshakeAck)",
                        client.state.stream.as_raw_fd()
                    );
                })?;

                trace! {
                    crate::log_debug!("[hw] trace: [{} @ {:.3}] <- {}", client.state.stream.as_raw_fd(), steady_millis(), msg.parse_data())
                }

                client.version.set(msg.version());

                let protocol_names = client
                    .state
                    .impls
                    .borrow()
                    .iter()
                    .map(|imp| {
                        format!(
                            "{}@{}",
                            imp.protocol().spec_name(),
                            imp.protocol().spec_ver()
                        )
                    })
                    .collect::<Vec<_>>();

                client
                    .state
                    .send_message(&handshake_protocols::HandshakeProtocols::new(
                        &protocol_names,
                    ));

                Ok(msg.data().len())
            }
            (Role::Server(client), message::MessageType::BindProtocol) => {
                let msg = bind_protocol::BindProtocol::from_bytes(&raw.data, needle).inspect_err(|_| {
                    crate::log_error!(
                        "client at fd {} core protocol error: malformed message recvd (BindProtocol)",
                        client.state.stream.as_raw_fd()
                    );
                })?;

                trace! {
                    crate::log_debug!("[hw] trace: [{} @ {:.3}] <- {}", client.state.stream.as_raw_fd(), steady_millis(), msg.parse_data())
                }

                client.create_object(msg.protocol(), "", msg.version(), msg.seq());

                Ok(msg.data().len())
            }
            (Role::Server(client), message::MessageType::GenericProtocolMessage) => {
                let msg = generic_protocol_message::GenericProtocolMessage::from_bytes(&raw.data, &mut raw.fds, needle)
                    .inspect_err(|e| {
                        match e {
                            message::Error::ArrayTooLong => {
                                trace! { crate::log_debug!("GenericProtocolMessage: failed demarshaling array message, array max size is 10000.") };
                            }
                            message::Error::MalformedMessage => {
                                trace! { crate::log_debug!("[hw] trace: GenericProtocolMessage: failed demarshaling array message") };
                            }
                            _ => {}
                        }
                        crate::log_error!(
                            "client at fd {} core protocol error: malformed message recvd (GenericProtocolMessage)",
                            client.state.stream.as_raw_fd()
                        );
                    })?;

                trace! {
                    crate::log_debug!("[hw] trace: [{} @ {:.3}] <- {}", client.state.stream.as_raw_fd(), steady_millis(), msg.parse_data())
                }

                client.on_generic(&msg, dispatch);

                Ok(msg.data().len())
            }
            (Role::Server(client), message::MessageType::RoundtripRequest) => {
                let msg = roundtrip_request::RoundtripRequest::from_bytes(&raw.data, needle).inspect_err(|_| {
                    crate::log_error!(
                        "client at fd {} core protocol error: malformed message recvd (RoundtripRequest)",
                        client.state.stream.as_raw_fd()
                    );
                })?;

                trace! {
                    crate::log_debug!("[hw] trace: [{} @ {:.3}] <- {}", client.state.stream.as_raw_fd(), steady_millis(), msg.parse_data())
                }

                client.scheduled_roundtrip_seq.set(msg.seq());

                Ok(msg.data().len())
            }
            (
                Role::Client(_),
                message::MessageType::BindProtocol
                | message::MessageType::HandshakeAck
                | message::MessageType::RoundtripRequest
                | message::MessageType::Sup,
            )
            | (
                Role::Server(_),
                message::MessageType::NewObject
                | message::MessageType::HandshakeProtocols
                | message::MessageType::HandshakeBegin
                | message::MessageType::FatalProtocolError
                | message::MessageType::RoundtripDone,
            ) => {
                let state = role.state();
                state.error.set(true);

                crate::log_error!(
                    "{} at fd {} core protocol error: invalid message recvd ({message})",
                    role.label(),
                    state.stream.as_raw_fd()
                );

                Err(message::Error::InvalidMessage)
            }
        }?;
    }

    if !raw.fds.is_empty() {
        return Err(message::Error::MalformedMessage);
    }

    trace! {
        crate::log_debug!("[hw] trace: [{} @ {}] -- handleMessage: Finished read", role.state().stream.as_raw_fd(), steady_millis())
    }

    Ok(())
}