1use std::sync::Arc;
12
13mod boot_guard;
14mod connection;
15mod dispatch_trait;
16mod locks;
17mod process_files;
18mod run_daemon;
19
20pub use dispatch_trait::*;
21
22#[cfg(all(unix, feature = "fault-injection"))]
23pub use connection::handle_conn_for_test;
24use connection::*;
25
26#[cfg(unix)]
27pub use run_daemon::*;
28
29#[cfg(unix)]
30pub use boot_guard::*;
31
32#[cfg(all(test, unix))]
33use locks::open_lock_file;
34#[cfg(unix)]
35pub use locks::{
36 acquire_daemon_boot_guard, acquire_recovery_lock, try_acquire_daemon_boot_guard_until,
37 try_acquire_recoverer_lock_until, DaemonBootGuard,
38};
39#[cfg(unix)]
40pub(crate) use locks::{peer_uid, uid_is_permitted};
41#[cfg(unix)]
42use locks::{socket_identity, SocketIdentity};
43pub use process_files::*;
44
45mod store_guard;
46mod store_identity;
47#[cfg(unix)]
48use store_guard::ensure_claimed_parent_identity;
49#[cfg(unix)]
50pub use store_guard::{acquire_daemon_store_guards, bind_daemon_store_files, claim_stores};
51pub use store_guard::{assert_daemon_store_identities, DaemonStoreGuard};
52#[cfg(unix)]
53pub use store_identity::claimed_daemon_store_identity;
54mod supervisor_marker;
55#[cfg(unix)]
56pub use supervisor_marker::supervisor_marker_path;
57
58#[cfg(unix)]
59use std::io::Write as _;
60#[cfg(unix)]
61use std::os::unix::fs::{MetadataExt, PermissionsExt};
62#[cfg(unix)]
63use std::os::unix::io::AsRawFd;
64#[cfg(all(test, unix))]
65use std::path::PathBuf;
66
67#[cfg(unix)]
68use async_trait::async_trait;
69#[cfg(unix)]
70use libc;
71#[cfg(unix)]
72use serde::Deserialize;
73#[cfg(unix)]
74use tokio::io::AsyncReadExt;
75#[cfg(all(test, unix))]
76use tokio::io::AsyncWriteExt;
77#[cfg(unix)]
78use tokio::net::{UnixListener, UnixStream};
79
80#[cfg(unix)]
81use crate::pack::RequestIdentity;
82#[cfg(unix)]
83use khive_db::{run_checkpoint_task, CheckpointConfig, CheckpointLifecycleOwner, ConnectionPool};
84
85mod exit_record;
88mod lifecycle;
89#[cfg(unix)]
90use lifecycle::khive_dir;
91#[cfg(test)]
92use lifecycle::khive_root_from;
93#[cfg(unix)]
94use lifecycle::{
95 current_supervisor_claim, default_socket_path, ensure_rendezvous_overrides_paired,
96 read_supervisor_marker_claim, DaemonLifecycle, PID_PATH_ENV, SOCKET_PATH_ENV,
97};
98pub use lifecycle::{
99 lock_path, volume_lock_dir, DaemonLifecyclePhase, DaemonLifecycleSnapshot, DaemonLifetime,
100 DaemonOptions, DaemonShutdownReason, DaemonStartupReport, DEFAULT_DEMAND_IDLE_SECS,
101};
102#[cfg(unix)]
103pub use lifecycle::{
104 pid_path, recoverer_lock_path, rendezvous_split, socket_path, RendezvousSplit,
105 SUPERVISOR_CLAIM_ENV,
106};
107
108mod load_limits;
109#[cfg(unix)]
110use load_limits::{admit_or_refuse_busy, ConnectionAdmission};
111pub use load_limits::{
112 recall_ledger_snapshot, track_recall_ledger_task, ConnectionCapSnapshot, RecallLedgerSnapshot,
113};
114
115pub const MAX_FRAME_BYTES: usize = 8 * 1024 * 1024;
117
118pub const PROTOCOL_VERSION: u32 = 8;
127
128#[doc(hidden)]
132pub const DAEMON_LEXICAL_TIMEOUT_MARKER: &str = "__khive_daemon_lexical_timeout";
133
134const DEFAULT_DRAIN_TIMEOUT_SECS: u64 = 10;
135#[cfg(unix)]
139const INITIAL_FRAME_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
140
141#[cfg(unix)]
142fn next_accept_error_backoff(previous: Option<std::time::Duration>) -> std::time::Duration {
143 previous
144 .map(|delay| delay.saturating_mul(2))
145 .unwrap_or_else(|| std::time::Duration::from_millis(10))
146 .min(std::time::Duration::from_secs(1))
147}
148
149mod config_id;
152#[cfg(test)]
153use config_id::parse_config_id;
154pub use config_id::{
155 config_id_extra_embedder_exclusions, config_ids_compatible, first_config_mismatch_field,
156};
157
158mod wire_frames;
159#[cfg(unix)]
160pub use wire_frames::{read_frame, write_frame};
161#[cfg(unix)]
162use wire_frames::{read_initial_frame, take_daemon_lexical_timeout_marker};
163pub use wire_frames::{
164 CheckpointStoreMetrics, DaemonDispatchError, DaemonRequestFrame, DaemonResponseFrame,
165 MetricsSnapshot, ERROR_DETAIL_NESTING_DEPTH_LIMIT,
166};
167
168#[cfg(unix)]
170pub fn env_truthy(key: &str) -> bool {
171 std::env::var(key)
172 .map(|v| {
173 let v = v.trim();
174 !v.is_empty() && v != "0" && !v.eq_ignore_ascii_case("false")
175 })
176 .unwrap_or(false)
177}
178
179include!("daemon_khive_root_tests.rs");
180
181#[cfg(all(unix, any(test, feature = "test-internals")))]
187#[doc(hidden)]
188pub async fn serve_connection_for_test<D: DaemonDispatch>(stream: UnixStream, dispatcher: D) {
189 handle_conn_with_shutdown(
190 stream,
191 dispatcher,
192 None,
193 tokio::time::Instant::now() + INITIAL_FRAME_READ_TIMEOUT,
194 )
195 .await;
196}
197
198#[cfg(all(test, unix))]
199#[path = "daemon_tests.rs"]
200mod tests;