rmux-server 0.10.0

Tokio daemon and request dispatcher for the RMUX terminal multiplexer.
Documentation
use rmux_proto::RmuxError;

use super::RequestHandler;
#[cfg(unix)]
use crate::unix_socket::{BoundUnixListener, SocketFileIdentity, UnixTransportAccess};
#[cfg(unix)]
use crate::unix_socket_access::UnixSocketAccessController;

impl RequestHandler {
    pub(in crate::handler) fn transition_unix_transport(
        &self,
        allow_listed: bool,
    ) -> Result<(), RmuxError> {
        #[cfg(unix)]
        {
            let mut transport = self
                .unix_socket_access
                .lock()
                .expect("Unix socket access mutex must not be poisoned");
            let Some(transport) = transport.as_mut() else {
                #[cfg(test)]
                return Ok(());
                #[cfg(not(test))]
                return Err(RmuxError::Server(
                    "Unix socket access controller is not initialized".to_owned(),
                ));
            };
            let target = if allow_listed {
                UnixTransportAccess::AllowListed
            } else {
                UnixTransportAccess::OwnerOnly
            };
            transport.transition(target).map_err(|error| {
                RmuxError::Server(format!("failed to update Unix socket access: {error}"))
            })
        }
        #[cfg(not(unix))]
        {
            let _ = allow_listed;
            Ok(())
        }
    }

    #[cfg(unix)]
    pub(crate) fn install_unix_socket_access_controller(
        &self,
        controller: UnixSocketAccessController,
    ) -> std::io::Result<()> {
        let mut slot = self
            .unix_socket_access
            .lock()
            .expect("Unix socket access mutex must not be poisoned");
        if slot.is_some() {
            return Err(std::io::Error::new(
                std::io::ErrorKind::AlreadyExists,
                "Unix socket access controller is already installed",
            ));
        }
        *slot = Some(controller);
        Ok(())
    }

    #[cfg(all(test, unix))]
    pub(in crate::handler) fn install_unix_socket_access_for_test(
        &self,
        socket_path: &std::path::Path,
        socket_identity: Option<SocketFileIdentity>,
    ) -> std::io::Result<()> {
        self.install_unix_socket_access_controller(UnixSocketAccessController::new(
            socket_path,
            socket_identity,
        )?)
    }

    #[cfg(unix)]
    pub(crate) async fn rebind_unix_socket(
        &self,
        socket_path: &std::path::Path,
        current_identity: Option<SocketFileIdentity>,
    ) -> std::io::Result<BoundUnixListener> {
        let _mutation = self.server_access_mutation.lock().await;
        let access = {
            let transport = self
                .unix_socket_access
                .lock()
                .expect("Unix socket access mutex must not be poisoned");
            let transport = transport.as_ref().ok_or_else(|| {
                std::io::Error::other("Unix socket access controller is not initialized")
            })?;
            transport.validate_rebind_source()?;
            transport.access()
        };
        let rebound =
            crate::unix_socket::rebind_unix_listener_at(socket_path, current_identity, access)?;
        self.unix_socket_access
            .lock()
            .expect("Unix socket access mutex must not be poisoned")
            .as_mut()
            .expect("Unix socket access controller checked above")
            .adopt_rebound_socket(rebound.identity)?;
        Ok(rebound)
    }

    #[cfg(unix)]
    pub(crate) async fn restore_owner_only_unix_transport(&self) -> std::io::Result<()> {
        let _mutation = self.server_access_mutation.lock().await;
        let mut transport = self
            .unix_socket_access
            .lock()
            .expect("Unix socket access mutex must not be poisoned");
        if let Some(transport) = transport.as_mut() {
            transport.transition(UnixTransportAccess::OwnerOnly)?;
        }
        Ok(())
    }

    #[cfg(all(test, unix))]
    pub(in crate::handler) fn fail_next_unix_transport_transition_for_test(&self) {
        self.unix_socket_access
            .lock()
            .expect("Unix socket access mutex must not be poisoned")
            .as_mut()
            .expect("Unix socket access controller must be installed")
            .fail_next_transition_after_first_mode_change();
    }
}