#![cfg_attr(
dylint_lib = "running_process_env_literal",
deny(running_process_env_direct)
)]
use std::io::{self, Read, Write};
use std::process::ExitCode;
use running_process::broker::backend_handle::DaemonProcess;
use running_process::broker::backend_sdk::{
write_daemon_identity_file, BackendEndpointMux, LegacyClassification, MuxPoll,
};
use running_process::broker::broker_owned_bind;
use running_process::broker::lifecycle::names_v2::{broker_v2_runtime_dir, daemon_identity_path};
use running_process::broker::protocol::{encode_framed, Endpoint, Frame};
use running_process::broker::secure_dir::ensure_private_dir;
use running_process::client::{IpcEndpoint, IpcListener, IpcStream};
use running_process::env_vars;
const LIFECYCLE_TEST_PAYLOAD_PROTOCOL: u32 = 0xF824;
fn main() -> ExitCode {
match run() {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
eprintln!("running-process lifecycle test backend failed: {error}");
ExitCode::from(1)
}
}
}
fn run() -> io::Result<()> {
let service_name = required_env(env_vars::BROKER_V1_SERVICE_NAME)?;
let endpoint_path = required_env(env_vars::BROKER_V1_BACKEND_PIPE)?;
let namespace_id = env_vars::BROKER_V1_BACKEND_NAMESPACE
.string()
.unwrap_or_default();
let endpoint = Endpoint {
namespace_id,
path: endpoint_path.clone(),
};
let listener = match broker_owned_bind::recover_from_env()? {
Some(listener) => listener,
None => IpcListener::bind_owner_only(&IpcEndpoint::new(endpoint_path.clone())?)?,
};
let daemon = DaemonProcess::current_process(endpoint, None).map_err(io::Error::other)?;
let runtime_dir = broker_v2_runtime_dir();
ensure_private_dir(&runtime_dir)?;
write_daemon_identity_file(&daemon_identity_path(&service_name), &daemon)?;
let mux = BackendEndpointMux::new(
daemon,
&[LIFECYCLE_TEST_PAYLOAD_PROTOCOL],
|_buffer: &[u8]| LegacyClassification::NotLegacy,
);
loop {
let mut stream = listener.accept()?;
if let Err(error) = serve_one(&mut stream, &mux) {
eprintln!("running-process lifecycle test backend connection failed: {error}");
}
}
}
fn required_env(var: env_vars::EnvVar) -> io::Result<String> {
var.string().ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("required environment variable {} is missing", var.name),
)
})
}
fn serve_one<F>(stream: &mut IpcStream, mux: &BackendEndpointMux<F>) -> io::Result<()>
where
F: Fn(&[u8]) -> LegacyClassification,
{
let mut buffer = Vec::new();
let mut chunk = [0_u8; 4096];
loop {
match mux.poll(&buffer).map_err(io::Error::other)? {
MuxPoll::NeedMoreBytes => {
let read = stream.read(&mut chunk)?;
if read == 0 {
return Ok(());
}
buffer.extend_from_slice(&chunk[..read]);
}
MuxPoll::ProbeAnswered { reply, .. } => {
stream.write_all(&reply)?;
stream.flush()?;
return Ok(());
}
MuxPoll::Payload { frame, .. } => {
let response =
Frame::response_to(&frame, std::process::id().to_be_bytes().to_vec());
stream.write_all(&encode_framed(&response).map_err(io::Error::other)?)?;
stream.flush()?;
return Ok(());
}
MuxPoll::Legacy => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"lifecycle fixture has no legacy wire",
));
}
}
}
}