diff --git a/.github/typos.toml b/.github/typos.toml new file mode 100644 index 0000000000..ef39fb45da --- /dev/null +++ b/.github/typos.toml @@ -0,0 +1,5 @@ +[type.go] +extend-ignore-re = [ + # ignore the generated schema binary string in *.capnp.go files + "const schema_[0-9a-f]+ = \"(\\\\?.|[^\"\\\\])*\"( \\+\\s+\"(\\\\?.|[^\"\\\\])*\")+", +] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 63833441f6..b2b9fcd7c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -277,3 +277,5 @@ jobs: steps: - uses: actions/checkout@v3 - uses: crate-ci/typos@v1.16.4 + with: + config: .github/typos.toml diff --git a/Cargo.lock b/Cargo.lock index 12ba7fd53b..60d1b6bee3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -310,6 +310,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "command-fds" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35cc819120a403d0eb3d0c404088c5a9f9b06066147ec69a21919fbc0833ef68" +dependencies = [ + "nix 0.22.3", + "thiserror", + "tokio", +] + [[package]] name = "conmon-common" version = "0.5.1" @@ -326,6 +337,7 @@ dependencies = [ "capnp", "capnp-rpc", "clap", + "command-fds", "conmon-common", "dashmap", "futures", @@ -336,7 +348,7 @@ dependencies = [ "memchr", "mockall", "multimap", - "nix", + "nix 0.26.2", "notify", "once_cell", "opentelemetry", @@ -354,6 +366,7 @@ dependencies = [ "tokio", "tokio-eventfd", "tokio-fd", + "tokio-seqpacket", "tokio-util", "tracing", "tracing-opentelemetry", @@ -530,6 +543,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +[[package]] +name = "filedesc" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d784862d0aff7e84b808ecd8291d27fb5df5c5edb279f275944484ac52dd45e1" +dependencies = [ + "libc", +] + [[package]] name = "filetime" version = "0.2.22" @@ -1045,7 +1067,7 @@ dependencies = [ "hmac", "libc", "log", - "nix", + "nix 0.26.2", "nom", "once_cell", "serde", @@ -1109,6 +1131,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.7.1" @@ -1187,6 +1218,19 @@ dependencies = [ "serde", ] +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + [[package]] name = "nix" version = "0.26.2" @@ -1196,7 +1240,7 @@ dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", - "memoffset", + "memoffset 0.7.1", "pin-utils", "static_assertions", ] @@ -1468,7 +1512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "059a34f111a9dee2ce1ac2826a68b24601c4298cfeb1a587c3cb493d5ab46f52" dependencies = [ "libc", - "nix", + "nix 0.26.2", ] [[package]] @@ -2054,6 +2098,17 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "tokio-seqpacket" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc46f531b7588ab145a216239aa4a6d682b92f987cd99fe07bea6a22dc1468d1" +dependencies = [ + "filedesc", + "libc", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" diff --git a/Makefile b/Makefile index dce297b452..e4969fc83f 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ integration-static: .install.ginkgo # It needs to be release so we correctly tes $(MAKE) release-static; \ fi && \ export RUNTIME_BINARY="$(RUNTIME_PATH)" && \ - export MAX_RSS_KB=4500 && \ + export MAX_RSS_KB=5000 && \ sudo -E "$(GOTOOLS_BINDIR)/ginkgo" $(TEST_FLAGS) $(GINKGO_FLAGS) .install.ginkgo: diff --git a/conmon-rs/common/proto/conmon.capnp b/conmon-rs/common/proto/conmon.capnp index 5e941d965b..2f78088a78 100644 --- a/conmon-rs/common/proto/conmon.capnp +++ b/conmon-rs/common/proto/conmon.capnp @@ -41,6 +41,8 @@ interface Conmon { metadata @11 :Metadata; # Standard metadata to carry. envVars @12 :TextTextMap; cgroupManager @13 :CgroupManager; + additionalFds @14 :List(UInt64); + leakFds @15 :List(UInt64); } struct LogDriver { @@ -169,6 +171,18 @@ interface Conmon { createNamespaces @6 (request: CreateNamespacesRequest) -> (response: CreateNamespacesResponse); + ############################################### + # StartFdSocket + struct StartFdSocketRequest { + metadata @0 :Metadata; # Standard metadata to carry. + } + + struct StartFdSocketResponse { + path @0 :Text; # The path to the fd socket. + } + + startFdSocket @7 (request: StartFdSocketRequest) -> (response: StartFdSocketResponse); + ############################################### # Helper types diff --git a/conmon-rs/server/Cargo.toml b/conmon-rs/server/Cargo.toml index b9569d05b2..e3b2bb948e 100644 --- a/conmon-rs/server/Cargo.toml +++ b/conmon-rs/server/Cargo.toml @@ -12,6 +12,7 @@ anyhow = "1.0.72" capnp = "0.17.2" capnp-rpc = "0.17.0" clap = { version = "4.3.8", features = ["color", "cargo", "deprecated", "derive", "deprecated", "env", "string", "unicode", "wrap_help"] } +command-fds = { version = "0.2.2", features = ["tokio"] } conmon-common = { path = "../common" } futures = "0.3.28" getset = "0.1.2" @@ -37,6 +38,7 @@ tempfile = "3.7.1" tokio = { version = "1.31.0", features = ["fs", "io-std", "io-util", "macros", "net", "process", "rt", "rt-multi-thread", "signal", "time"] } tokio-eventfd = "0.2.0" tokio-fd = "0.3.0" +tokio-seqpacket = "0.7.0" tokio-util = { version = "0.7.8", features = ["compat"] } tracing = "0.1.37" tracing-opentelemetry = "0.20.0" diff --git a/conmon-rs/server/src/child_reaper.rs b/conmon-rs/server/src/child_reaper.rs index 3ff22816e6..52255749d3 100644 --- a/conmon-rs/server/src/child_reaper.rs +++ b/conmon-rs/server/src/child_reaper.rs @@ -4,7 +4,8 @@ use crate::{ container_io::{ContainerIO, ContainerIOType, SharedContainerIO}, oom_watcher::OOMWatcher, }; -use anyhow::{bail, format_err, Context, Result}; +use anyhow::{bail, Context, Result}; +use command_fds::{tokio::CommandFdAsyncExt, FdMapping}; use getset::{CopyGetters, Getters, Setters}; use libc::pid_t; use multimap::MultiMap; @@ -19,6 +20,7 @@ use nix::{ use std::{ ffi::OsStr, fmt::Write, + os::fd::{AsRawFd, OwnedFd, RawFd}, path::{Path, PathBuf}, process::Stdio, str, @@ -41,11 +43,8 @@ pub struct ChildReaper { grandchildren: Arc>>, } -macro_rules! lock { - ($x:expr) => { - $x.lock().map_err(|e| format_err!("{:#}", e))? - }; -} +/// first usable file descriptor after stdin, stdout and stderr +const FIRST_FD_AFTER_STDIO: RawFd = 3; impl ChildReaper { pub fn get(&self, id: &str) -> Result { @@ -56,6 +55,7 @@ impl ChildReaper { Ok(r) } + #[allow(clippy::too_many_arguments)] pub async fn create_child( &self, cmd: P, @@ -64,6 +64,7 @@ impl ChildReaper { container_io: &mut ContainerIO, pidfile: &Path, env_vars: Vec<(String, String)>, + additional_fds: Vec, ) -> Result<(u32, CancellationToken)> where P: AsRef, @@ -81,9 +82,22 @@ impl ChildReaper { .stdout(Stdio::piped()) .stderr(Stdio::piped()) .envs(env_vars) + .fd_mappings( + additional_fds + .iter() + .enumerate() + .map(|(i, fd)| FdMapping { + parent_fd: fd.as_raw_fd(), + child_fd: i as RawFd + FIRST_FD_AFTER_STDIO, + }) + .collect(), + )? .spawn() .context("spawn child process: {}")?; + // close file descriptors after spawn + drop(additional_fds); + let token = CancellationToken::new(); match container_io.typ_mut() { @@ -134,7 +148,11 @@ impl ChildReaper { Ok((grandchild_pid, token)) } - pub fn watch_grandchild(&self, child: Child) -> Result> { + pub fn watch_grandchild( + &self, + child: Child, + leak_fds: Vec, + ) -> Result> { let locked_grandchildren = &self.grandchildren().clone(); let mut map = lock!(locked_grandchildren); let mut reapable_grandchild = ReapableChild::from_child(&child); @@ -148,6 +166,7 @@ impl ChildReaper { task::spawn( async move { exit_tx.subscribe().recv().await?; + drop(leak_fds); Self::forget_grandchild(&cleanup_grandchildren, pid) } .instrument(debug_span!("watch_grandchild", pid)), diff --git a/conmon-rs/server/src/config.rs b/conmon-rs/server/src/config.rs index cbe57258f5..5165ebf0cb 100644 --- a/conmon-rs/server/src/config.rs +++ b/conmon-rs/server/src/config.rs @@ -303,6 +303,7 @@ impl Default for Config { // Sync with `pkg/client/client.go` const SOCKET: &str = "conmon.sock"; const PIDFILE: &str = "pidfile"; +const FD_SOCKET: &str = "conmon-fd.sock"; impl Config { /// Validate the configuration integrity. @@ -354,6 +355,10 @@ impl Config { fs::remove_file(self.socket())?; } + if self.fd_socket().exists() { + fs::remove_file(self.fd_socket())?; + } + Ok(()) } pub fn socket(&self) -> PathBuf { @@ -362,4 +367,7 @@ impl Config { pub fn conmon_pidfile(&self) -> PathBuf { self.runtime_dir().join(PIDFILE) } + pub fn fd_socket(&self) -> PathBuf { + self.runtime_dir().join(FD_SOCKET) + } } diff --git a/conmon-rs/server/src/fd_socket.rs b/conmon-rs/server/src/fd_socket.rs new file mode 100644 index 0000000000..2d8b38db37 --- /dev/null +++ b/conmon-rs/server/src/fd_socket.rs @@ -0,0 +1,261 @@ +//! File descriptor passing via UDS (unix socket). +//! +//! ## File descriptor socket protocol +//! +//! Connect via a unix `SOCK_SEQPACKET` socket. +//! +//! **Request:** +//! Pass file descriptors via `SCM_RIGHTS` ancillary message. +//! +//! `request_id: u32`: Request id selected by client +//! `num_fds: u8`: Number of file descriptors +//! +//! ```txt +//! u64: (request_id << 32) | num_fds +//! ``` +//! +//! **Response:** +//! ```txt +//! u64: (request_id << 32) | num_fds +//! u64: slot for file descriptor 0 +//! u64: slot for file descriptor 1 +//! ... +//! u64: slot for file descriptor num_fds-1 +//! ``` +//! +//! On error `num_fds` will be set to 0xffff_ffff and the rest of the message +//! is an error message string. +//! ```txt +//! u64: (request_id << 32) | 0xffff_ffff +//! ...: error message +//! ``` +//! +//! **Close file descriptors:** +//! Received file descriptors will be closed on disconnect +//! or with an empty request (`request_id` = 0 and `num_fds` = 0). +//! +//! An empty request does **not** receive a response. + +use crate::listener::{Listener, SeqpacketListener}; +use anyhow::Result; +use std::{ + collections::{hash_map, HashMap}, + io::{IoSliceMut, Write}, + mem, + num::Wrapping, + os::fd::OwnedFd, + path::PathBuf, + sync::{Arc, Mutex}, +}; +use tokio::{runtime::Handle, sync::Mutex as AsyncMutex, task}; +use tokio_seqpacket::{ancillary::OwnedAncillaryMessage, UnixSeqpacket}; +use tracing::{debug_span, Instrument}; + +#[derive(Debug, Default)] +pub struct FdSocket { + server: AsyncMutex>, + state: Mutex, +} + +impl FdSocket { + pub async fn start(self: Arc, path: PathBuf) -> Result { + let mut server = self.server.lock().await; + if let Some(server) = server.as_ref() { + Ok(server.path.clone()) + } else { + *server = Server::start(path.clone(), self.clone()).await?.into(); + Ok(path) + } + } + + #[allow(dead_code)] + pub fn take(&self, slot: u64) -> Result { + lock!(self.state).take(slot) + } + + pub fn take_all(&self, slots: I) -> Result> + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + { + let slots = slots.into_iter(); + if slots.len() == 0 { + Ok(Vec::new()) + } else { + let mut state = lock!(self.state); + slots.into_iter().map(|slot| state.take(slot)).collect() + } + } +} + +#[derive(Debug, Default)] +struct State { + last: Wrapping, + fds: HashMap, +} + +impl State { + fn add(&mut self, fd: OwnedFd) -> u64 { + let mut slot = self.last; + loop { + slot += 1; + match self.fds.entry(slot.0) { + hash_map::Entry::Occupied(_) => continue, + hash_map::Entry::Vacant(entry) => { + entry.insert(fd); + break; + } + } + } + println!("add {slot}: {:?}", self.fds); + self.last = slot; + slot.0 + } + + fn take(&mut self, slot: u64) -> Result { + println!("take {slot}: {:?}", self.fds); + self.fds + .remove(&slot) + .ok_or_else(|| anyhow::anyhow!("no file descriptor in slot {slot}")) + } +} + +#[derive(Debug)] +struct Server { + path: PathBuf, +} + +struct ListenerGuard(Arc); + +impl Drop for ListenerGuard { + fn drop(&mut self) { + if let Ok(handle) = Handle::try_current() { + let fd_socket = self.0.clone(); + handle.spawn(async move { + *fd_socket.server.lock().await = None; + }); + } else { + *self.0.server.blocking_lock() = None; + } + } +} + +struct ConnectionGuard { + fd_socket: Arc, + slots: Vec, +} + +impl Drop for ConnectionGuard { + fn drop(&mut self) { + let _ = self.close(); + } +} + +impl ConnectionGuard { + fn close(&mut self) -> Result<()> { + let mut state = lock!(self.fd_socket.state); + println!("close... {state:?}"); + for slot in mem::take(&mut self.slots) { + state.fds.remove(&slot); + } + println!("closed: {state:?}"); + Ok(()) + } +} + +impl Server { + async fn start(path: PathBuf, fd_socket: Arc) -> Result { + let server = Self { path }; + + let mut listener = Listener::::default().bind_long_path(&server.path)?; + let guard = ListenerGuard(fd_socket); + + task::spawn( + async move { + while let Ok(conn) = listener.accept().await { + let fd_socket = guard.0.clone(); + task::spawn( + Self::serve(conn, fd_socket).instrument(debug_span!("fd_socket_serve")), + ); + } + drop(guard); + } + .instrument(debug_span!("fd_socket_server")), + ); + + Ok(server) + } + + async fn serve(conn: UnixSeqpacket, fd_socket: Arc) -> Result<()> { + let mut guard = ConnectionGuard { + fd_socket, + slots: Vec::new(), + }; + loop { + let mut buf = [0; 9]; + let mut ancillary_buf = [0; 1024]; + let (n, ancillary) = conn + .recv_vectored_with_ancillary(&mut [IoSliceMut::new(&mut buf)], &mut ancillary_buf) + .await?; + + let id_and_num_fds = match n { + 0 => break Ok(()), // EOF + 8 => u64::from_le_bytes(buf[..8].try_into().unwrap()), + _ => continue, // ignore invalid message + }; + + if id_and_num_fds == 0 { + guard.close()?; + continue; + } + + let num_fds = (id_and_num_fds & 0xff) as usize; + + let result: Result<_> = async { + let mut received_fds = Vec::with_capacity(num_fds); + for msg in ancillary.into_messages() { + if let OwnedAncillaryMessage::FileDescriptors(msg) = msg { + received_fds.extend(msg); + } else { + // ignore other messages + } + } + + if received_fds.len() != num_fds { + anyhow::bail!( + "received {} fds, but expected {num_fds} fds", + received_fds.len() + ) + } + + let mut state = lock!(guard.fd_socket.state); + let start = guard.slots.len(); + guard + .slots + .extend(received_fds.into_iter().map(|fd| state.add(fd))); + Ok(&guard.slots[start..]) + } + .await; + + match result { + Ok(slots) => { + let mut buf = vec![0; 8 + slots.len() * 8]; + let mut chunks = buf.chunks_exact_mut(8); + chunks + .next() + .unwrap() + .copy_from_slice(&id_and_num_fds.to_le_bytes()); + for slot in slots { + chunks.next().unwrap().copy_from_slice(&slot.to_le_bytes()); + } + conn.send(&buf).await?; + } + Err(err) => { + let mut buf = (id_and_num_fds | 0xff).to_le_bytes().to_vec(); + write!(buf, "{err}")?; + conn.send(&buf).await?; + } + } + } + } +} diff --git a/conmon-rs/server/src/lib.rs b/conmon-rs/server/src/lib.rs index ea56070b27..72f3237cd2 100644 --- a/conmon-rs/server/src/lib.rs +++ b/conmon-rs/server/src/lib.rs @@ -4,6 +4,9 @@ pub use server::Server; pub use version::Version; +#[macro_use] +mod macros; + mod attach; mod capnp_util; mod child; @@ -12,6 +15,7 @@ mod config; mod container_io; mod container_log; mod cri_logger; +mod fd_socket; mod init; mod journal; mod listener; diff --git a/conmon-rs/server/src/listener.rs b/conmon-rs/server/src/listener.rs index b68d95ccbb..92f1c9396a 100644 --- a/conmon-rs/server/src/listener.rs +++ b/conmon-rs/server/src/listener.rs @@ -6,6 +6,7 @@ use std::{ path::{Path, PathBuf}, }; use tokio::net::UnixListener; +use tokio_seqpacket::UnixSeqpacketListener; #[cfg(test)] use mockall::{automock, predicate::*}; @@ -20,7 +21,7 @@ impl Listener where T: ListenerImpl, { - pub fn bind_long_path

(&self, path: P) -> Result + pub fn bind_long_path

(&self, path: P) -> Result where P: AsRef, { @@ -60,9 +61,10 @@ where } } -#[cfg_attr(test, automock)] +#[cfg_attr(test, automock(type Listener = UnixListener;))] pub trait ListenerImpl { - fn bind(&self, path: &Path) -> io::Result; + type Listener; + fn bind(&self, path: &Path) -> io::Result; fn create_dir_all(&self, path: &Path) -> io::Result<()>; fn open(&self, path: &Path) -> io::Result; } @@ -72,7 +74,8 @@ pub trait ListenerImpl { pub struct DefaultListener; impl ListenerImpl for DefaultListener { - fn bind(&self, path: &Path) -> io::Result { + type Listener = UnixListener; + fn bind(&self, path: &Path) -> io::Result { UnixListener::bind(path) } @@ -85,6 +88,25 @@ impl ListenerImpl for DefaultListener { } } +#[derive(Debug, Default)] +/// The default implementation for the Listener. +pub struct SeqpacketListener; + +impl ListenerImpl for SeqpacketListener { + type Listener = UnixSeqpacketListener; + fn bind(&self, path: &Path) -> io::Result { + UnixSeqpacketListener::bind(path) + } + + fn create_dir_all(&self, path: &Path) -> io::Result<()> { + fs::create_dir_all(path) + } + + fn open(&self, path: &Path) -> io::Result { + File::open(path) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/conmon-rs/server/src/macros.rs b/conmon-rs/server/src/macros.rs new file mode 100644 index 0000000000..640ba24d0a --- /dev/null +++ b/conmon-rs/server/src/macros.rs @@ -0,0 +1,12 @@ +/// Lock a mutex and return a possible poison error converted to an `anyhow::Error`. +/// ```ignore +/// let mutex = Mutex::new(vec![]); +/// // needs to be inside of a function that returns an anyhow::Result +/// lock!(mutex).push(42); +/// assert_eq!(lock!(mutex).pop(), Some(42)); +/// ``` +macro_rules! lock { + ($mutex:expr) => { + $mutex.lock().map_err(|e| anyhow::anyhow!("{e}"))? + }; +} diff --git a/conmon-rs/server/src/rpc.rs b/conmon-rs/server/src/rpc.rs index 4b5c613c86..eed97077bb 100644 --- a/conmon-rs/server/src/rpc.rs +++ b/conmon-rs/server/src/rpc.rs @@ -8,7 +8,7 @@ use crate::{ telemetry::Telemetry, version::Version, }; -use anyhow::format_err; +use anyhow::{format_err, Context}; use capnp::{capability::Promise, Error}; use capnp_rpc::pry; use conmon_common::conmon_capnp::conmon; @@ -138,12 +138,23 @@ impl conmon::Server for Server { let oom_exit_paths = capnp_vec_path!(req.get_oom_exit_paths()); let env_vars = pry!(req.get_env_vars().and_then(capnp_util::into_map)); + let additional_fds = pry_err!(self.fd_socket().take_all(pry!(req.get_additional_fds()))); + let leak_fds = pry_err!(self.fd_socket().take_all(pry!(req.get_leak_fds()))); + Promise::from_future( async move { capnp_err!(container_log.write().await.init().await)?; let (grandchild_pid, token) = capnp_err!(match child_reaper - .create_child(runtime, args, stdin, &mut container_io, &pidfile, env_vars) + .create_child( + runtime, + args, + stdin, + &mut container_io, + &pidfile, + env_vars, + additional_fds, + ) .await { Err(e) => { @@ -172,7 +183,7 @@ impl conmon::Server for Server { cleanup_cmd, token, ); - capnp_err!(child_reaper.watch_grandchild(child))?; + capnp_err!(child_reaper.watch_grandchild(child, leak_fds))?; results .get() @@ -236,6 +247,7 @@ impl conmon::Server for Server { &mut container_io, &pidfile, env_vars, + vec![], ) .await { @@ -260,7 +272,7 @@ impl conmon::Server for Server { token.clone(), ); - let mut exit_rx = capnp_err!(child_reaper.watch_grandchild(child))?; + let mut exit_rx = capnp_err!(child_reaper.watch_grandchild(child, vec![]))?; let (stdout, stderr, timed_out) = capnp_err!(io.read_all_with_timeout(time_to_timeout).await)?; @@ -415,4 +427,36 @@ impl conmon::Server for Server { Promise::ok(()) } + + fn start_fd_socket( + &mut self, + params: conmon::StartFdSocketParams, + mut results: conmon::StartFdSocketResults, + ) -> Promise<(), capnp::Error> { + let req = pry!(pry!(params.get()).get_request()); + + let span = debug_span!( + "start_fd_socket", + uuid = Uuid::new_v4().to_string().as_str() + ); + let _enter = span.enter(); + pry_err!(Telemetry::set_parent_context(pry!(req.get_metadata()))); + + debug!("Got a start fd socket request"); + + let path = self.config().fd_socket(); + let fd_socket = self.fd_socket().clone(); + + Promise::from_future( + async move { + let path = capnp_err!(fd_socket.start(path).await)?; + + let mut resp = results.get().init_response(); + resp.set_path(capnp_err!(path.to_str().context("fd_socket path to str"))?); + + Ok(()) + } + .instrument(debug_span!("promise")), + ) + } } diff --git a/conmon-rs/server/src/server.rs b/conmon-rs/server/src/server.rs index 06106d6c67..77e00d325b 100644 --- a/conmon-rs/server/src/server.rs +++ b/conmon-rs/server/src/server.rs @@ -4,6 +4,7 @@ use crate::{ child_reaper::ChildReaper, config::{Commands, Config, LogDriver, Verbosity}, container_io::{ContainerIO, ContainerIOType}, + fd_socket::FdSocket, init::{DefaultInit, Init}, journal::Journal, listener::{DefaultListener, Listener}, @@ -48,6 +49,10 @@ pub struct Server { /// Child reaper instance. #[getset(get = "pub(crate)")] reaper: Arc, + + /// Fd socket instance. + #[getset(get = "pub(crate)")] + fd_socket: Arc, } impl Server { @@ -56,6 +61,7 @@ impl Server { let server = Self { config: Default::default(), reaper: Default::default(), + fd_socket: Default::default(), }; if let Some(v) = server.config().version() { @@ -192,11 +198,12 @@ impl Server { let (shutdown_tx, shutdown_rx) = oneshot::channel(); let socket = self.config().socket(); + let fd_socket = self.config().fd_socket(); let reaper = self.reaper.clone(); let signal_handler_span = debug_span!("signal_handler"); task::spawn( - Self::start_signal_handler(reaper, socket, shutdown_tx) + Self::start_signal_handler(reaper, socket, fd_socket, shutdown_tx) .with_context(signal_handler_span.context()) .instrument(signal_handler_span), ); @@ -216,6 +223,7 @@ impl Server { async fn start_signal_handler>( reaper: Arc, socket: T, + fd_socket: T, shutdown_tx: oneshot::Sender<()>, ) -> Result<()> { let mut sigterm = signal(SignalKind::terminate())?; @@ -250,7 +258,19 @@ impl Server { debug!("Removing socket file {}", socket.as_ref().display()); fs::remove_file(socket) .await - .context("remove existing socket file") + .context("remove existing socket file")?; + + debug!("Removing fd socket file {}", fd_socket.as_ref().display()); + fs::remove_file(fd_socket) + .await + .or_else(|err| { + if err.kind() == std::io::ErrorKind::NotFound { + Ok(()) + } else { + Err(err) + } + }) + .context("remove existing fd socket file") } async fn start_backend(self, mut shutdown_rx: oneshot::Receiver<()>) -> Result<()> { diff --git a/internal/proto/conmon.capnp.go b/internal/proto/conmon.capnp.go index 33e30b2c86..4fcf17db7f 100644 --- a/internal/proto/conmon.capnp.go +++ b/internal/proto/conmon.capnp.go @@ -156,6 +156,26 @@ func (c Conmon) CreateNamespaces(ctx context.Context, params func(Conmon_createN } +func (c Conmon) StartFdSocket(ctx context.Context, params func(Conmon_startFdSocket_Params) error) (Conmon_startFdSocket_Results_Future, capnp.ReleaseFunc) { + + s := capnp.Send{ + Method: capnp.Method{ + InterfaceID: 0xb737e899dd6633f1, + MethodID: 7, + InterfaceName: "internal/proto/conmon.capnp:Conmon", + MethodName: "startFdSocket", + }, + } + if params != nil { + s.ArgsSize = capnp.ObjectSize{DataSize: 0, PointerCount: 1} + s.PlaceArgs = func(s capnp.Struct) error { return params(Conmon_startFdSocket_Params(s)) } + } + + ans, release := capnp.Client(c).SendCall(ctx, s) + return Conmon_startFdSocket_Results_Future{Future: ans.Future()}, release + +} + func (c Conmon) WaitStreaming() error { return capnp.Client(c).WaitStreaming() } @@ -242,6 +262,8 @@ type Conmon_Server interface { SetWindowSizeContainer(context.Context, Conmon_setWindowSizeContainer) error CreateNamespaces(context.Context, Conmon_createNamespaces) error + + StartFdSocket(context.Context, Conmon_startFdSocket) error } // Conmon_NewServer creates a new Server from an implementation of Conmon_Server. @@ -260,7 +282,7 @@ func Conmon_ServerToClient(s Conmon_Server) Conmon { // This can be used to create a more complicated Server. func Conmon_Methods(methods []server.Method, s Conmon_Server) []server.Method { if cap(methods) == 0 { - methods = make([]server.Method, 0, 7) + methods = make([]server.Method, 0, 8) } methods = append(methods, server.Method{ @@ -347,6 +369,18 @@ func Conmon_Methods(methods []server.Method, s Conmon_Server) []server.Method { }, }) + methods = append(methods, server.Method{ + Method: capnp.Method{ + InterfaceID: 0xb737e899dd6633f1, + MethodID: 7, + InterfaceName: "internal/proto/conmon.capnp:Conmon", + MethodName: "startFdSocket", + }, + Impl: func(ctx context.Context, call *server.Call) error { + return s.StartFdSocket(ctx, Conmon_startFdSocket{call}) + }, + }) + return methods } @@ -469,6 +503,23 @@ func (c Conmon_createNamespaces) AllocResults() (Conmon_createNamespaces_Results return Conmon_createNamespaces_Results(r), err } +// Conmon_startFdSocket holds the state for a server call to Conmon.startFdSocket. +// See server.Call for documentation. +type Conmon_startFdSocket struct { + *server.Call +} + +// Args returns the call's arguments. +func (c Conmon_startFdSocket) Args() Conmon_startFdSocket_Params { + return Conmon_startFdSocket_Params(c.Call.Args()) +} + +// AllocResults allocates the results struct. +func (c Conmon_startFdSocket) AllocResults() (Conmon_startFdSocket_Results, error) { + r, err := c.Call.AllocResults(capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_startFdSocket_Results(r), err +} + // Conmon_List is a list of Conmon. type Conmon_List = capnp.CapList[Conmon] @@ -822,12 +873,12 @@ type Conmon_CreateContainerRequest capnp.Struct const Conmon_CreateContainerRequest_TypeID = 0xba77e3fa3aa9b6ca func NewConmon_CreateContainerRequest(s *capnp.Segment) (Conmon_CreateContainerRequest, error) { - st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 11}) + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 13}) return Conmon_CreateContainerRequest(st), err } func NewRootConmon_CreateContainerRequest(s *capnp.Segment) (Conmon_CreateContainerRequest, error) { - st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 11}) + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 13}) return Conmon_CreateContainerRequest(st), err } @@ -1120,12 +1171,59 @@ func (s Conmon_CreateContainerRequest) SetCgroupManager(v Conmon_CgroupManager) capnp.Struct(s).SetUint16(2, uint16(v)) } +func (s Conmon_CreateContainerRequest) AdditionalFds() (capnp.UInt64List, error) { + p, err := capnp.Struct(s).Ptr(11) + return capnp.UInt64List(p.List()), err +} + +func (s Conmon_CreateContainerRequest) HasAdditionalFds() bool { + return capnp.Struct(s).HasPtr(11) +} + +func (s Conmon_CreateContainerRequest) SetAdditionalFds(v capnp.UInt64List) error { + return capnp.Struct(s).SetPtr(11, v.ToPtr()) +} + +// NewAdditionalFds sets the additionalFds field to a newly +// allocated capnp.UInt64List, preferring placement in s's segment. +func (s Conmon_CreateContainerRequest) NewAdditionalFds(n int32) (capnp.UInt64List, error) { + l, err := capnp.NewUInt64List(capnp.Struct(s).Segment(), n) + if err != nil { + return capnp.UInt64List{}, err + } + err = capnp.Struct(s).SetPtr(11, l.ToPtr()) + return l, err +} +func (s Conmon_CreateContainerRequest) LeakFds() (capnp.UInt64List, error) { + p, err := capnp.Struct(s).Ptr(12) + return capnp.UInt64List(p.List()), err +} + +func (s Conmon_CreateContainerRequest) HasLeakFds() bool { + return capnp.Struct(s).HasPtr(12) +} + +func (s Conmon_CreateContainerRequest) SetLeakFds(v capnp.UInt64List) error { + return capnp.Struct(s).SetPtr(12, v.ToPtr()) +} + +// NewLeakFds sets the leakFds field to a newly +// allocated capnp.UInt64List, preferring placement in s's segment. +func (s Conmon_CreateContainerRequest) NewLeakFds(n int32) (capnp.UInt64List, error) { + l, err := capnp.NewUInt64List(capnp.Struct(s).Segment(), n) + if err != nil { + return capnp.UInt64List{}, err + } + err = capnp.Struct(s).SetPtr(12, l.ToPtr()) + return l, err +} + // Conmon_CreateContainerRequest_List is a list of Conmon_CreateContainerRequest. type Conmon_CreateContainerRequest_List = capnp.StructList[Conmon_CreateContainerRequest] // NewConmon_CreateContainerRequest creates a new list of Conmon_CreateContainerRequest. func NewConmon_CreateContainerRequest_List(s *capnp.Segment, sz int32) (Conmon_CreateContainerRequest_List, error) { - l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 8, PointerCount: 11}, sz) + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 8, PointerCount: 13}, sz) return capnp.StructList[Conmon_CreateContainerRequest](l), err } @@ -2739,6 +2837,176 @@ func (f Conmon_NamespaceResponse_Future) Struct() (Conmon_NamespaceResponse, err return Conmon_NamespaceResponse(p.Struct()), err } +type Conmon_StartFdSocketRequest capnp.Struct + +// Conmon_StartFdSocketRequest_TypeID is the unique identifier for the type Conmon_StartFdSocketRequest. +const Conmon_StartFdSocketRequest_TypeID = 0xba53ab87a688ec29 + +func NewConmon_StartFdSocketRequest(s *capnp.Segment) (Conmon_StartFdSocketRequest, error) { + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_StartFdSocketRequest(st), err +} + +func NewRootConmon_StartFdSocketRequest(s *capnp.Segment) (Conmon_StartFdSocketRequest, error) { + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_StartFdSocketRequest(st), err +} + +func ReadRootConmon_StartFdSocketRequest(msg *capnp.Message) (Conmon_StartFdSocketRequest, error) { + root, err := msg.Root() + return Conmon_StartFdSocketRequest(root.Struct()), err +} + +func (s Conmon_StartFdSocketRequest) String() string { + str, _ := text.Marshal(0xba53ab87a688ec29, capnp.Struct(s)) + return str +} + +func (s Conmon_StartFdSocketRequest) EncodeAsPtr(seg *capnp.Segment) capnp.Ptr { + return capnp.Struct(s).EncodeAsPtr(seg) +} + +func (Conmon_StartFdSocketRequest) DecodeFromPtr(p capnp.Ptr) Conmon_StartFdSocketRequest { + return Conmon_StartFdSocketRequest(capnp.Struct{}.DecodeFromPtr(p)) +} + +func (s Conmon_StartFdSocketRequest) ToPtr() capnp.Ptr { + return capnp.Struct(s).ToPtr() +} +func (s Conmon_StartFdSocketRequest) IsValid() bool { + return capnp.Struct(s).IsValid() +} + +func (s Conmon_StartFdSocketRequest) Message() *capnp.Message { + return capnp.Struct(s).Message() +} + +func (s Conmon_StartFdSocketRequest) Segment() *capnp.Segment { + return capnp.Struct(s).Segment() +} +func (s Conmon_StartFdSocketRequest) Metadata() (Conmon_TextTextMapEntry_List, error) { + p, err := capnp.Struct(s).Ptr(0) + return Conmon_TextTextMapEntry_List(p.List()), err +} + +func (s Conmon_StartFdSocketRequest) HasMetadata() bool { + return capnp.Struct(s).HasPtr(0) +} + +func (s Conmon_StartFdSocketRequest) SetMetadata(v Conmon_TextTextMapEntry_List) error { + return capnp.Struct(s).SetPtr(0, v.ToPtr()) +} + +// NewMetadata sets the metadata field to a newly +// allocated Conmon_TextTextMapEntry_List, preferring placement in s's segment. +func (s Conmon_StartFdSocketRequest) NewMetadata(n int32) (Conmon_TextTextMapEntry_List, error) { + l, err := NewConmon_TextTextMapEntry_List(capnp.Struct(s).Segment(), n) + if err != nil { + return Conmon_TextTextMapEntry_List{}, err + } + err = capnp.Struct(s).SetPtr(0, l.ToPtr()) + return l, err +} + +// Conmon_StartFdSocketRequest_List is a list of Conmon_StartFdSocketRequest. +type Conmon_StartFdSocketRequest_List = capnp.StructList[Conmon_StartFdSocketRequest] + +// NewConmon_StartFdSocketRequest creates a new list of Conmon_StartFdSocketRequest. +func NewConmon_StartFdSocketRequest_List(s *capnp.Segment, sz int32) (Conmon_StartFdSocketRequest_List, error) { + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz) + return capnp.StructList[Conmon_StartFdSocketRequest](l), err +} + +// Conmon_StartFdSocketRequest_Future is a wrapper for a Conmon_StartFdSocketRequest promised by a client call. +type Conmon_StartFdSocketRequest_Future struct{ *capnp.Future } + +func (f Conmon_StartFdSocketRequest_Future) Struct() (Conmon_StartFdSocketRequest, error) { + p, err := f.Future.Ptr() + return Conmon_StartFdSocketRequest(p.Struct()), err +} + +type Conmon_StartFdSocketResponse capnp.Struct + +// Conmon_StartFdSocketResponse_TypeID is the unique identifier for the type Conmon_StartFdSocketResponse. +const Conmon_StartFdSocketResponse_TypeID = 0xb62f418e0ae4e003 + +func NewConmon_StartFdSocketResponse(s *capnp.Segment) (Conmon_StartFdSocketResponse, error) { + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_StartFdSocketResponse(st), err +} + +func NewRootConmon_StartFdSocketResponse(s *capnp.Segment) (Conmon_StartFdSocketResponse, error) { + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_StartFdSocketResponse(st), err +} + +func ReadRootConmon_StartFdSocketResponse(msg *capnp.Message) (Conmon_StartFdSocketResponse, error) { + root, err := msg.Root() + return Conmon_StartFdSocketResponse(root.Struct()), err +} + +func (s Conmon_StartFdSocketResponse) String() string { + str, _ := text.Marshal(0xb62f418e0ae4e003, capnp.Struct(s)) + return str +} + +func (s Conmon_StartFdSocketResponse) EncodeAsPtr(seg *capnp.Segment) capnp.Ptr { + return capnp.Struct(s).EncodeAsPtr(seg) +} + +func (Conmon_StartFdSocketResponse) DecodeFromPtr(p capnp.Ptr) Conmon_StartFdSocketResponse { + return Conmon_StartFdSocketResponse(capnp.Struct{}.DecodeFromPtr(p)) +} + +func (s Conmon_StartFdSocketResponse) ToPtr() capnp.Ptr { + return capnp.Struct(s).ToPtr() +} +func (s Conmon_StartFdSocketResponse) IsValid() bool { + return capnp.Struct(s).IsValid() +} + +func (s Conmon_StartFdSocketResponse) Message() *capnp.Message { + return capnp.Struct(s).Message() +} + +func (s Conmon_StartFdSocketResponse) Segment() *capnp.Segment { + return capnp.Struct(s).Segment() +} +func (s Conmon_StartFdSocketResponse) Path() (string, error) { + p, err := capnp.Struct(s).Ptr(0) + return p.Text(), err +} + +func (s Conmon_StartFdSocketResponse) HasPath() bool { + return capnp.Struct(s).HasPtr(0) +} + +func (s Conmon_StartFdSocketResponse) PathBytes() ([]byte, error) { + p, err := capnp.Struct(s).Ptr(0) + return p.TextBytes(), err +} + +func (s Conmon_StartFdSocketResponse) SetPath(v string) error { + return capnp.Struct(s).SetText(0, v) +} + +// Conmon_StartFdSocketResponse_List is a list of Conmon_StartFdSocketResponse. +type Conmon_StartFdSocketResponse_List = capnp.StructList[Conmon_StartFdSocketResponse] + +// NewConmon_StartFdSocketResponse creates a new list of Conmon_StartFdSocketResponse. +func NewConmon_StartFdSocketResponse_List(s *capnp.Segment, sz int32) (Conmon_StartFdSocketResponse_List, error) { + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz) + return capnp.StructList[Conmon_StartFdSocketResponse](l), err +} + +// Conmon_StartFdSocketResponse_Future is a wrapper for a Conmon_StartFdSocketResponse promised by a client call. +type Conmon_StartFdSocketResponse_Future struct{ *capnp.Future } + +func (f Conmon_StartFdSocketResponse_Future) Struct() (Conmon_StartFdSocketResponse, error) { + p, err := f.Future.Ptr() + return Conmon_StartFdSocketResponse(p.Struct()), err +} + type Conmon_TextTextMapEntry capnp.Struct // Conmon_TextTextMapEntry_TypeID is the unique identifier for the type Conmon_TextTextMapEntry. @@ -4113,206 +4381,404 @@ func (p Conmon_createNamespaces_Results_Future) Response() Conmon_CreateNamespac return Conmon_CreateNamespacesResponse_Future{Future: p.Future.Field(0, nil)} } -const schema_ffaaf7385bc4adad = "x\xda\xd4Y}p\x14\xf5\xf9\x7f\x9e\xfd\xdeesy" + - "\xf1\xb2\xbf\xbd`@b\x10\xc1\x1fR\x11$X\x90\x81" + - "!\x012\x14\x04\xcd\xe6@+T\x87\xe5nI\x0es" + - "\xb7\xc7\xee\x1e\x10\x94\x82/L1V%)\x8c\x85\x91" + - "\x19\xf0\xad@\xa1J-V\xf0eDaT\x94\xb6\xa1" + - "\x95\xaa\xa3V\xa5Te|\x81\x0aSph\xb7\xf3|" + - "/\xfb\x92K\xc4Kj\xff\xe8\x1fLn\x9f\xfd\xec\xf3" + - "}{\xbe\x9f\xe7\xf3<\x8c\xba$T\x13\xb8\xaaT/" + - "\x05Ay(X`\x9b\x1f\xb6\x18\x8fo\x9av\x17H" + - "\x97\"@\x10E\x80\xeaM\x05\x1f!\xa0\xbc\xab`\x12" + - "\xa0}\xfa\xd1W'>\xd8\xf6e\xab\x1f\xd0\x91\x05\x1c" + - "\xe3\x80w\xc7\x0d_\xb8\x99\xcd\xbc\xd7\x0f\x08\x89\xef\x10" + - "\xa0R$\xc0\x8f\xe7\x87\xd7\xfd\xac\xdf<\x0e\xb0OV" + - "/|o\xc3'c\x7f\x0bA\x91\x80\x13\xc5wP\xbe" + - "\x89\xff\x9c#>\x80\x80\xf6\xeb\x17/\xbf1\xfc\xf8O" + - "~\x9e\x83\xe6n\xaf\x0e}\x84\xb2\x12\x12\x01\xe4Y!" + - "r\xbd\xfa\xd3\xeb\x9e\x9es\xd7\x97\x9b\xfdc\xdf\x11\xfa" + - ";\x8d\xbd\x9e\x036\xcc\xfb\xe4\xd6\xba\xe9\xe1\x87\xbbz" + - "\x0b\x10nOh;\xca\x1d!\x11\x98\xdd\xef\xeb\xa3\x8f" + - "\x1e\x89\x8e\xdb\x06\xca\xa5\xd8m\xd0\x9d\x84;\xc0\x07\xdd" + - "\x17Z\x0ah\x0fy\xe2\xe5\x8e\xd6\x09#\xb7\xfb\x07\xad" + - ",:L\x83^UD\x83\xb6\xfeB\xfb\xff}{\xaf" + - "%\x80\xe0y\x03\xacV\x8aZQN\x14\x91+\xadh" + - ",\xa0\xbdt\xfe\xabO,W\x8e\xed\xe8az\xc9\xa2" + - "v\x94W\x17\xd1\xf4\xe4\xa9\xa3\xf6\x1c\xa9\x1e\xbe3w" + - "z\x02\xe1T\xc2\xb5p\x9f\x99\xa2'\x00\xed1[\x9e" + - "z\xfa\xfe/\x96\xfd\x8a\xd0B\xeeb\x86\x16/B\xf9" + - "\x9a\xe2\x0b\x01\xe4\xdabB\xdf\xd6q|\xeb\xfd\xf7\xd6" + - "\xee\xce\xf5\xcd\x08\xfdv\xf1K(\x9f,\xa6\x9f\x9f\x17" + - "W\xd1\xe9\xb8\x00i \xb3w\xee\xdc?o\xdc?\xb6" + - "\xdb\xb4\xb4\xf2\xd2\x01X=\xb4t,\x02T\xdfw\xc1" + - "+(\x1f\x0a\x8b\x00\xf6\xc1\xa7\xb7\x8d\xff\xfa\xe8\xd2\xbd" + - "\xb9\xee\xb9\xcf\xdd\xe1\xc3(w\x10\xae\xfaP\xf8B\x06" + - "h\x97\xcd\xfb\xfd\xc4\xcfn\xf9\xdb\x01\xff\xd6>&\xf3" + - "X\xda#\xd3\xd6~\xac>+\xd4\x1dj~\xc5\x0fx" + - "O.\x12\x00\xe5\xd3Y\xc0_\xff\xb5\xa81=\xf2\x0d" + - "?\xa0<\xd2N\x1e\x86F\x08p\xa6\xfc\x85\x07\x07L" + - "\xd8\xfb;?\xa0.\xc2\x87\xb8\x89\x03\x06\xd4v\x8c\x09" + - "\xa7\xa6\xfd!'\x00\xf9\x86\xac\x88<\x8c\xf2\xfa\x08m" + - "v[\x84\xb6\xef\x91\xaf\xb6\xce\xdf\xdd\x169\xd2\xed\xa8" + - "k\xcb\x17\xa1<\xa7\x9c\x90J\xf9J@\xfb\xdc\xea\x09" + - "\xab*+\x8f\xbc\xdd\xe3!\xae.?\x8e\xf2\x16\x8e\xde" + - "T\xfe1\xa0\xbd\xf1{K\xd3\xb7,\x18\xff~\x0e\x9a" + - "GFK\xbfwP^\xdf\x8fO\xa2\x1f\xcd\xf8\xdc\xf8" + - "s/l\x9e\x90\xfeK\xae\xeb \xdf\xe4~\xad(\x1f" + - "\"t\xf5k\xfdn\xa43\x9c\x93\x9e&]\xd6p\xc1" + - "\x07\xfe\x1d\x98X\xf1\x7f\xb4\x87s*\xc8\xdf\xa8\xdb\xa6" + - "m\xbb%!\x1f\xf5\x03Z*6\xd2\x16\xdd\xc3\x01\xdf" + - "\x97_~2\xd5v\xfc\x98\x1f\xb0\xb3\xe28\x01\xf6q" + - "\xc0\xbey\xd5\xf5\x7f>z\xd9\x09\x90F\x08^@\x02" + - "V\x7fX\xd1\x8e\xf2\xd9\x0a\x9a\xfb\xe9\x8a*@\xbb\xe3" + - "\x8b\xaa\x1d\xaf\x1f\xbb\xf6\xab\xdc\xb9\xd3}\xab>]\xb1" + - "\x11\xe5\xd2\xfe\x9cQ\xfa\x8f\x15\x00\xed\xc7\x17?\xb2\xf6" + - "\xcc`\xe9Tnp\xf3\xa5\xde|\xd1G(\xb7\\D" + - "?3\x17\xbdBK}f\xe3\xba\x07\xf6\x8f\x9ev\xca" + - "?\xd1\x15\x95\xfc\xaa\xb6U\xd2D\x9f\xc3\xed\xc5?Z" + - "\xf4\xc9\x19?`W%_\xc9\x01\x0e8\xb3\xe5\x97\xd5" + - "\xab\x0e=u\xb6\x87\x1b\xfai\xe5A\x94\x83\x17\xd3\x0d" + - "m\xff\xe3\x8c\xe4\xfb\xff|\xf6\xeb\x9c\x98\xe1g\xfba" + - "\xe5\xc3(\x9f\xad\xe4K\xae\\\x0a#\xecD\xca\xd2\x8c" + - "\x94\xda\\02m\xe8\x96>2\xa6\xa7\x92z\xea\xca" + - "\x98\x9aN\xa5\xc7O\xc9>h\xcb\xb4X\xb4%\x15\x9b" + - "\xa2\xa7,5\x91\xd2\x8c!\xf5\xaa!\xaaIS\x09\xb0" + - "\x00@\x00\x01\xa4\xd2\xc9\x00J!C%\"\xe0JC" + - "[\x9c\xd1L\x0b\xcb\xbc-\x02\xc42\xc0\xbc\x86\x8b\x19" + - "\x9aji\xd7\xa9I\xcdL\xab1\xcd\x1c\xd2\xa0\x99\x19" + - "\xb1\xd9\xea2\xdc\x0c\x00\xa5\x84\xa1R!\xa0mhf" + - "ZO\x99\x1a\x00`\x99\xc7\xd9\xff\xc9\x90\xf5\xaa\xa1\xb2" + - "|\x16\xe8\xe6\x93^\x8c6%g\xb4\x06\xf2\xc6L\xab" + - "\x1eQ\x19\xe8\x0e\xb8{\x01\x80\xf2\x1b\x86\xca\x8b\x02J" + - "\x88\x11$\xe3\xf3s\x01\x94\xe7\x18*o\x09(\x09B" + - "\x04\x05\x00\xe9MB\xfe\x89\xa1rB@\x89\xb1\x082" + - "\x00\xe9s2~\xc60Z\x88\x02J\x81@\x04\x03\x00" + - "r\x10g\x00D\x03\xc80ZF\xf6`0\x82A\x00" + - "\xb9\x14G\x03D\x0b\xc9\x1e!{AA\x04\x0b\x00d" + - "\x89\xe3\xcb\xc8~\x05\x0ah'5K\x8d\xab\x96\x0a\xe2" + - "\xf5\xcdq,\x05\x01K\x01\xedT\xe7R\x80i&^" + - "\x00X\xcf\x10\xc3\x1e\x1d\x01\x92\xd1\xce$\xe2\xb3\xd4t" + - ":\x01b\xaa\xd1\x85\x95\x80\xc0_6\x9e\xef\xe5\x02\xd5" + - "\xd4\xeaU\xab\x89\x0e\x98l%\x80Ui=>=\xee" + - ".\xf3.B\xe7\x04\xfav6f" + - "Z\x17S\xa6F\x87\xe3\x8b\x86\xb9\x9d\xf17L\xe8y" + - "\xf9e^\x1e\xef\xc5\xe8\x86\xa6\xa7\xb5\xd4L\xbd\xd1\xbb" + - "j\x0dZ\x95\x99\xc9;\xf8]\x89\x91\x13\x8e\xc1\xf3\x0c" + - "\xda\xe0\x0cJk\x0d\xeb\xd9\xb5\xe6\xf5\xa5\xbbM\xfe/" + - "\x95Bw\xa2\x97\x0f\x07P\x860TF\x09\xe8D\xf0" + - "\x08\xb2\x0dc\xa8\x8c\x110l\xb5\xa4\xb5\x9cH\x09\x03" + - "\x86\xd3\xaa\xd5\xe4\x1em>\xfb\xa6Z\x96\x1ak\xea\xc2" + - "Oj\x12\xf3\xb8\xben\xb6\xea\xc5~Mi4\xf4L" + - "z\x96\x9aR\x1b5\x03\x80/\x99\xdfCi2\xb9\x91" + - "B3\x00V\x9a-\xa6\xa5%\xe3v\x8c\x83\x17\x9a\x00" + - "\x90\x97\xf3Z\xbe\x92\x86\xec\xa1b\xde'q\x83f\x98" + - "\x09=\xc5\x99\xc4D\xce$%\xee\xda\xebh\xed5\x0c" + - "\x95\x99\xde1L'z\xf8\x01Ce6\x11\x09f\x89" + - "D\xa1\xc0\xaag\xa84\x0b\xb8r\x89f,\xd0M\x0d" + - "\x11\x04D\xf8\xa6\xab\xdf\xab\x8b\x178\xcf\x0af\xea\x8d" + - "S\x8dpb\x89f(\x01\xf4'm\x1c\x1e\x9e\xdd\x92" + - "\xd6\xfc\xeb\x19\xde\xc3z\xc86\x95\xa1R\xef[\xcf\xac" + - "\xc9\xde\"\x9dXs\x1d\xf7\x10k+\x93\xea\xb2hb" + - "\xb9\x86!\x100\x94g\xecE5\xeb\xc6D*\xae/" + - "\xa5/\xb3\x07`\xf1\xa0\x88\xb8\x13^1\x00@Y\xc6" + - "P\xb9\xdb\x9b\xf0\x1d\xa3\x01\x94\xdb\x19*k|\x13^" + - "=\x1e@Y\xc5P\xf9)19f\x99\xfc\x1e:\xaa" + - "5\x0c\x95uD\xe4\x02'r\xa9\x8d\x8ej-Ce" + - "\x87\x80,\xe1\x12a\xd5\xd2D\xdcjB\x11\x04\x14\x01" + - "'5i\x89\xc6&\xcby\xfc.\x8e\x90}\xd3N0" + - "=\xa5\xccD\xf4\xea\x03\xa9m\xb9'\xa8\xa4\xb6;=" + - "\xf9-\xb5\xed\xf5t\x98\xb4\xbe\xc1W\xa3\xac7<\xb5" + - ")\xad\x7f\xc9\xd3\x0f\xd2\x86\x83\x9ej\x95\xb6\x1c\xf6n" + - "\xae\xb4\xcd\xf0\x95.\xdb\x96\xfb4\xf3\xb6V_\xcd\xb5" + - "\xb3\xdd\xab/\xa4]\xdb}bj\xf7\xaf}e\xe1\x9e" + - "\x97|:\xfa\xf9\x06_\x09\xf8\xfcA\x8f\xd3\xa5\x03\xed" + - ">\x9d\xf5Z\xab\xed\\@\x98\x94\x8d\x00\xd7\xc0\x1c~" + - "\xcef\x16\x97\xa3\x1a\x1c \x0f\xfc\xc4\x12\x0d\xd0\xb0\x1d" + - "j\x81*N.\xb6\xf3M\xd0\xf9\xc8qV\x97+\xc9" + - "\x9c\xc0\x03\xdby%\xf8\xdeu\xb2\x89\xed\xb0\x0bTe" + - "\xc7v\x9f'e\xfd\xdaN.\xc0F\xcf\xa1\xdf\xe68" + - "r\x82\x1e\x9d\xa8\x0fs\x7f\xb9f\xb3*\xeb\xd6\xc9\xaa" + - "\xac\x8b\xe41-p2\x08z\x18\xa1K\xea\xe5\x99\xcd" + - "\xf6`\xde\x14fk\xcb,\xfa\x87\xb3\xd4t]\xca2" + - "Z\x00\x94\x81,\x08\xe0\x96]\xe8\xd4\x0eR\xc7d\x10" + - "\xa4\x03\"z\"\x1c\x9d\xd2K\xdas'\x08\xd2.\x11" + - "\x05\xb7\xfd\x80\x8e\x10\x97\x1ek\x07A\xda\"\"s\xeb" + - "lt\xaaBi=}w\x9f\x88\x01\xb7\x02A\xa7\x03" + - " \xdd\xb1\x11\x04i\x85\x88A\xb7FD\xa7\xd0\x91\x16" + - "\xef\x05AJ\x8aX\xe06+\xd0ikHj+\x08" + - "\xd2\xcd\"q/\x05O\x0d\xda\xb1\xce\x08\xc0\xce\xb3\x84" + - "\x1a\xb4\x1d=\x8e\xce\x09\xa3Q\x83\xb6\x93\x03\xfdH\xc3" + - "=\xbaN(\xd3\x08jv9\xa6)zjR\xf6\x13" + - "w\xbc\xebTtN\x01\xa0\x06\xfdY\xe8\xdb\xc5SN" + - "Lf\xb3\xd18\x87\x0c\xe5\x16\x1c\x00\x10\xb5HR\xae" + - "BO\xda\xca+p.@\xf4v\xb2\xafA\x011+" + - "n\xe5\xd5\\\x81\xdeM\xe6\xb5\xe8\xb1\xa2|\x1fW\xac" + - "k\xc8\xbe\x0e=b\x94\xdb\xb0\x01 \xba\x96\xec;\xb8" + - "\xc2eY\x85\xbb\x0d\x17\x01D\xb7\x92}?W\xb8\x81" + - "\xac\xc2\xdd\xc7\x87}\x91\xec\xef\x92]\x0cF\xa8\xf0\x92" + - "\xdf\xe6\xf6\xb7\xc8~\x8a\xec\x85\x05\x11,\x04\x90Or" + - "\xfb\x09\xb2\x97\x08\x02J!1\x82!\x009$, " + - "\x05-0\x8c\x0e!{Qa\x04\x8b\x00\xe4K\xb8}" + - "\x10\xd9\xaf {q(\x82\xc5\x00\xf2\xe5\x02\xadk\x18" + - "\xd9\xa7\x92\xbd\xa4(\x82%\x00r\xad0\x19 :\x81" + - "\xec?${)F\xb0\x14@\x9e#\x18\x00\xd1\xd9d" + - "\x9f/t\xe1|{A&\x15o\xd6\xeaU`>\xd9" + - "diF2\x91R\x9b\x89\xd5;Sx\x95i\xc5\x13" + - ")7\xa1k\xcb\x12\x16W\xd5\xd8Mp\xebz\xb2\x8e" + - "\xdeBX\xb5\x9a\xba\xbdmv\x18\x8b\x19>\xbd\xeb\xab" + - "\xac9*\xd6\xac\xa9\xa9Lz\x0a\xb0d\xbc\x9b\xdao" + - "\xd6\x17\xa8\xcd\xb5\x06\xb0\xeeb?\xa6'\x93j*^" + - "\x0b\xa2\xd1\xfde\xdf3\xd8J-\xb5\xe4\x06\xd5?\xe1" + - "\xdc\x14\x17\xebJ\xbe\x18\xf6\xf2RV+\xf4I\x8aR" + - "\xf1\xda\xcc\xf2\xd5\xefn\"\xcb\xd1\xa3\xe2yF4\xfd" + - "\x02$G\x03\x9b\x00\xdf.\x82\xdd\xb4\xd8\x0b\x11\xdc\xc9" + - "P\xf9+mW\x17\xf4\xba,\xef\xeb^\xbaB\xa2o" + - "\xb5\xd0\xe2\x8c\xa8\x99\xb9Jz\x80\xa7<\xa5\x9e\xa5\xb4" + - "\xd0]J\xfb\xef\xea\x7fYE\xf3D\x19&\xe2\xe6\x0a" + - "\x94O\xe5\xea\xc1\xbc,\x19A\x7f\x04i(\xfdaR" + - "\xe5p\x00\x0cH\xe5\x83\x01\xc4D:&\xa64KL" + - "'\xe2\xe1\x8c\xa9\x19b\xc62\xf3:\x9f\x1eT\x88\xaf" + - "\x0e,s\xb7M\xa5\xcd\x98\x9f\xdd\x0cg\xd7\x12$u" + - "\xe3\x0c\x95\xb4O\xff&\xc9\xd8\xc4P\xb1\x88\xe9\x07e" + - "\xf5\xefb\xfa:\xcdP\xb9]\xc8\x92\xd6\x14=\xce\x8f" + - "8\x00\x02\x06\x00'\x99V\\\xcfX\xcef\xd2\xa3f" + - "\x18\xee\xdeZ\x89\xa4\x16\xbf>c\xf9\x88\xb0o\xc9\x8c" + - "b\x8buk\x04,\xf2\xc5_\xac\x13\x0ca\xa3>\x11" + - "\xc7B\x10\xb00\xcf\xc0s\x94X\xa7\xe8\xa2A*\xdc" + - "A6P\xd8\xadc\xa8l\xf6\x85\xdd\xa6\xb9\x00\xcaC" + - "\x0c\x95\xad\xbe\xb0{\xcc\x00P\x1ee\xa8<) v" + - "v\x82v\xb6\x03(O2T\x9e\xa34\xc9\xb2\xf5\xc3" + - "\x1e\x0a\xdag\x18*\xfb)G\x06x\x8e\x94\xf6\xd1N" + - "\xbf\xc8Py\xb7k\xd0\x9az\xecV\xcd\xcaI0\\" + - "\x85h\xa6\x09U\x09=\xe5k\xc5\x98\x96\x9e\xae]h" + - "ihD)\xdd\xd4\xe9\xb8\xf0\xbb\xac!\xfb\xc0\x84\x9c" + - "6,\xcc\x936\xdc\xba\xa0\x0fl\xd8;\x82r\xab\xa3" + - "^Pb\x0f\x1d\xa2z5l\xe4\xd5\x8cu\x0b\xa3^" + - "\xac\xcc\xa9N\x8c+g\xb7\xa41\x1b\xfc<\xd2\x82\x87" + - "\x01\xdc\x80\x17\x8c\x86L\x8a.\xdatr\xb9\x90\xeb\xf9" + - "^\xb5-|wk\x98\xab\x14C\\\xca\xb9MIG" + - "(JH\x0a\xa9\x84\xcc\x15\xe8\x91\x87\\\x8e\x83\x9d^" + - "\xe5@\xae\x14\x85\xacR\xec\x8f\xe3\x01\xa2\x11\xb2\x0fB" + - "\xef\x0a\xc8\x95\xdc\xfd@\xb2\x0fC\xef\x16\xc8C9~" + - "\x90\xd3\xf3\x94\x0a\x82Y\xa5x9\x92\x92\x1bF\xf61" + - "\\)\x16d\x95\xe2U\\Y\x8e\"\xfb\x04\xae\x14\xc5" + - "\xacR\xbc\x86\xfb\x1fG\xf6\xa9d\x0f\x15f\x95b-" + - "W\xb45d\x9f\x89\x02\xdaiC\x8fi\xa69\x1d\xd0" + - "\xa5\x0c\xa7\x00p.\x95h\xa9\x8d\xce\xefI$\x90\x12" + - "\x96O\xfd%\x9a\xe3SU\x0bPs!\x96j4j" + - "\x1e\xc4\xc8\x98\x16m5\x88>\x9fvL5\x1a\xf5\x1b" + - "4\x03\xc2f7\xf3lC\xf3\xf9\xebrC\x9d[\xdb" + - "\xc7\x04\xe1\xa5\xd5An\xbcv\x10\xbf\xbd\x91\xedj;" + - "\xf4\xf6\xe6\xdc\xce\xa6\xf6\x07\xbe\xfc\xf0\x1e\x05\xf6[\x0c" + - "\x95St\xbe5Y~;I7\xec\x04C\xe5\x9c\xaf" + - "?r\x96\xf8\xed\x0c\xc3h\xc0_\x04 m}\x83\x1b" + - "!N\x0d\xd0\x9fG\x14\x8f\x90Q\xfe\x1a`\x04\x92\xe6" + - "\xbe\x82\xec\xe3\xb0+%R\xb0\xeb\x19+\x0aL\x8b9" + - "\xed\xa2\x95\x9d\xd25W\xb4\xf6 \xc5\xff\x07\x84l\xae" + - "\xf8\xca[\xe9\xb9}\x9e^\xd0Z\xf7\xffbj\xd0\xcc" + - "p\xfe}o\xb75\xd4\x8b1s\x1aw\x8e\xbb|[" + - "\xaeN\xff\x81\xb7\x1fD\xcbh\xc9\xe9}\x0f\xf6z\xdf" + - "n\xce\x1e1\xdak~\x8b\xb7j-n\xdbn\x89\xda" + - "\x9cq\xaf\xdb\xbf\x03\x00\x00\xff\xff%\x93J\x19" +type Conmon_startFdSocket_Params capnp.Struct + +// Conmon_startFdSocket_Params_TypeID is the unique identifier for the type Conmon_startFdSocket_Params. +const Conmon_startFdSocket_Params_TypeID = 0xce733f0914c80b6b + +func NewConmon_startFdSocket_Params(s *capnp.Segment) (Conmon_startFdSocket_Params, error) { + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_startFdSocket_Params(st), err +} + +func NewRootConmon_startFdSocket_Params(s *capnp.Segment) (Conmon_startFdSocket_Params, error) { + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_startFdSocket_Params(st), err +} + +func ReadRootConmon_startFdSocket_Params(msg *capnp.Message) (Conmon_startFdSocket_Params, error) { + root, err := msg.Root() + return Conmon_startFdSocket_Params(root.Struct()), err +} + +func (s Conmon_startFdSocket_Params) String() string { + str, _ := text.Marshal(0xce733f0914c80b6b, capnp.Struct(s)) + return str +} + +func (s Conmon_startFdSocket_Params) EncodeAsPtr(seg *capnp.Segment) capnp.Ptr { + return capnp.Struct(s).EncodeAsPtr(seg) +} + +func (Conmon_startFdSocket_Params) DecodeFromPtr(p capnp.Ptr) Conmon_startFdSocket_Params { + return Conmon_startFdSocket_Params(capnp.Struct{}.DecodeFromPtr(p)) +} + +func (s Conmon_startFdSocket_Params) ToPtr() capnp.Ptr { + return capnp.Struct(s).ToPtr() +} +func (s Conmon_startFdSocket_Params) IsValid() bool { + return capnp.Struct(s).IsValid() +} + +func (s Conmon_startFdSocket_Params) Message() *capnp.Message { + return capnp.Struct(s).Message() +} + +func (s Conmon_startFdSocket_Params) Segment() *capnp.Segment { + return capnp.Struct(s).Segment() +} +func (s Conmon_startFdSocket_Params) Request() (Conmon_StartFdSocketRequest, error) { + p, err := capnp.Struct(s).Ptr(0) + return Conmon_StartFdSocketRequest(p.Struct()), err +} + +func (s Conmon_startFdSocket_Params) HasRequest() bool { + return capnp.Struct(s).HasPtr(0) +} + +func (s Conmon_startFdSocket_Params) SetRequest(v Conmon_StartFdSocketRequest) error { + return capnp.Struct(s).SetPtr(0, capnp.Struct(v).ToPtr()) +} + +// NewRequest sets the request field to a newly +// allocated Conmon_StartFdSocketRequest struct, preferring placement in s's segment. +func (s Conmon_startFdSocket_Params) NewRequest() (Conmon_StartFdSocketRequest, error) { + ss, err := NewConmon_StartFdSocketRequest(capnp.Struct(s).Segment()) + if err != nil { + return Conmon_StartFdSocketRequest{}, err + } + err = capnp.Struct(s).SetPtr(0, capnp.Struct(ss).ToPtr()) + return ss, err +} + +// Conmon_startFdSocket_Params_List is a list of Conmon_startFdSocket_Params. +type Conmon_startFdSocket_Params_List = capnp.StructList[Conmon_startFdSocket_Params] + +// NewConmon_startFdSocket_Params creates a new list of Conmon_startFdSocket_Params. +func NewConmon_startFdSocket_Params_List(s *capnp.Segment, sz int32) (Conmon_startFdSocket_Params_List, error) { + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz) + return capnp.StructList[Conmon_startFdSocket_Params](l), err +} + +// Conmon_startFdSocket_Params_Future is a wrapper for a Conmon_startFdSocket_Params promised by a client call. +type Conmon_startFdSocket_Params_Future struct{ *capnp.Future } + +func (f Conmon_startFdSocket_Params_Future) Struct() (Conmon_startFdSocket_Params, error) { + p, err := f.Future.Ptr() + return Conmon_startFdSocket_Params(p.Struct()), err +} +func (p Conmon_startFdSocket_Params_Future) Request() Conmon_StartFdSocketRequest_Future { + return Conmon_StartFdSocketRequest_Future{Future: p.Future.Field(0, nil)} +} + +type Conmon_startFdSocket_Results capnp.Struct + +// Conmon_startFdSocket_Results_TypeID is the unique identifier for the type Conmon_startFdSocket_Results. +const Conmon_startFdSocket_Results_TypeID = 0xf4e3e92ae0815f15 + +func NewConmon_startFdSocket_Results(s *capnp.Segment) (Conmon_startFdSocket_Results, error) { + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_startFdSocket_Results(st), err +} + +func NewRootConmon_startFdSocket_Results(s *capnp.Segment) (Conmon_startFdSocket_Results, error) { + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}) + return Conmon_startFdSocket_Results(st), err +} + +func ReadRootConmon_startFdSocket_Results(msg *capnp.Message) (Conmon_startFdSocket_Results, error) { + root, err := msg.Root() + return Conmon_startFdSocket_Results(root.Struct()), err +} + +func (s Conmon_startFdSocket_Results) String() string { + str, _ := text.Marshal(0xf4e3e92ae0815f15, capnp.Struct(s)) + return str +} + +func (s Conmon_startFdSocket_Results) EncodeAsPtr(seg *capnp.Segment) capnp.Ptr { + return capnp.Struct(s).EncodeAsPtr(seg) +} + +func (Conmon_startFdSocket_Results) DecodeFromPtr(p capnp.Ptr) Conmon_startFdSocket_Results { + return Conmon_startFdSocket_Results(capnp.Struct{}.DecodeFromPtr(p)) +} + +func (s Conmon_startFdSocket_Results) ToPtr() capnp.Ptr { + return capnp.Struct(s).ToPtr() +} +func (s Conmon_startFdSocket_Results) IsValid() bool { + return capnp.Struct(s).IsValid() +} + +func (s Conmon_startFdSocket_Results) Message() *capnp.Message { + return capnp.Struct(s).Message() +} + +func (s Conmon_startFdSocket_Results) Segment() *capnp.Segment { + return capnp.Struct(s).Segment() +} +func (s Conmon_startFdSocket_Results) Response() (Conmon_StartFdSocketResponse, error) { + p, err := capnp.Struct(s).Ptr(0) + return Conmon_StartFdSocketResponse(p.Struct()), err +} + +func (s Conmon_startFdSocket_Results) HasResponse() bool { + return capnp.Struct(s).HasPtr(0) +} + +func (s Conmon_startFdSocket_Results) SetResponse(v Conmon_StartFdSocketResponse) error { + return capnp.Struct(s).SetPtr(0, capnp.Struct(v).ToPtr()) +} + +// NewResponse sets the response field to a newly +// allocated Conmon_StartFdSocketResponse struct, preferring placement in s's segment. +func (s Conmon_startFdSocket_Results) NewResponse() (Conmon_StartFdSocketResponse, error) { + ss, err := NewConmon_StartFdSocketResponse(capnp.Struct(s).Segment()) + if err != nil { + return Conmon_StartFdSocketResponse{}, err + } + err = capnp.Struct(s).SetPtr(0, capnp.Struct(ss).ToPtr()) + return ss, err +} + +// Conmon_startFdSocket_Results_List is a list of Conmon_startFdSocket_Results. +type Conmon_startFdSocket_Results_List = capnp.StructList[Conmon_startFdSocket_Results] + +// NewConmon_startFdSocket_Results creates a new list of Conmon_startFdSocket_Results. +func NewConmon_startFdSocket_Results_List(s *capnp.Segment, sz int32) (Conmon_startFdSocket_Results_List, error) { + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz) + return capnp.StructList[Conmon_startFdSocket_Results](l), err +} + +// Conmon_startFdSocket_Results_Future is a wrapper for a Conmon_startFdSocket_Results promised by a client call. +type Conmon_startFdSocket_Results_Future struct{ *capnp.Future } + +func (f Conmon_startFdSocket_Results_Future) Struct() (Conmon_startFdSocket_Results, error) { + p, err := f.Future.Ptr() + return Conmon_startFdSocket_Results(p.Struct()), err +} +func (p Conmon_startFdSocket_Results_Future) Response() Conmon_StartFdSocketResponse_Future { + return Conmon_StartFdSocketResponse_Future{Future: p.Future.Field(0, nil)} +} + +const schema_ffaaf7385bc4adad = "x\xda\xc4Y{p\x14gr\xef\x9e\xd9\xd5h\xf5`" + + "5\x99\x95\x00\x81\"\x15\x87/\xa0\x1c\xc7C8\xc6\x14" + + "W\x92\x00\x1d\x81\x03\x9fF\x8bM\x0e\xee\x1c\x86\xddA" + + "ZX\xed,3\xb3\x808;2wq\xd9\xa7;l" + + "\xa3\xe0\xb2M\x85*d\x1b\x02\x18b\xfc\x80\x18\x8c]" + + "\x80\xa1\x0c\xd8\xc4\x81\x04b\\\xc6\x01cb\x9b\xf2\x8b" + + "\xd8\xa9`\x17dR\xfd\xcd\xceC+\x19\xaf\x14\xa7\xf2" + + "\x07\x85\xb6\xe77\xdd\xdf\xf7u\x7f\xdd\xfd\xeb\x99\xf0y" + + "\xa8!0\xb1\xf4\xad!\xc0\xc9;\x83\x05\x96q\xb1C" + + "\xdf\xbai\xd6oA\xfc\x01\x02\x04Q\x00\xa8\x9b'\xbc" + + "\x8f\x80\x92\"\xd4\x03Z\xff\xf9\xf4\xb1\x9f<\xb6\xfe\xf3" + + ".?`\xad\x0dx\x94\x01\xde\x9dR\xbbt3?\xf7" + + "\xf7~\xc0>\xe1\x1d\x02\x9cd\x80\xbfZ\x1c\xde\xf07" + + "\x15\x8b\x18\xc0\xbaZ\xb7\xf4\xfc\x13\x1f\xdd\xf6\x0f\x10\x14" + + "\x08\xf8\xa9\xf0\x0eJ\xa1B\xfa3X\xf80\x02Zo" + + "\xfc\xf1\x9a\x05\xe1\xad\x0f<\x9e\x83fj/\x87\xdeG" + + "\x09\x8b\x04\x00\xe9F\x88T\xdf\xff\xf1\x1d{\xef\xfc\xed" + + "\xe7\x9b\xfd\xb6'\x16\xfd\x07\xd9n*\"\xc0\x13\x8b>" + + "Z\xde4;\xfcdom\x01\xc2%\x8av\xa0\xb4\xb6" + + "H\x00\xde\xaa\xf8\xe6\xd2\xd3g\xa3S\xb6\x83\xfc\x03\xec" + + "c\xf4W\x84\xcb0\xa3+\x8aV\x01Z\xa3\x9f}\xed" + + "T\xd7\xb4\xf1;\xfcFO\x16\x9d&\xa3\x17\x99\xd1\xae" + + "\xbfS\xff\xe4\xd0\xfe\x9f\x11\x80\xf3\xb4\x01\xd6aq\x17" + + "J\xc3\x8bIUy\xf1m\x80\xd6\xaa\xc5\xc7\x9e]#" + + "_\xde\xd9\xcf\xf2\xaa\x8a\xbbQ\xba\xb5\x98\x96'\xcd\x9c" + + "\xb0\xefl]\xed\xae\xdc\xe5q\x84\x13\x097\x96\xe9\xbc" + + "\xa5\xf8Y@kr\xcf\x0b{\x1f\xfal\xf5\xdf\x13\x9a" + + "\xcb\xdd\xcc\x99\xe2e(}\\<\x14@\xba\xca\xd0\xbf" + + ">ue\xdbC\xbfo\xdc\x93\xab\x9b'\xf4\xefJ\x0e" + + "\xa3\xd4SB\x7fn*\xa9&\xef\xf0\x17>(z\xa8" + + "q\xfc\xde\xfe\xbcs\xb4\xf4\x04J\x17Ki%\xe7K" + + "\xe9\x1c\xdc\xe7\xe2H\xde\xda\xb5\xeb\xc8\xa2)\xff\xb5\xc3" + + "\xa2s\xb8QZ\x89u\xa5C\x16 )\x0e\x0b\x9c\x14" + + "\x12\x05\x00k\xec'\x0fn}\xe0\x99\xe8\xfe\xfe\x94_" + + "-;\x8c6L\x0a\x8a\xa4\xfc\xc4\xde\xedS\xbf\xb9\xb4" + + "j\x7f\xee\xc2\xc9~\xdd\xed\xe2i\x94\xee$t\x9d," + + ">\xc0\x03Ze\x8b\xde\xfa\xc9'w\xff\xfbQ\xbf\xd3" + + "\x8e\x96\xb3(=WN\xfa>T^\xe6\x9aN&_" + + "\xf7\x03n\x94\x17q\x80Ry\x05\x03|\xf0\xdf\xcbZ" + + "\xd3\xe3\xdf\xf4\x03n\xad\xe8f\xb1\xc6\x00\xcb\x8b\x8fE" + + "B\xf5\xc6?\xfa\x01j\xc5a\x02d\x18\xe0Z\xf9\xab" + + "\x8fUN\xdb\xdf\x0b\xf0h\x05[\xc3v\x06\xa8l<" + + "59\x9c\x9a\xf5O9\x07\xc0|q\xb2\xe2I\x94." + + "W\xd0\x01\\\xac \xcf=\xf5\xe5\xb6\xc5{\xd6G\xce" + + "\xf6\x89\xb2\xf5C\x97\xa1\xb4e(!{\x86v\x02Z" + + "\xd7\xef\x9fv_U\xd5\xd9s\xfd\xc6\xcf\x99\xa1WP" + + "\xba\xca\xd0\x9f\x0e\xfd\x10\xd0\xda\xf8\xa7\xab\xd2w/\x99" + + "\xfa^\x0e\x9a\x05\xe5\xf1a\xef\xa0ty\x18[\xc40" + + "Z\xf1\xf5\xa9\xd7_\xdd<-\xfdo\xb9\xaa\x83\xecF" + + "\x0f\xefB\xa9j8\xfd9|\xf8\x02\x0a\x9f;\xd3\xb3" + + "\xc4\x1f\xb6\x0c\xb9\xe0?\x81u\x95\x7fD\x87\xbc\xa5\x92" + + "\xf4M\xf8\xf5\xac\xedw'\xa4K~\xc0\xf1\xca\x8d\xcc" + + "M\x0c\xf0g\xd2k\xbbS\xeb\xaf\\\xee\xe5\xa6\xca+" + + "\x04\x10G\x10\xe0\xd0\xa2\xba\xe6\x7f\xbd\xf4\xc3/@\x1c" + + "\xc7yw\x01\xb0n\xe2\x88n\x94f\x8f\xa0\xb57\x8d" + + "\xa8\x06\xb4N}V\xbd\xf3\x8d\xcb?\xfb2w\xed!" + + "\xd2\xd94b#J\xbf\"t\xdd/F\xdc\xc6\x01Z" + + "[W<\xf5\xc8\xb5Q\xe2W\xb9\xf7\x8amuW\xd5" + + "\xfb(\x1d\xafbQU\xf5:m\xf5\xa5\x8d\x1b\x1e>" + + "2i\xd6W\xbd\xb2D\xb5\x9d%\xaai\xa1\xe5\x7f\xb9" + + "\xf6B\xed\xc7\x97z\x01\xb0\xe6\x04\x01\xcak\x08p\x00" + + "w\x14\xffr\xd9G\xd7\xfc\x80\xdbk\xd8V\xe71\xc0" + + "\xb5\x9eg\xea\xee;\xf9\xc2\xd7\xfdd\x8f\x155'P" + + "ZWC\xd9\xa3\xfb\x9f\xe7\xb4\xbfw\xe3\xe5or\x82" + + "\x8a9?Q\xf3$Jkk\xe8L\xee\xadY\x05\xe3" + + "\xacD\xcaT\xf5\x94\x92,\x18\x9f\xd65S\x1b\x1f\xd3" + + "R\xedZ\xea\xc71%\x9dJO\x9da\xffPW\xab" + + "\xb1hG*6CK\x99J\"\xa5\xea\xa3\x9b\x15]" + + "P\xda\x0d9\xc0\x07\x00\x02\x08 \x96N\x07\x90\x0by" + + "\x94#\x1cv\xea\xea\x8a\x8cj\x98X\xe6\x9d! \x96" + + "\x01\xe6e.\xa6\xab\x8a\xa9\xde\xa1\xb4\xabFZ\x89\xa9" + + "\xc6\xe8\x16\xd5\xc8\x08I\xb3\x97\xb99\x00r\x09\x8f\xf2" + + "0\x0e-]5\xd2Z\xcaP\x01\x00\xcb\xbcz\xf2\xbf" + + "1\xd9\xac\xe8\x0a\x9f\xcf\x06\xddZ7\x00k3r\xac" + + "\xb5\x906\xde0\x9b\x11\xe5\x91\xae\xc1=K\x00\xe4\x17" + + "y\x94\x0fr(\"F\x90\x84\xaf,\x04\x90\x0f\xf0(" + + "\xbf\xcd\xa1\xc8q\x11\xe4\x00\xc43\x84\xfc\x17\x1e\xe5/" + + "8\x14y>\x82<\x80\xf8)\x09?\xe11Z\x88\x1c" + + "\x8a\x81@\x04\x03\x94Jq\x0e@4\x80\xe1&\xc2\xeaU\x89" + + "\xb8\xd9\x86\x02p(\x00\xd6\xb7\xa9\x89\xd66\xd3\xf9\xf9" + + "}\xb8\xf0\xa6'a*\xba\xf9\xd3xT\x8b-W\xcd" + + "\x167/\xe5d\xceZ\xef\"\xf6\x7f\xd1\xf9o3\xc1" + + "k)y>\xa2G\x8f\xc4\x9e5^S'\xf6\xfc\xc6" + + "\xe3\x08b\xcf~\xaf\x17\x14\xb7\xb4\xf8(\xda\x16\xdd\xeb" + + "x\xc5-\x87\xbd\x16E\xdc~\xc2\xeb\x9c\xc5\xe7N{" + + "\xc9A\xdc\xa7\xfb\x98\xdb\xbe5\xbe\xbe}_\x97\x8fr" + + "\xbe\xd2\xed\xd1+\xf1\xd0\x0e_\xbfv\xf4y\x1f+>" + + "~\xd8\xd7\xcb\x9fl\xf11\xe0\x93'\xbc\xb2!\x9e\xe9" + + "\xf6\x11\xa4s;|T\xec\xfc\xf3\xbe&\xefb\x97\xe5" + + "\xdc~\xa8\xb7\xc3\xcf\x15\xf0\x8e\x13\xec\xb2\xe6&\xc8\x16" + + "\x07\xc8n]b\xa5\x0a\xa8[N^\x83j\x96\xd9," + + "\xe7\x9d\xa0\xf3\x92\xa3\xac)\xb7\x1ft\xa2\x1e,\xe7\x11" + + "\xe7{\x96Me\x96\x93\xda\xa0\xda\xb6\xed\xfe\xae\xb7\xf5" + + "ZN!\xc2VO\xa1_\xe6(rn\x1c:W." + + "\xcc\xf4\xe5\x8a\x8dj[\xadS\xd2\xf9^\xfd\x96a\x82" + + "S\xbe\xd0\xc3p\xbd\xea>\x0b_\xcb\x83\xf9\x96\x90\x0d" + + "u\xcc\xc6\xba\xb3\x84\x1c\xb1\xb3\x84\xf9\xeaj\x93\xfe\xe1" + + "<%\xdd\x942\xf5\x0e\x00\xb9\x86\x0f\x02\xb8$\x13\x1d" + + "\"$^\x9d\x0e\x9cxY@\x8fQ\xa0\xc3#\xc5s" + + "\xbf\x01N<% \xe7\x8eq\xd0!\x0d\xe2\xd1n\xe0" + + "\xc4C\x02\xf2\xee\xbc\x02\x1d\x0e,\xee\xa1\xf7v\x09\x18" + + "p\xe9\x14:\x93\x14\xb1g#p\xe2&\x01\x83.#" + + "F\x87\xb5\x89\xeb\xf7\x03'\xae\x13\xb0\xc0\x1d\xfa\xa03" + + "\x1e\x12\xd7v\x01'\xde+\xa0\xe0\xf2`t\x18\x8e\xb8" + + "B\x07NL\x08TC(\x0e\x1b\xd0\x8ae\x83\x09\xb3" + + "a\x01\x0dh9\xbc\x02\x9d`A\xbd\x01-\xa7\x96\xfb" + + "\x91\xba\x1b\x05Y(\xaf\x12\xd4\xe8\xe5\xf1\x19Z\xaa\xde" + + "~\xc5\xb5w\x87\x82\x8eC\x81\xf4\x18Y\xff@5s" + + "P\x03\xfa\xeb\xeb\x00R\x9b\x97\xe4\xfb\xe9\xca\xc6p\xdf" + + "{?\x9as\xd3\xec\x02\xdf\xe0\x98\x96\x9e\xc3J\x80\xe8" + + "N\xea\xd2_B\x8f-H{p!@\xf4E\x92\x1f" + + "D\x0e\xd1\xe6\x0b\xd2+\xac\xa9?@\xe2c\xe8\x15\x1a" + + "\xe9(#\x01\x07I\xfe&z\xb5F:\x8e-\x00\xd1" + + "c$\xff\x80\x91\x06\xde&\x0d\x17q\x19@\xf4\x02\xc9" + + "\xaf3\xd2\x10\xb0I\xc3\xd7\xcc\xec5F&8\x0eE" + + "!\x18!.+\x89\x1c\xc9\xcb8\"\x13$/,\x88" + + "`!\x804\x96\xc9\xc7\x90|&\xc9CB\x04C\x00" + + "R#\xb7\x04 \xda@\xf2_\x92\xbc\xa80\x82E\x00" + + "\xd2/\x98\xfc/H\x1e'yq(\x82\xc5\x00\x92\xc2" + + "\xd1\xbe\x16\x93\xfc\x1e\x92\x97\x14E\xb0\x04@\xea\xe0\xa6" + + "\x03DM\x92?B\xf2R\x8c`)\x80\xb4\x8e\xd3\x01" + + "\xa2\x7f \xf9\xe3$\x1fR\x1c\xc1!\x00\xd2\xa3L\xbe" + + "\x81\xe4\xbbI\x1e.\x89`\x18@\xda\xc5\xf4l#\xf9" + + "\x11\xaeW\xd9\xb5\x96dR\xf1\xa4\xda\xac\x00\xef+h" + + "\xa6\xaa\xb7'RJ\x92\x82 \xdbEU\x1bf<\x91" + + "r{*uu\xc2d\xc4\x06\xfbp\x1eMko\xa2" + + "\xa7\x10V\xcc\xb6>O\x93N\xde\xe6u\x1f\xe5\xf0M" + + "?\x18*\x96T\x95T&=\x03\xf8\xf6x\x1f\xc2\x95" + + "\xd4\x96(\xc9F\x1d\xf8\xbe|+\xa6\xb5\xb7+\xa9x" + + "#\x08z\xdf\x87\x83o\":\xd5\xd4\xca\xbb\x14\xff\x82" + + "soD\xacw\x09\xc2\xb0W\xb7\xedv\xcdR\xe2\xf1" + + "\x84\x99\xd0RP\xad$\x7f\x1awU\x85\xec\xc5u&" + + "Uey_\xf1\xa08D\x8bjd\x92|\xbe\xc4\xcb" + + "m\x0fr\x88\x84p\x13\x8b\x86\xbfs\xcc!/\x06\xc0" + + "w\xb3\x17\xb7\xd9\x18\x00{\xc9\xa6\xe4\xfc)\x92\xdbm" + + "\x0d`\xc2a\xf8\xd3\xa5\xb3\xa1\xef6\xe5\xb6;\x03\x1e" + + "\xdd\x0c\xd6mn'88\xbe\xbc\"#\xa8F.\xdb" + + "\xaa\xf4\xd8\x89\xd8?\xdd\xe2\xfa\xd2-\x7f2\xf9?f" + + "Z\xac\x9f\x09SQd,\x85-\xe5\xd6Q\x8c\xba\x8e" + + "\xa3\xff8\xf1\x16\xfa\x8f\x17\xabj\x010 \x96\x8f\x02" + + "\x10\x12\xe9\x98\x90RM!\x9d\x88\x873\x86\xaa\x0b\x19" + + "\xd3\xc8\xcb?\xfd4\x8b\xbeYA\x99{l\x0a\x1d\xc6" + + "b\xfb0\x9cSK\x10\x1d\x8a\xf3(\xa7}\x1c\xa9\x9d" + + "\x84m<\xca&\x95\xae\x1a\x9b#\xad\xa0\xb7\xd3<\xca" + + "\xf7pvV\x9d\xa1\xc5\x99\x8b\x03\xc0a\x00\xb0\xde0" + + "\xe3Z\xc6t\x0e\x93~\xaa\xba\xee\x9e\xad\x99hW\xe3" + + "?\xcf\x98\xbeL=\xb8\xeaL\xb1\xc5\xf7\x19\x16-\xf3" + + "\xc5_,\x0b\x86\xb0\xde\x9c\x88c!pX\x98g\xe0" + + "9\x0ds\xb67&#\xc3\\#OP\xd8m\xe0Q" + + "\xde\xec\x0b\xbbM\x0b\x01\xe4\xbf\xe5Q\xde\xe6\x0b\xbb-" + + ":\x80\xfc4\x8f\xf2n\x0e1;-\xdc\xd5\x0d \xef" + + "\xe6Q>@u\x9f\xb79\xe6>\x0a\xda\x97x\x94\x8f" + + "P\xd1\x0f\xb0\xa2/\x1e\xa2\x93>\xc8\xa3\xfcn\xef\xa0" + + "5\xd8]\xcf\xa9\x80\xac\xc3S\x0d\x03\xaa\x13Z\xca7" + + "\xae3L-\xdd\xb8\xd4TQ\x8fR=l\xd2p\xe9" + + "\xf79g\x18D\xd2ei\xc3\xc4<\xd3\x86K\xec\x06" + + "\x91x\x07\x96\xa0\\z;\x80\x94\xd8\xcf\x14\xb1Y\x09" + + "\xeby\x0d\xec]f;\x80\x9d9$R\xff\xf1\xfc\x8e" + + "4\xda\xc1\xcf\"-x\x1a\xc0\x0dxNo\xc9\xa4\xe8" + + "\xa2\xcd&\x95K\x19\xed\x1a\xd0h\xcbw\xb7\xc6\xb8\xad" + + "o\x88\xf5\xa6\xee\xe0\xda\xe9|E\xa4V\xad\x84\xc4\xc3" + + "\xd0K\x1eR9\x8er\xe6\xd9#Y\xeb\xcb\xd9\xad\xef" + + "p\x9c\x0a\x10\x8d\x90\xbc\x06\xbd+ U1\xf5#I" + + ">\x06\xbd[ \xdd\xc2\xf05\xce\\\\,\x08\xda\xad" + + "\xefX\xa4\xd6t\x0c\xc9'\x93\\(\xb0[\xdf\x89\xac" + + "U\x9e@\xf2i$/\x14\xec\xd6\xf7v\xa6\x7f\x0a\xc9" + + "g\x92}\xbdn\xa8sk\x07Y \xbc\xb2Z\xe3\xc6\xeb" + + ")\xcaoo\xda_>\x9c\xf4vfa\xf6\xc3\xc7\x05" + + "_}8O\x81\xfd6\x8f\xf2W\xe4\xdf\x06;\xbf]" + + "\xa5\x1b\xf6\x05\x8f\xf2u\xdf\x0c\xedk\xcao\xd7x\x8c" + + "\x06\xfc\xac\x06\xe9\xe8[\xdc\x08qH\xcdp\x16Q," + + "B&\xa0\x8f\xd4\x8cC\"\x0b?\"\xf9\x14\xec\x9d\x12" + + ")\xd8\xb5\x8c\x19\x05^\x8d9#\xc5\xcelo\x9d\xdb" + + "U\xf7\xc3\x15\xfe\x9f;\xed\xc14_y7\x95\xee\xa0" + + "n\xd0M\xa5\x9d\xb0s\xda\xe4o\xcf\xa3\xee\xf0l\x00" + + "\x06\xfb~\xf7lQ\x8dp\xfe\x1fc\xdca\xe2\x00l" + + "\xe6L\x93}3\xd4\xbc\x92\xa53hbs&\xc1\xd4" + + ";r>\xc8\x8c\xf2>\xc8\xb8M\xc2\xb8I\xde\x17\x19" + + "a\xb9\xda\xe1\xce\x92W*\xc9\x8c{\xbf\xff'\x00\x00" + + "\xff\xff\xb7$=\xfd" func RegisterSchema(reg *schemas.Registry) { reg.Register(&schemas.Schema{ @@ -4332,11 +4798,14 @@ func RegisterSchema(reg *schemas.Registry) { 0xad2a33d6b9304413, 0xae78ee8eb6b3a134, 0xb5418b8ea8ead17b, + 0xb62f418e0ae4e003, 0xb737e899dd6633f1, + 0xba53ab87a688ec29, 0xba77e3fa3aa9b6ca, 0xc5e65eec3dcf5b10, 0xc76ccd4502bb61e7, 0xcc2f70676afee4e7, + 0xce733f0914c80b6b, 0xceba3c1a97be15f8, 0xd0476e0f34d1411a, 0xd61491b560a8f3a3, @@ -4350,6 +4819,7 @@ func RegisterSchema(reg *schemas.Registry) { 0xf34be5cbac1feed1, 0xf41122f890a371a6, 0xf44732c48f949ab8, + 0xf4e3e92ae0815f15, 0xf8e86a5c0baa01bc, 0xf9b3cd8033aba1f8, 0xfabbfdde6d4ad392, diff --git a/pkg/client/capnp_util.go b/pkg/client/capnp_util.go index 783ee08027..68cc981dda 100644 --- a/pkg/client/capnp_util.go +++ b/pkg/client/capnp_util.go @@ -58,3 +58,19 @@ func stringStringMapToMapEntryList( return nil } + +func remoteFDSliceToUInt64List(src []RemoteFD, newFunc func(int32) (capnp.UInt64List, error)) error { + l := int32(len(src)) + if l == 0 { + return nil + } + list, err := newFunc(l) + if err != nil { + return err + } + for i := 0; i < len(src); i++ { + list.Set(i, uint64(src[i])) + } + + return nil +} diff --git a/pkg/client/client.go b/pkg/client/client.go index f77289a2a8..e6aa985ef5 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -657,6 +657,12 @@ type CreateContainerConfig struct { // // To use this option set `ConmonServerConfig.CgroupManager` to `CgroupManagerPerCommand`. CgroupManager CgroupManager + + // AdditionalFDs can be used to pass additional file descriptors to the container. + AdditionalFDs []RemoteFD + + // LeakFDs can be used to keep file descriptors open as long as the container is running. + LeakFDs []RemoteFD } // ContainerLogDriver specifies a selected logging mechanism. @@ -751,6 +757,14 @@ func (c *ConmonClient) CreateContainer( c.setCgroupManager(cfg.CgroupManager, req) + if err := remoteFDSliceToUInt64List(cfg.AdditionalFDs, req.NewAdditionalFds); err != nil { + return fmt.Errorf("convert file descriptor slice to slot list: %w", err) + } + + if err := remoteFDSliceToUInt64List(cfg.LeakFDs, req.NewLeakFds); err != nil { + return fmt.Errorf("convert file descriptor slice to slot list: %w", err) + } + return nil }) defer free() diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index cd59db8e06..2668499675 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -319,7 +319,7 @@ var _ = Describe("ConmonClient", func() { rssAfter := vmRSSGivenPID(pid) GinkgoWriter.Printf("VmRSS after: %d\n", rssAfter) GinkgoWriter.Printf("VmRSS diff: %d\n", rssAfter-rssBefore) - Expect(rssAfter - rssBefore).To(BeNumerically("<", 1500)) + Expect(rssAfter - rssBefore).To(BeNumerically("<", 2000)) }) } }) diff --git a/pkg/client/remote_fds.go b/pkg/client/remote_fds.go new file mode 100644 index 0000000000..74ae5dfbd9 --- /dev/null +++ b/pkg/client/remote_fds.go @@ -0,0 +1,184 @@ +package client + +import ( + "context" + "encoding/binary" + "errors" + "fmt" + "net" + "syscall" + + "github.com/containers/conmon-rs/internal/proto" +) + +var ( + errTooManyFileDescriptors = errors.New("too many file descriptors") + errResponseTooShort = errors.New("response too short") + errResponseIDDoesNotMatch = errors.New("response id does not match") + errNumberOfFDsDoesNotMatch = errors.New("number of fds does not match") + errInvalidResponseLength = errors.New("invalid response length") +) + +type serverError string + +func (s serverError) Error() string { + return fmt.Sprintf("server error: %s", string(s)) +} + +const ( + uint64Bytes = 8 + + maxFDs = 253 + msgBufferSize = uint64Bytes + maxFDs*uint64Bytes + 1 // one additional byte used to detect packet truncation + + numFDsBits = 32 +) + +// RemoteFD represents a file descriptor on the server, identified by a slot number. +type RemoteFD uint64 + +func (r RemoteFD) String() string { + return fmt.Sprintf("RemoteFD(%d)", r) +} + +// RemoteFDs can be used to send file descriptors to the server. +type RemoteFDs struct { + conn *net.UnixConn + reqID uint32 +} + +// NewRemoteFDs connects to the fd socket at `path`. +func NewRemoteFDs(path string) (*RemoteFDs, error) { + conn, err := DialLongSocket("unixpacket", path) + if err != nil { + return nil, fmt.Errorf("dial long socket: %w", err) + } + + return &RemoteFDs{ + conn: conn, + }, nil +} + +// Send file descriptors to the server. +func (r *RemoteFDs) Send(fds ...int) ([]RemoteFD, error) { + if len(fds) == 0 { + return nil, nil + } + + if len(fds) > maxFDs { + return nil, errTooManyFileDescriptors + } + + r.reqID++ + reqID := r.reqID + + b := binary.LittleEndian.AppendUint64(nil, uint64(reqID)<> numFDsBits); resID != reqID { + return nil, fmt.Errorf("%w: %d (expected %d)", errResponseIDDoesNotMatch, resID, reqID) + } + + numFDs := int(resIDAndNumFDs & (1<