Milestone 5: metered awareness, DSCP, systemd, man pages, packaging
Metered detection polls NetworkManager's Metered property over D-Bus (feature "metered", default on; builds without D-Bus via no-default-features). While metered the daemon closes incoming blob connections and defers every fetch; VARDE_FORCE_METERED=true forces the state as a kill switch and test hook. Endpoint UDP sockets get DSCP CS1 best-effort by matching bound ports to /proc/net/udp inodes (iroh hides its fds). systemd socket activation adopts LISTEN_FDS fd 3, readiness is a hand-rolled sd_notify READY=1 (abstract + path sockets), and standalone binding still works unchanged. dist/ ships hardened system and user units (DynamicUser, ProtectSystem=strict, StateDirectory, RestrictAddressFamilies), a commented config example, scdoc man pages validated with scdoc, and an untested PKGBUILD skeleton. Tests: activation-socket round trip via a real fd-3 handoff, READY=1 received on a NOTIFY_SOCKET, metered daemons neither serve nor fetch. Dependencies: zbus (optional, feature-gated D-Bus client for the NetworkManager metered flag). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,57 @@ use varde_proto::{Envelope, ErrorCode, Request};
|
||||
|
||||
use crate::daemon::Daemon;
|
||||
|
||||
/// A listener passed in by systemd socket activation (`LISTEN_FDS`),
|
||||
/// if any. Protocol: fds start at 3; `LISTEN_PID`, when set, must be us.
|
||||
pub fn activation_listener() -> Result<Option<UnixListener>> {
|
||||
let Ok(listen_fds) = std::env::var("LISTEN_FDS") else {
|
||||
return Ok(None);
|
||||
};
|
||||
if let Ok(pid) = std::env::var("LISTEN_PID") {
|
||||
if pid != std::process::id().to_string() {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
let n: u32 = listen_fds.parse().context("parsing LISTEN_FDS")?;
|
||||
anyhow::ensure!(n == 1, "expected exactly one activation fd, got {n}");
|
||||
// SAFETY: fd 3 is the first activation fd per the LISTEN_FDS
|
||||
// protocol; we take sole ownership of it.
|
||||
let std_listener = unsafe {
|
||||
use std::os::fd::FromRawFd;
|
||||
std::os::unix::net::UnixListener::from_raw_fd(3)
|
||||
};
|
||||
std_listener
|
||||
.set_nonblocking(true)
|
||||
.context("setting activation socket nonblocking")?;
|
||||
let listener = UnixListener::from_std(std_listener).context("adopting activation socket")?;
|
||||
info!("using systemd activation socket");
|
||||
Ok(Some(listener))
|
||||
}
|
||||
|
||||
/// Tell the service manager we are ready (`sd_notify(READY=1)`),
|
||||
/// hand-rolled to avoid a libsystemd dependency. No-op without
|
||||
/// `NOTIFY_SOCKET`.
|
||||
pub fn notify_ready() {
|
||||
let Some(path) = std::env::var_os("NOTIFY_SOCKET") else {
|
||||
return;
|
||||
};
|
||||
let result = (|| -> std::io::Result<()> {
|
||||
let socket = std::os::unix::net::UnixDatagram::unbound()?;
|
||||
let bytes = path.as_encoded_bytes();
|
||||
if let Some(name) = bytes.strip_prefix(b"@") {
|
||||
use std::os::linux::net::SocketAddrExt;
|
||||
let addr = std::os::unix::net::SocketAddr::from_abstract_name(name)?;
|
||||
socket.send_to_addr(b"READY=1", &addr)?;
|
||||
} else {
|
||||
socket.send_to(b"READY=1", &path)?;
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
if let Err(e) = result {
|
||||
debug!(error = %e, "sd_notify failed");
|
||||
}
|
||||
}
|
||||
|
||||
/// Bind the API socket, replacing a stale socket file if the previous
|
||||
/// daemon did not shut down cleanly.
|
||||
pub fn bind_socket(path: &Path) -> Result<UnixListener> {
|
||||
|
||||
Reference in New Issue
Block a user