//! One `state.sock` connection: `memoryd` asks for a session's state when a turn ends, and the //! answer is what the state store holds (M5c spec, section 7). It reads, and never changes //! anything: no state, no audit record. use std::os::unix::net::UnixStream; use bxcore::{ErrorCode, Message, SessionStateReply, WireError}; use crate::broker::{Broker, forbid, read_request, send}; use crate::state::StateStore; /// The socket's name in the lines `brokerd` logs and the errors it sends. pub const SOCKET: &str = "state.sock"; /// Serve one `state.sock` connection from `memoryd`: one question, one final answer, then the /// connection is closed. pub fn handle(mut stream: UnixStream, broker: &Broker) { // 1. The peer is gone before it speaks, or its frame is malformed: answered, then return. let Some(envelope) = read_request(&mut stream) else { return; }; let id = envelope.id; let msg = envelope.msg; // 2. Only the question belongs here. `bxcore::SessionState` is matched through `Message`, so // this file names neither it nor `policy::SessionState`, which the store returns. let Message::SessionState(question) = msg else { forbid(broker, &mut stream, id, &msg, SOCKET); return; }; // 3. The store the ledger writes. A session without a file is the store's default, `private` // and trusted; a file that cannot be read is an error, never that default. let store = StateStore::new(&broker.cfg().state_dir()); let response = match store.read(&question.session) { Ok(state) => Message::SessionStateReply(SessionStateReply { class: state.taint, untrusted: state.untrusted, }), Err(e) => { broker.log(&format!("brokerd: {e}")); Message::Error(WireError { code: ErrorCode::Internal, detail: e.to_string(), }) } }; // 4. The final frame; a failed send is ignored, as the peer is gone. let _ = send(&mut stream, id, true, response); }