diff --git a/Cargo.lock b/Cargo.lock index 5e6b9dc37..53a3f9a46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -547,6 +547,15 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +[[package]] +name = "cadeau" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cba4af571bf872af2caaed2d274439dd542db94b75cfeaa85863f674105cf1a0" +dependencies = [ + "xmf-sys", +] + [[package]] name = "camino" version = "1.1.7" @@ -1005,6 +1014,7 @@ dependencies = [ "axum-extra", "backoff", "bytes", + "cadeau", "camino", "ceviche", "cfg-if", @@ -1145,6 +1155,15 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d" +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + [[package]] name = "dlopen" version = "0.1.8" @@ -5938,6 +5957,15 @@ dependencies = [ "time", ] +[[package]] +name = "xmf-sys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17dade9447321f393019b9ced5f73c15b868d2613f736c34f648354d7641ce4" +dependencies = [ + "dlib", +] + [[package]] name = "zeroize" version = "1.8.1" diff --git a/devolutions-gateway/Cargo.toml b/devolutions-gateway/Cargo.toml index 3d8647606..0b606e1b4 100644 --- a/devolutions-gateway/Cargo.toml +++ b/devolutions-gateway/Cargo.toml @@ -83,10 +83,13 @@ utoipa = { version = "4.2", default-features = false, features = ["uuid", "time" # Safe pin projection pin-project-lite = "0.2" -# Native plugins +# Native plugins (QUESTION: now that we have Cadeau integrated, should we remove this feature?) dlopen = "0.1" dlopen_derive = "0.1" +# Video processing for session recording +cadeau = { version = "0.3", features = ["dlopen"] } + # Dependencies required for PCAP support (QUESTION: should we keep that built-in?) pcap-file = "2.0" etherparse = "0.15" diff --git a/devolutions-gateway/src/config.rs b/devolutions-gateway/src/config.rs index cb7220253..135976802 100644 --- a/devolutions-gateway/src/config.rs +++ b/devolutions-gateway/src/config.rs @@ -1080,6 +1080,9 @@ pub mod dto { /// Providing this option will cause the PCAP interceptor to be attached to each stream. pub capture_path: Option, + /// Path to the XMF shared library (Cadeau) for runtime loading. + pub lib_xmf_path: Option, + /// Enable unstable API which may break at any point #[serde(default)] pub enable_unstable: bool, @@ -1095,6 +1098,7 @@ pub mod dto { override_kdc: None, log_directives: None, capture_path: None, + lib_xmf_path: None, enable_unstable: false, } } diff --git a/devolutions-gateway/src/service.rs b/devolutions-gateway/src/service.rs index b664505ff..a0627c122 100644 --- a/devolutions-gateway/src/service.rs +++ b/devolutions-gateway/src/service.rs @@ -1,4 +1,5 @@ use anyhow::Context as _; +use camino::Utf8PathBuf; use devolutions_gateway::config::{Conf, ConfHandle}; use devolutions_gateway::listener::GatewayListener; use devolutions_gateway::log::GatewayLog; @@ -70,6 +71,38 @@ impl GatewayService { warn!("Anomality detected with TLS configuration: {e:#}"); } + let xmf_lib_path; + let xmf_lib_path = if let Some(path) = conf.debug.lib_xmf_path.as_deref() { + Some(path) + } else if cfg!(target_os = "windows") { + if let Ok(mut exe_path) = std::env::current_exe() { + exe_path.pop(); + exe_path.push("xmf.dll"); + xmf_lib_path = Utf8PathBuf::from_path_buf(exe_path).ok(); + xmf_lib_path.as_deref() + } else { + None + } + } else if cfg!(target_os = "linux") { + xmf_lib_path = Some(Utf8PathBuf::from("/usr/lib/libxmf.so")); + xmf_lib_path.as_deref() + } else { + None + }; + + if let Some(path) = xmf_lib_path { + // SAFETY: No initialisation or termination routine in the XMF library we should worry about for preconditions. + let result = unsafe { cadeau::xmf::init(path.as_str()) }; + + match result { + Ok(_) => info!("XMF native library loaded and installed"), + Err(error) => warn!( + %error, + "Failed to load XMF native library, video processing features are disabled" + ), + } + } + Ok(GatewayService { conf_handle, state: GatewayState::Stopped,