Files
boxmaker/crates/brokerd/src/state_socket.rs
T

52 lines
2.0 KiB
Rust

//! 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);
}