diff --git a/Cargo.lock b/Cargo.lock index 3d963c1..5260a56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,8 +142,8 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "busd" -version = "0.5.0" -source = "git+https://github.com/valpackett/busd?branch=val%2Fmsksqvsqqrxm#7084025107e02600043856c56fd178730526daad" +version = "0.4.0" +source = "git+https://github.com/valpackett/busd?branch=val%2Fmsksqvsqqrxm#25736c855284b13371f0be2ef38f16af8f73bda1" dependencies = [ "anyhow", "clap", @@ -151,8 +151,8 @@ dependencies = [ "event-listener", "fastrand", "futures-util", + "nix 0.30.1", "quick-xml", - "rustix", "serde", "tokio", "tracing", @@ -635,15 +635,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.178" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "listenfd" @@ -726,6 +726,19 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -858,9 +871,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.39.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2e3bf4aa9d243beeb01a7b3bc30b77cfe2c44e24ec02d751a7104a53c2c49a1" +checksum = "8927b0664f5c5a98265138b7e3f90aa19a6b21353182469ace36d4ac527b7b1b" dependencies = [ "memchr", "serde", @@ -927,15 +940,15 @@ checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustix" -version = "1.1.3" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1013,7 +1026,6 @@ dependencies = [ "clap", "eyre", "futures", - "libc", "rand", "rustix", "sidebus-common", @@ -1309,9 +1321,7 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom", "js-sys", - "serde", "wasm-bindgen", ] @@ -1328,7 +1338,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e8b4d00e672f147fc86a09738fadb1445bd1c0a40542378dfb82909deeee688" dependencies = [ "libc", - "nix", + "nix 0.29.0", ] [[package]] @@ -1426,12 +1436,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - [[package]] name = "windows-sys" version = "0.52.0" @@ -1459,15 +1463,6 @@ dependencies = [ "windows-targets 0.53.2", ] -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -1656,9 +1651,8 @@ dependencies = [ [[package]] name = "zbus" -version = "5.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc" +version = "5.9.0" +source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c" dependencies = [ "async-broadcast", "async-recursion", @@ -1668,17 +1662,16 @@ dependencies = [ "futures-core", "futures-lite", "hex", - "libc", + "nix 0.30.1", "ordered-stream", - "rustix", + "rand", "serde", "serde_repr", "tokio", "tokio-vsock", "tracing", "uds_windows", - "uuid", - "windows-sys 0.61.2", + "windows-sys 0.60.2", "winnow", "zbus_macros", "zbus_names", @@ -1687,9 +1680,8 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222" +version = "5.9.0" +source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1702,9 +1694,8 @@ dependencies = [ [[package]] name = "zbus_names" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" +version = "4.2.0" +source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c" dependencies = [ "serde", "winnow", @@ -1787,9 +1778,8 @@ dependencies = [ [[package]] name = "zvariant" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b" +version = "5.6.0" +source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c" dependencies = [ "endi", "enumflags2", @@ -1801,9 +1791,8 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c" +version = "5.6.0" +source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1814,9 +1803,8 @@ dependencies = [ [[package]] name = "zvariant_utils" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" +version = "3.2.0" +source = "git+https://github.com/dbus2/zbus#6da6b1b5f528fe2d14b0f25ae1dca1a9fd31575c" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 0f66a83..3d815b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,6 @@ members = [ [workspace.dependencies] sidebus-common = { path = "sidebus-common" } busd = { git = "https://github.com/valpackett/busd", branch = "val/msksqvsqqrxm", default-features = false } -zbus = { version = "5.0", default-features = false, features = ["tokio", "tokio-vsock", "bus-impl", "p2p"] } +zbus = { git = "https://github.com/dbus2/zbus", default-features = false, features = ["tokio", "tokio-vsock", "bus-impl", "p2p"] } +# zbus git to match busd git + diff --git a/README.md b/README.md index c8ebf21..df3aac1 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,6 @@ (it.. runs as a "sidecar" to a VM.. but manages D-*Bus*.. get it?) - - A cross-domain smart D-Bus proxying system that makes (some) [XDG Desktop Portals] work across virtual machines. [XDG Desktop Portals]: https://flatpak.github.io/xdg-desktop-portal/docs/index.html @@ -14,8 +10,9 @@ A cross-domain smart D-Bus proxying system that makes (some) [XDG Desktop Portal - `sidebus-broker` host process: - to be launched alongside the VMM - - hosts a "private" bus for VM-instance-specific daemons such as permission-store and document-portal - - listens on vsock (or on a unix socket that muvm would proxy as vsock) and connects to the VM bus as a client when the agent connects + - hosts D-Bus servers in-process, based on [busd](https://github.com/dbus2/busd): + - a "private" bus for VM-instance-specific daemons such as permission-store and document-portal + - a "VM" bus, the one actually exposed to the guest over vsock - orchestrates the lifecycle of the aforementioned daemons + virtiofsd - (we are sharing the directory *provided by* the document-portal FUSE filesystem!) - provides portal front-end interfaces like `org.freedesktop.portal.FileChooser` on the VM bus @@ -23,10 +20,11 @@ A cross-domain smart D-Bus proxying system that makes (some) [XDG Desktop Portal - (not talking directly to impls: don't want to reimplement per-DE portal selection; also 1:1 mapping is nicer to code) - but with extra hooks like exposing files to the guest using our private (per-VM) document-portal! - `sidebus-agent` guest process: - - connects to the broker over vsock and splices the connection into the VM (session) bus - - can be spawned spawned on-demand by D-Bus + - listens on a guest unix socket, proxies D-Bus messages to a vsock + - spawned on-demand by systemd via socket activation - uses systemd credentials for config args like vsock port - (very convenient to pass via the VMM, e.g. qemu: `-smbios type=11,value=io.systemd.credential:sidebus.port=1337`) + - guest NixOS configuration exposed via the flake ## Development Notes diff --git a/flake.lock b/flake.lock index 8445fa1..e8bb457 100644 --- a/flake.lock +++ b/flake.lock @@ -1,32 +1,30 @@ { "nodes": { - "flake-parts": { + "flake-utils": { "inputs": { - "nixpkgs-lib": [ - "nixpkgs" - ] + "systems": "systems" }, "locked": { - "lastModified": 1768135262, - "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { - "owner": "hercules-ci", - "repo": "flake-parts", + "owner": "numtide", + "repo": "flake-utils", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1762977756, - "narHash": "sha256-4PqRErxfe+2toFJFgcRKZ0UI9NSIOJa+7RXVtBhy4KE=", + "lastModified": 1751271578, + "narHash": "sha256-P/SQmKDu06x8yv7i0s8bvnnuJYkxVGBWLWHaU+tt4YY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c5ae371f1a6a7fd27823bc500d9390b38c05fa55", + "rev": "3016b4b15d13f3089db8a41ef937b13a9e33a8df", "type": "github" }, "original": { @@ -38,8 +36,44 @@ }, "root": { "inputs": { - "flake-parts": "flake-parts", - "nixpkgs": "nixpkgs" + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1751510438, + "narHash": "sha256-m8PjOoyyCR4nhqtHEBP1tB/jF+gJYYguSZmUmVTEAQE=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "7f415261f298656f8164bd636c0dc05af4e95b6b", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" } } }, diff --git a/flake.nix b/flake.nix index c2050d0..1aeb30c 100644 --- a/flake.nix +++ b/flake.nix @@ -1,60 +1,80 @@ { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-parts.url = "github:hercules-ci/flake-parts"; - flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; + flake-utils.url = "github:numtide/flake-utils"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; - outputs = - inputs@{ flake-parts, ... }: - flake-parts.lib.mkFlake { inherit inputs; } { - systems = [ - "x86_64-linux" - "aarch64-linux" - ]; - - perSystem = - { pkgs, ... }: - let - buildEnvVars = { - BIN_XDG_PERMISSION_STORE = "${pkgs.xdg-desktop-portal}/libexec/xdg-permission-store"; - BIN_XDG_DOCUMENT_PORTAL = "${pkgs.xdg-desktop-portal}/libexec/xdg-document-portal"; - BIN_VIRTIOFSD = "${pkgs.virtiofsd}/bin/virtiofsd"; - }; - - rustPackage = - crate: - let - cargoToml = builtins.fromTOML (builtins.readFile ./${crate}/Cargo.toml); - in - pkgs.rustPlatform.buildRustPackage { - inherit (cargoToml.package) name version; - src = ./.; - cargoLock.lockFile = ./Cargo.lock; - cargoLock.outputHashes = { - "busd-0.5.0" = "sha256-IZZ2MeEmUbzRrH6SUz0pnecMH4f8Mh54WdhI4q44YfI="; - }; - buildAndTestSubdir = crate; - env = buildEnvVars; - }; - in - { - devShells.default = pkgs.mkShell { - buildInputs = with pkgs; [ - cargo - rustc - rust-analyzer - clippy - ]; - env = buildEnvVars; - }; - - packages.sidebus-agent = rustPackage "sidebus-agent"; - packages.sidebus-broker = rustPackage "sidebus-broker"; + outputs = {self, nixpkgs, flake-utils, rust-overlay}: + flake-utils.lib.eachDefaultSystem (system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { + inherit system overlays; }; - flake = { - nixosModules.sidebus-vm = ./nixosModules/sidebus-vm.nix; - }; - }; + buildEnvVars = { + BIN_XDG_PERMISSION_STORE = "${pkgs.xdg-desktop-portal}/libexec/xdg-permission-store"; + BIN_XDG_DOCUMENT_PORTAL = "${pkgs.xdg-desktop-portal}/libexec/xdg-document-portal"; + BIN_VIRTIOFSD = "${pkgs.virtiofsd}/bin/virtiofsd"; + }; + + rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + rustPlatform = pkgs.makeRustPlatform { + cargo = rustToolchain; + rustc = rustToolchain; + }; + rustPackage = crate: + let cargoToml = builtins.fromTOML (builtins.readFile ./${crate}/Cargo.toml); + in rustPlatform.buildRustPackage { + inherit (cargoToml.package) name version; + src = ./.; + cargoLock.lockFile = ./Cargo.lock; + cargoLock.outputHashes = { + "zbus-5.9.0" = "sha256-3xaKbf+JmO5yVwPbvA3z9dHvqICh7yCeKk1SIX8zhJA="; + "busd-0.4.0" = "sha256-UzTclEJ8lRMmiuLJJi+gsm7vkx+MLfnDdi5s9OVT1HE="; + }; + buildAndTestSubdir = crate; + env = buildEnvVars; + }; + in + { + devShells.default = pkgs.mkShell { + buildInputs = [ rustToolchain ]; + env = buildEnvVars; + }; + + packages.sidebus-agent = rustPackage "sidebus-agent"; + packages.sidebus-broker = rustPackage "sidebus-broker"; + + nixosModules.sidebus-vm = { ... }: { + environment.sessionVariables.DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/sidebus.sock"; + systemd.sockets.sidebus-agent = { + # SocketMode= is 0666 by default + listenStreams = [ "/run/sidebus.sock" ]; + wantedBy = [ "sockets.target" ]; + documentation = [ "https://git.clan.lol/valpackett/sidebus" ]; + }; + systemd.services.sidebus-agent = { + # TODO: confinement (can do a lot) + serviceConfig = { + ExecStart = "${rustPackage "sidebus-agent"}/bin/sidebus-agent"; + ImportCredential = "sidebus.*"; + }; + documentation = [ "https://git.clan.lol/valpackett/sidebus" ]; + }; + systemd.mounts = [ + { + type = "virtiofs"; + what = "vm-doc-portal"; + where = "/run/vm-doc-portal"; + wantedBy = [ "multi-user.target" ]; + } + ]; + }; + } + ); } diff --git a/nixosModules/sidebus-vm.nix b/nixosModules/sidebus-vm.nix deleted file mode 100644 index 215d2b1..0000000 --- a/nixosModules/sidebus-vm.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ - environment.sessionVariables.DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/sidebus.sock"; - systemd.sockets.sidebus-agent = { - # SocketMode= is 0666 by default - listenStreams = [ "/run/sidebus.sock" ]; - wantedBy = [ "sockets.target" ]; - documentation = [ "https://git.clan.lol/valpackett/sidebus" ]; - }; - systemd.services.sidebus-agent = { - # TODO: confinement (can do a lot) - serviceConfig = { - ExecStart = throw "sidebus-vm module requires setting systemd.services.sidebus-agent.serviceConfig.ExecStart to a sidebus-agent package"; - ImportCredential = "sidebus.*"; - }; - documentation = [ "https://git.clan.lol/valpackett/sidebus" ]; - }; - systemd.mounts = [ - { - type = "virtiofs"; - what = "vm-doc-portal"; - where = "/run/vm-doc-portal"; - wantedBy = [ "multi-user.target" ]; - } - ]; -} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..a1de405 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.88.0" +components = ["rust-analyzer", "rust-src", "clippy"] diff --git a/sidebus-agent/src/main.rs b/sidebus-agent/src/main.rs index 650cde3..984a59f 100644 --- a/sidebus-agent/src/main.rs +++ b/sidebus-agent/src/main.rs @@ -1,3 +1,5 @@ +use eyre::OptionExt; +use tokio::net::UnixListener; use tracing::info; #[tokio::main] @@ -8,23 +10,38 @@ async fn main() -> eyre::Result<()> { let vsock_port = std::fs::read_to_string(creds_dir.join("sidebus.port"))? .trim() .parse::()?; - let vsock_addr = zbus::Address::from(zbus::address::Transport::Vsock( - zbus::address::transport::Vsock::new(2, vsock_port), - )); - info!("connecting to session bus"); - let session_conn = zbus::connection::Builder::session()?.p2p().build().await?; - - let vsock_conn = zbus::connection::Builder::address(vsock_addr)? - .server(session_conn.server_guid()) - .unwrap() - .p2p() - .auth_mechanism(zbus::AuthMechanism::Anonymous) - .build() - .await - .unwrap(); - info!(guid = %vsock_conn.server_guid(), "connected to vsock bus"); - sidebus_common::raw::splice_conns(vsock_conn, session_conn).await; + let unix_listener = UnixListener::from_std( + listenfd::ListenFd::from_env() + .take_unix_listener(0)? + .ok_or_eyre("no unix listener provided")?, + )?; + info!("listening for unix clients"); + while let Ok((unix_client, client_addr)) = unix_listener.accept().await { + info!(?client_addr, "new unix client"); + tokio::spawn(async move { + let vsock_addr = zbus::Address::from(zbus::address::Transport::Vsock( + zbus::address::transport::Vsock::new(2, vsock_port), + )); + let vsock_conn = zbus::connection::Builder::address(vsock_addr) + .unwrap() + .p2p() + .auth_mechanism(zbus::AuthMechanism::Anonymous) + .build() + .await + .unwrap(); + info!(guid = %vsock_conn.server_guid(), "connected to vsock bus"); + let client_conn = zbus::connection::Builder::unix_stream(unix_client) + .server(vsock_conn.server_guid()) + .unwrap() + .p2p() + .auth_mechanism(zbus::AuthMechanism::External) + .build() + .await + .unwrap(); + sidebus_common::raw::splice_conns(client_conn, vsock_conn).await; + }); + } Ok(()) } diff --git a/sidebus-broker/Cargo.toml b/sidebus-broker/Cargo.toml index 1cbde4d..3be80d9 100644 --- a/sidebus-broker/Cargo.toml +++ b/sidebus-broker/Cargo.toml @@ -18,4 +18,3 @@ rustix = { version = "1.0.8", features = ["fs"] } url = "2.5.4" rand = "0.9.2" futures = "0.3.31" -libc = "0.2.178" diff --git a/sidebus-broker/src/bus.rs b/sidebus-broker/src/bus.rs index b2fd94f..4607379 100644 --- a/sidebus-broker/src/bus.rs +++ b/sidebus-broker/src/bus.rs @@ -1,6 +1,6 @@ -use std::{hash::DefaultHasher, sync::Arc}; +use std::sync::Arc; use tokio_stream::StreamExt as _; -use tracing::{debug, error, trace}; +use tracing::{debug, trace}; pub struct HostedBus { peers: Arc, @@ -57,14 +57,10 @@ impl HostedBus { .map_err(|err| eyre::eyre!(Box::new(err))) // https://github.com/eyre-rs/eyre/issues/31 XXX: busd should not use anyhow! } - pub async fn connect_unix( - &mut self, - socket: tokio::net::UnixStream, - auth: zbus::AuthMechanism, - ) -> eyre::Result<()> { + pub async fn connect_unix(&mut self, socket: tokio::net::UnixStream) -> eyre::Result<()> { let id = self.next_id(); self.peers - .add(&self.guid, id, socket.into(), auth) + .add(&self.guid, id, socket.into(), zbus::AuthMechanism::External) .await .map_err(|err| eyre::eyre!(Box::new(err))) } @@ -81,7 +77,7 @@ impl HostedBus { } pub trait SharedHostedBus { - async fn run_unix_listener(self, listener: tokio::net::UnixListener, auth: zbus::AuthMechanism); + async fn run_unix_listener(self, listener: tokio::net::UnixListener); async fn spawn_external_client( self, command: &mut tokio::process::Command, @@ -89,15 +85,9 @@ pub trait SharedHostedBus { } impl SharedHostedBus for Arc> { - async fn run_unix_listener( - self, - listener: tokio::net::UnixListener, - auth: zbus::AuthMechanism, - ) { + async fn run_unix_listener(self, listener: tokio::net::UnixListener) { while let Ok((socket, _remote_addr)) = listener.accept().await { - if let Err(e) = self.lock().await.connect_unix(socket, auth).await { - error!("unix connection: {:?}", e); - } + self.lock().await.connect_unix(socket).await.unwrap() } } @@ -110,7 +100,7 @@ impl SharedHostedBus for Arc> { let abstract_path = format!("/run/sidebus-broker/{}", zbus::Guid::generate()); let listener = tokio::net::UnixListener::bind(format!("\0{abstract_path}"))?; debug!(%abstract_path, "opened listener for external client"); - tokio::spawn(self.run_unix_listener(listener, zbus::AuthMechanism::External)); + tokio::spawn(self.run_unix_listener(listener)); Ok(command .env( "DBUS_SESSION_BUS_ADDRESS", diff --git a/sidebus-broker/src/main.rs b/sidebus-broker/src/main.rs index aad976b..7a2247d 100644 --- a/sidebus-broker/src/main.rs +++ b/sidebus-broker/src/main.rs @@ -4,12 +4,9 @@ mod vsock; use bus::SharedHostedBus; use clap::Parser; -use eyre::OptionExt; -use futures::{TryFutureExt, stream::FuturesUnordered}; -use std::{path::PathBuf, sync::Arc, time::Duration}; +use std::{path::PathBuf, sync::Arc}; use tokio::{net::UnixListener, process::Command, sync::Mutex}; -use tokio_stream::StreamExt as _; -use tracing::{Instrument, debug, error, info_span}; +use tracing::error; use zbus::names::WellKnownName; // https://github.com/rust-lang/rfcs/issues/2407#issuecomment-385291238 @@ -25,7 +22,7 @@ macro_rules! enclose { #[derive(Parser)] #[command(version, about, long_about = None)] struct BrokerCli { - /// Create unix socket listeners for internal busses in the provided directory + /// Create unix socket listeners for all internal busses in the provided directory #[clap(long)] debug_access: Option, @@ -37,29 +34,9 @@ struct BrokerCli { #[clap(long, default_value = "/run/vm-doc-portal")] guest_mountpoint: PathBuf, - /// Mappings from guest paths to host paths for passthrough file systems (for file transfer), in guest=host format + /// Vsock port number to listen on #[clap(long)] - path_mapping: Vec, - - /// Vsock port number to listen on for the VM bus - #[clap(long)] - vsock_port: Option, - - /// Unix socket path to listen on for the VM bus - #[clap(long)] - unix_path: Option, - - /// Use ANONYMOUS auth to connect to the guest bus instead of EXTERNAL with the provided --guest-uid - #[clap(long)] - guest_bus_anonymous_auth: bool, - - /// The user ID for the appvm user inside of the guest - #[clap(long, default_value = "1337")] - guest_uid: u32, - - /// The group ID for the appvm group inside of the guest - #[clap(long, default_value = "1337")] - guest_gid: u32, + vsock_port: u32, } async fn new_hosted_bus() -> eyre::Result<( @@ -74,272 +51,110 @@ async fn new_hosted_bus() -> eyre::Result<( Ok((Arc::new(Mutex::new(bus)), guid, owner_stream)) } -fn parse_path_mapping(s: &str) -> eyre::Result<(PathBuf, PathBuf)> { - let mut split = s.split('='); - let guest_path = PathBuf::from(split.next().ok_or_eyre("failed to split mapping")?); - let host_path = PathBuf::from(split.next().ok_or_eyre("failed to split mapping")?); - Ok((guest_path, host_path)) -} - #[tokio::main] async fn main() -> eyre::Result<()> { tracing_subscriber::fmt::init(); let cli = BrokerCli::parse(); - let mut path_prefix_to_host: Vec<(PathBuf, PathBuf)> = cli - .path_mapping - .iter() - .flat_map(|arg| match parse_path_mapping(arg) { - Ok(mapping) => Some(mapping), - Err(err) => { - error!(?err, %arg, "could not parse path mapping"); - None - } - }) - .collect(); - path_prefix_to_host.sort_unstable_by_key(|(prefix, _)| -(prefix.as_os_str().len() as isize)); - debug!(?path_prefix_to_host, "parsed path mappings"); + let (vm_bus, vm_bus_guid, _) = new_hosted_bus().await?; let (priv_bus, _, mut priv_lst) = new_hosted_bus().await?; - let mut server_tasks = tokio::task::JoinSet::new(); - let mut child_procs = Vec::new(); - if let Some(dir_path) = cli.debug_access { if !dir_path.is_dir() { error!(path = %dir_path.display(), "--debug-access path is not an existing directory"); std::process::exit(1); } + let vm_dbg_listener = UnixListener::bind(dir_path.join("vm.sock"))?; + let _vm_dbg_task = tokio::spawn(vm_bus.clone().run_unix_listener(vm_dbg_listener)); let priv_dbg_listener = UnixListener::bind(dir_path.join("priv.sock"))?; - server_tasks.spawn( - priv_bus - .clone() - .run_unix_listener(priv_dbg_listener, zbus::AuthMechanism::External), - ); + let _priv_dbg_task = tokio::spawn(priv_bus.clone().run_unix_listener(priv_dbg_listener)); // TODO: unlink sockets on exit } std::fs::create_dir_all(&cli.runtime_dir)?; - child_procs.push( - priv_bus - .clone() - .spawn_external_client( - Command::new(env!("BIN_XDG_PERMISSION_STORE")) - .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str()) - .kill_on_drop(true), - ) - .await?, - ); + let _xps = priv_bus + .clone() + .spawn_external_client( + Command::new(env!("BIN_XDG_PERMISSION_STORE")) + .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str()) + .kill_on_drop(true), + ) + .await?; let impl_permission_store = WellKnownName::from_static_str("org.freedesktop.impl.portal.PermissionStore")?.into(); priv_lst.wait_for_acquisition(impl_permission_store).await?; - child_procs.push( - priv_bus - .clone() - .spawn_external_client( - Command::new(env!("BIN_XDG_DOCUMENT_PORTAL")) - .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str()) - .kill_on_drop(true), - ) - .await?, - ); + let _xdp = priv_bus + .clone() + .spawn_external_client( + Command::new(env!("BIN_XDG_DOCUMENT_PORTAL")) + .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str()) + .kill_on_drop(true), + ) + .await?; let portal_documents = WellKnownName::from_static_str("org.freedesktop.portal.Documents")?.into(); priv_lst.wait_for_acquisition(portal_documents).await?; - child_procs.push( - Command::new(env!("BIN_VIRTIOFSD")) - .args(&[ - "--shared-dir", - cli.runtime_dir.join("doc").to_str().unwrap(), - "--socket-path", - cli.runtime_dir.join("fs.sock").to_str().unwrap(), - "--uid-map", - &format!(":{}:{}:1:", cli.guest_uid, unsafe { libc::getuid() }), - "--gid-map", - &format!(":{}:{}:1:", cli.guest_gid, unsafe { libc::getgid() }), - "--log-level", - "debug", - ]) - .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str()) - .kill_on_drop(true) - .spawn()?, - ); + let _vfs = Command::new(env!("BIN_VIRTIOFSD")) + .args(&[ + "--shared-dir", + cli.runtime_dir.join("doc").to_str().unwrap(), + "--socket-path", + cli.runtime_dir.join("fs.sock").to_str().unwrap(), + "--uid-map", + ":1000:1001:1:", + "--gid-map", + ":100:100:1:", + "--log-level", + "debug", + ]) + .env("XDG_RUNTIME_DIR", cli.runtime_dir.as_os_str()) + .kill_on_drop(true) + .spawn(); + // TODO: die when it exits + let vm_bus_conn = vm_bus.lock().await.connect_channel(false).await?; let priv_bus_conn = priv_bus.lock().await.connect_channel(false).await?; let host_session_conn = zbus::connection::Builder::session()?.build().await?; let file_chooser_imp = portal::file_chooser::FileChooser::new( - &host_session_conn, - &priv_bus_conn, - cli.guest_mountpoint.clone(), - ) - .await?; - let file_transfer_imp = portal::file_transfer::FileTransfer::new( &host_session_conn, &priv_bus_conn, cli.guest_mountpoint, - path_prefix_to_host, ) .await?; - let notification_imp = portal::notification::Notification::new(&host_session_conn).await?; - let print_imp = portal::print::Print::new(&host_session_conn).await?; - let settings_imp = portal::settings::Settings::new(&host_session_conn).await?; - - async fn on_vm_bus_connected( - vm_bus_conn: zbus::Connection, - file_chooser: portal::file_chooser::FileChooser, - file_transfer: portal::file_transfer::FileTransfer, - notification: portal::notification::Notification, - print: portal::print::Print, - settings: portal::settings::Settings, - ) -> Result<(), eyre::Report> { - if !vm_bus_conn - .object_server() - .at("/org/freedesktop/portal/desktop", file_chooser) - .await? - { - error!("org.freedesktop.portal.FileChooser already provided"); - }; - - if !vm_bus_conn - .object_server() - .at("/org/freedesktop/portal/documents", file_transfer) - .await? - { - error!("org.freedesktop.portal.FileTransfer already provided"); - }; - let file_transfer_ref = vm_bus_conn - .object_server() - .interface::<_, portal::file_transfer::FileTransfer>( - "/org/freedesktop/portal/documents", - ) - .await?; - tokio::spawn(async move { - let file_transfer = file_transfer_ref.get().await; - let emitter = file_transfer_ref.signal_emitter(); - if let Err(err) = file_transfer.forward_transfer_closed(emitter.clone()).await { - error!(%err, "forwarding forward_transfer_closed changes ended"); - } - }); - - if !vm_bus_conn - .object_server() - .at("/org/freedesktop/portal/desktop", notification) - .await? - { - error!("org.freedesktop.portal.Notification already provided"); - }; - let notification_ref = vm_bus_conn - .object_server() - .interface::<_, portal::notification::Notification>("/org/freedesktop/portal/desktop") - .await?; - tokio::spawn(async move { - let notification = notification_ref.get().await; - let emitter = notification_ref.signal_emitter(); - if let Err(err) = notification.forward_actions(emitter.clone()).await { - error!(%err, "forwarding notification changes ended"); - } - }); - - if !vm_bus_conn - .object_server() - .at("/org/freedesktop/portal/desktop", print) - .await? - { - error!("org.freedesktop.portal.Print already provided"); - }; - - if !vm_bus_conn - .object_server() - .at("/org/freedesktop/portal/desktop", settings) - .await? - { - error!("org.freedesktop.portal.Settings already provided"); - }; - let settings_ref = vm_bus_conn - .object_server() - .interface::<_, portal::settings::Settings>("/org/freedesktop/portal/desktop") - .await?; - tokio::spawn(async move { - let settings = settings_ref.get().await; - let emitter = settings_ref.signal_emitter(); - if let Err(err) = settings.forward_changes(emitter).await { - error!(%err, "forwarding settings changes ended"); - } - }); - - // XXX: no method for "wait until the conn dies"? - Ok(std::future::pending::<()>().await) - } - - if let Some(path) = cli.unix_path { - let vm_unix_listener = UnixListener::bind(path)?; - server_tasks.spawn(enclose!((file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp) async move { - while let Ok((socket, remote_addr)) = vm_unix_listener.accept().await { - let f = enclose!((file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp) async move { - let client_conn = if cli.guest_bus_anonymous_auth { - zbus::connection::Builder::unix_stream(socket).auth_mechanism(zbus::AuthMechanism::Anonymous) - } else { - zbus::connection::Builder::unix_stream(socket).user_id(cli.guest_uid) - } - .name("org.freedesktop.portal.Desktop")? - .name("org.freedesktop.portal.Documents")? - .build() - .await?; - on_vm_bus_connected(client_conn, file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp).await - }); - tokio::spawn( - async { - match f.await { - Ok(()) => debug!("done with server"), - Err(err) => error!(%err, "error dealing with server"), - } - } - .instrument(info_span!("serve", ?remote_addr)), - ); - } - })); - } - - if let Some(port) = cli.vsock_port { - // TODO: modprobe vhost_vsock first! - server_tasks.spawn( - vsock::ListenerBuilder::new(vsock::VsockAddr::new(vsock::VMADDR_CID_HOST, port)) - .with_label("VM Bus") - .listen(move |client| { - enclose!((file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp) async move { - // TODO: Not necessary to go through the channel, add vsock support to the Peer too? - let client_conn = client.build().await?; - on_vm_bus_connected(client_conn, file_chooser_imp, file_transfer_imp, notification_imp, print_imp, settings_imp).await - }) - }) - .map_ok_or_else( - |e| { - error!("vsock listener: {:?}", e); - }, - |()| (), - ), - ); - } - - let mut waiter = child_procs - .iter_mut() - .map(|child| child.wait()) - .collect::>(); - tokio::select! { - _ = server_tasks.join_all() => debug!("server tasks ended"), - res = waiter.next() => debug!(?res, "child process terminated"), - _ = tokio::signal::ctrl_c() => debug!("interrupt signal"), + vm_bus_conn + .request_name("org.freedesktop.portal.Desktop") + .await?; + let true = vm_bus_conn + .object_server() + .at("/org/freedesktop/portal/desktop", file_chooser_imp) + .await? + else { + unreachable!("our own fresh bus can't have interfaces already provided"); }; - drop(waiter); - for mut child in child_procs { - if let Err(e) = child.kill().await { - error!(?e, "could not kill process"); - } - } + + // TODO: modprobe vhost_vsock first! + // NOTE: Every individual D-Bus client inside of the VM is a new client here! + vsock::ListenerBuilder::new(vsock::VsockAddr::new( + vsock::VMADDR_CID_HOST, + cli.vsock_port, + )) + .with_label("VM Bus") + .listen(move |client| { + enclose! { (vm_bus, vm_bus_guid) async move { + // TODO: Not necessary to go through the channel, add vsock support to the Peer too + let client_conn = client.build((&vm_bus_guid).into()).await?; + let vmbus_conn = vm_bus.lock().await.connect_channel(true).await?; + sidebus_common::raw::splice_conns(client_conn, vmbus_conn).await; + Ok(()) + } } + }) + .await?; + Ok(()) } diff --git a/sidebus-broker/src/portal/file_chooser.rs b/sidebus-broker/src/portal/file_chooser.rs index 6121da8..b3a0ff9 100644 --- a/sidebus-broker/src/portal/file_chooser.rs +++ b/sidebus-broker/src/portal/file_chooser.rs @@ -8,7 +8,6 @@ use zbus::{Connection, ObjectServer, fdo::Result, zvariant}; use super::documents::DocumentsProxy; use super::request::{RESPONSE_SUCCESS, ReqHandler, ResultTransformer}; -#[derive(Clone)] pub struct FileChooser { host: FileChooserProxy<'static>, docs: DocumentsProxy<'static>, @@ -53,7 +52,6 @@ impl FileChooser { docs: self.docs.clone(), guest_root: self.guest_root.clone(), for_save: false, - persistent: true, directory: options.get_as("directory")?.unwrap_or(false), }) .perform(async || self.host.open_file(parent_window, title, options).await) @@ -74,7 +72,6 @@ impl FileChooser { docs: self.docs.clone(), guest_root: self.guest_root.clone(), for_save: true, - persistent: true, directory: false, }) .perform(async || self.host.save_file(parent_window, title, options).await) @@ -95,7 +92,6 @@ impl FileChooser { docs: self.docs.clone(), guest_root: self.guest_root.clone(), for_save: true, - persistent: true, directory: false, }) .perform(async || self.host.save_files(parent_window, title, options).await) @@ -109,13 +105,11 @@ impl FileChooser { } } -#[derive(Clone)] -pub struct FileTransformer { - pub docs: DocumentsProxy<'static>, - pub guest_root: PathBuf, - pub for_save: bool, - pub persistent: bool, - pub directory: bool, +struct FileTransformer { + docs: DocumentsProxy<'static>, + guest_root: PathBuf, + for_save: bool, + directory: bool, } // ref: send_response_in_thread_func @@ -139,14 +133,6 @@ impl ResultTransformer for FileTransformer { .async_map(|u| self.add_path_as_doc(u)) .await .flatten() - .map(|path| match url::Url::from_file_path(&path) { - Ok(url) => Some(url.to_string()), - Err(err) => { - warn!(?err, ?path, "could not make url from returned path"); - None - } - }) - .flatten() .collect::>(); results.insert("uris", guest_uris.into()); @@ -163,7 +149,7 @@ const DIRECTORY: u32 = 1 << 3; // https://github.com/flatpak/xdg-desktop-portal/blob/10e712e06aa8eb9cd0e59c73c5be62ba53e981a4/src/xdp-documents.c#L71 impl FileTransformer { - pub async fn add_path_as_doc(&self, path: PathBuf) -> Option { + async fn add_path_as_doc(&self, path: PathBuf) -> Option { use rustix::fs::{Mode, OFlags}; let o_path_fd = match rustix::fs::open( @@ -179,8 +165,8 @@ impl FileTransformer { }; let flags = REUSE_EXISTING + | PERSISTENT | AS_NEEDED_BY_APP - | if self.persistent { PERSISTENT } else { 0 } | if self.directory { DIRECTORY } else { 0 }; // XXX: portal impl can return writable=false but host frontend does not pass that back.. @@ -225,7 +211,14 @@ impl FileTransformer { return None; } }; - Some(self.guest_root.join(doc_id).join(filename)) + let path = self.guest_root.join(doc_id).join(filename); + match url::Url::from_file_path(&path) { + Ok(url) => Some(url.to_string()), + Err(err) => { + warn!(?err, ?path, "could not make url from returned path"); + None + } + } } } diff --git a/sidebus-broker/src/portal/file_transfer.rs b/sidebus-broker/src/portal/file_transfer.rs deleted file mode 100644 index 8c175f6..0000000 --- a/sidebus-broker/src/portal/file_transfer.rs +++ /dev/null @@ -1,205 +0,0 @@ -use std::{ - collections::HashMap, - os::fd::{AsFd, AsRawFd}, - os::unix::ffi::OsStrExt, - path::PathBuf, -}; - -use tokio::sync::broadcast; -use tokio_stream::StreamExt; -use tracing::{debug, error}; -use zbus::{ - Connection, fdo::Result, names::OwnedUniqueName, object_server::SignalEmitter, zvariant, -}; - -use super::{documents::DocumentsProxy, file_chooser::FileTransformer}; - -#[derive(Clone)] -pub struct FileTransfer { - host: FileTransferProxy<'static>, - file_transformer: FileTransformer, - tx: broadcast::Sender, - path_prefix_to_host: Vec<(PathBuf, PathBuf)>, -} - -#[derive(Clone, Debug)] -enum ForwarderCommand { - Add(String, OwnedUniqueName), - // Remove(String), -} - -#[zbus::interface( - name = "org.freedesktop.portal.FileTransfer", - proxy( - default_service = "org.freedesktop.portal.Documents", - default_path = "/org/freedesktop/portal/documents" - ) -)] -impl FileTransfer { - async fn add_files( - &self, - key: &str, - fds: Vec>, - options: HashMap<&str, zvariant::Value<'_>>, - ) -> Result<()> { - let mut host_paths = Vec::with_capacity(fds.len()); - for fd in fds.iter() { - let link = rustix::fs::readlink( - format!("/proc/self/fd/{}", fd.as_fd().as_raw_fd()), - Vec::new(), - ) - .map_err(|e| zbus::fdo::Error::Failed(e.to_string()))?; - let guest_path = std::path::PathBuf::from(std::ffi::OsStr::from_bytes( - &link.to_string_lossy().as_bytes(), - )); - let (prefix, host_prefix) = self - .path_prefix_to_host - .iter() - .find(|(prefix, _)| guest_path.starts_with(prefix)) - .ok_or_else(|| { - zbus::fdo::Error::Failed("Could not find host mapping for path".to_owned()) - })?; - let guest_suffix = guest_path - .strip_prefix(prefix) - .map_err(|e| zbus::fdo::Error::Failed(e.to_string()))?; - let host_path = if guest_suffix.as_os_str().is_empty() { - // Edge case: a bind-mounted file exposed at the same path would get an extra '/' after its path - host_prefix.to_path_buf() - } else { - host_prefix.join(guest_suffix) - }; - debug!( - ?guest_path, - ?prefix, - ?guest_suffix, - ?host_prefix, - ?host_path, - "mapped path" - ); - let path_fd = rustix::fs::open( - host_path, - rustix::fs::OFlags::PATH, - rustix::fs::Mode::empty(), - ) - .map_err(|e| zbus::fdo::Error::Failed(e.to_string()))?; - host_paths.push(path_fd.into()); // OwnedFd variant of zbus's Fd enum, so still owned by the Vec - } - self.host.add_files(key, host_paths, options).await - } - - async fn retrieve_files( - &self, - key: &str, - options: HashMap<&str, zvariant::Value<'_>>, - ) -> Result> { - let host_paths = self.host.retrieve_files(key, options).await?; - let mut result = Vec::with_capacity(host_paths.len()); - for host_path in host_paths { - if let Some(guest_path) = self - .file_transformer - .add_path_as_doc(PathBuf::from(&host_path)) - .await - { - result.push(guest_path.to_string_lossy().into_owned()); - } else { - debug!(%host_path, "could not add path as doc to retrieve file"); - } - } - Ok(result) - } - - async fn start_transfer( - &self, - #[zbus(header)] hdr: zbus::message::Header<'_>, - options: HashMap<&str, zvariant::Value<'_>>, - ) -> Result { - let sender = hdr - .sender() - .ok_or_else(|| zbus::Error::MissingField)? - .to_owned(); - let key = self.host.start_transfer(options).await?; - debug!(%key, %sender, "started transfer"); - if let Err(err) = self - .tx - .send(ForwarderCommand::Add(key.clone(), sender.into())) - { - error!(?err, "file_transfer internal channel error"); - return Err(zbus::fdo::Error::IOError("channel error".to_owned())); - } - Ok(key) - } - - async fn stop_transfer(&self, key: &str) -> Result<()> { - debug!(%key, "stopping transfer"); - self.host.stop_transfer(key).await - } - - #[zbus(signal)] - async fn transfer_closed(signal_emitter: &SignalEmitter<'_>, key: &str) -> zbus::Result<()>; - - #[zbus(property, name = "version")] - fn version(&self) -> Result { - Ok(1) - } -} - -impl FileTransfer { - pub async fn new( - host_session_conn: &Connection, - priv_conn: &Connection, - guest_root: PathBuf, - path_prefix_to_host: Vec<(PathBuf, PathBuf)>, - ) -> Result { - let host = FileTransferProxy::builder(host_session_conn) - .build() - .await?; - let docs = DocumentsProxy::builder(priv_conn).build().await?; - let file_transformer = FileTransformer { - docs, - guest_root, - for_save: false, - persistent: false, - directory: false, - }; - let (tx, _) = broadcast::channel(8); - Ok(FileTransfer { - host, - file_transformer, - tx, - path_prefix_to_host, - }) - } - - pub async fn forward_transfer_closed( - &self, - mut signal_emitter: SignalEmitter<'static>, - ) -> Result<()> { - let mut stream = self.host.receive_transfer_closed().await?; - let mut cmds = self.tx.subscribe(); - let mut receivers = HashMap::new(); - - loop { - tokio::select! { - Ok(cmd) = cmds.recv() => match cmd { - ForwarderCommand::Add(key, receiver) => { receivers.insert(key, receiver); }, - // ForwarderCommand::Remove(key) => { receivers.remove(&key); }, - }, - Some(signal) = stream.next() => { - debug!(?signal, "transfer closed"); - if let Ok((key,)) = signal.0.deserialize::<(&str,)>() { - if let Some(bus_name) = receivers.remove(key) { - signal_emitter = signal_emitter.set_destination(zbus::names::BusName::Unique(bus_name.clone().into())); - if let Err(err) = FileTransfer::transfer_closed(&signal_emitter, key).await { - error!(?err, %key, "could not forward signal"); - } - } else { - error!(%key, "got a signal for unknown key"); - } - } else { - error!("could not deserialize transfer closed signal"); - }; - } - } - } - } -} diff --git a/sidebus-broker/src/portal/mod.rs b/sidebus-broker/src/portal/mod.rs index d43de89..69aa6be 100644 --- a/sidebus-broker/src/portal/mod.rs +++ b/sidebus-broker/src/portal/mod.rs @@ -1,7 +1,3 @@ pub mod documents; pub mod file_chooser; -pub mod file_transfer; -pub mod notification; -pub mod print; pub mod request; -pub mod settings; diff --git a/sidebus-broker/src/portal/notification.rs b/sidebus-broker/src/portal/notification.rs deleted file mode 100644 index 0d41850..0000000 --- a/sidebus-broker/src/portal/notification.rs +++ /dev/null @@ -1,95 +0,0 @@ -use std::collections::HashMap; - -use tokio_stream::StreamExt; -use tracing::warn; -use zbus::{Connection, fdo::Result, names::UniqueName, object_server::SignalEmitter, zvariant}; - -#[derive(Clone)] -pub struct Notification { - host: NotificationProxy<'static>, -} - -#[zbus::interface( - name = "org.freedesktop.portal.Notification", - proxy( - default_service = "org.freedesktop.portal.Desktop", - default_path = "/org/freedesktop/portal/desktop" - ) -)] -impl Notification { - async fn add_notification( - &self, - #[zbus(header)] hdr: zbus::message::Header<'_>, - id: &str, - notification: HashMap<&str, zvariant::Value<'_>>, - ) -> Result<()> { - let sender = hdr.sender().ok_or_else(|| zbus::Error::MissingField)?; - self.host - .add_notification( - &format!("{sender}\x0C\x0CSIDEBUS\x0C\x0C{id}"), - notification, - ) - .await - } - - async fn remove_notification( - &self, - #[zbus(header)] hdr: zbus::message::Header<'_>, - id: &str, - ) -> Result<()> { - let sender = hdr.sender().ok_or_else(|| zbus::Error::MissingField)?; - self.host - .remove_notification(&format!("{sender}\x0C\x0CSIDEBUS\x0C\x0C{id}")) - .await - } - - #[zbus(signal)] - async fn action_invoked( - signal_emitter: &SignalEmitter<'_>, - id: &str, - action: &str, - parameter: Vec>, - ) -> zbus::Result<()>; - - #[zbus(property)] - async fn supported_options(&self) -> Result> { - self.host - .supported_options() - .await - .map_err(|err| err.into()) - } - - #[zbus(property, name = "version")] - fn version(&self) -> Result { - Ok(2) - } -} - -impl Notification { - pub async fn new(host_session_conn: &Connection) -> Result { - let host = NotificationProxy::builder(host_session_conn) - .build() - .await?; - Ok(Self { host }) - } - - pub async fn forward_actions(&self, mut signal_emitter: SignalEmitter<'static>) -> Result<()> { - let mut stream = self.host.receive_action_invoked().await?; - while let Some(x) = stream.next().await { - let args = x.args()?; - let mut split = args.id.split("\x0C\x0CSIDEBUS\x0C\x0C"); - let sender = split - .next() - .and_then(|x| UniqueName::try_from(x).ok().map(|x| x.to_owned())) - .ok_or_else(|| zbus::fdo::Error::Failed("bad ID".to_owned()))?; - let id = split - .next() - .ok_or_else(|| zbus::fdo::Error::Failed("bad ID".to_owned()))?; - signal_emitter = signal_emitter.set_destination(sender.into()); - Notification::action_invoked(&signal_emitter, id, args.action, args.parameter).await?; - () - } - warn!("actions stream end"); - Ok(()) - } -} diff --git a/sidebus-broker/src/portal/print.rs b/sidebus-broker/src/portal/print.rs deleted file mode 100644 index 7c77881..0000000 --- a/sidebus-broker/src/portal/print.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::collections::HashMap; - -use zbus::{Connection, ObjectServer, fdo::Result, zvariant}; - -use super::request::ReqHandler; - -#[derive(Clone)] -pub struct Print { - host: PrintProxy<'static>, -} - -#[zbus::interface( - name = "org.freedesktop.portal.Print", - proxy( - default_service = "org.freedesktop.portal.Desktop", - default_path = "/org/freedesktop/portal/desktop" - ) -)] -impl Print { - async fn prepare_print( - &self, - #[zbus(header)] hdr: zbus::message::Header<'_>, - #[zbus(object_server)] server: &ObjectServer, - #[zbus(connection)] conn: &Connection, - parent_window: &str, - title: &str, - settings: HashMap<&str, zvariant::Value<'_>>, - page_setup: HashMap<&str, zvariant::Value<'_>>, - options: HashMap<&str, zvariant::Value<'_>>, - ) -> Result { - ReqHandler::prepare(&self.host, hdr, server, conn, &options) - .perform(async || { - self.host - .prepare_print(parent_window, title, settings, page_setup, options) - .await - }) - .await - } - - async fn print( - &self, - #[zbus(header)] hdr: zbus::message::Header<'_>, - #[zbus(object_server)] server: &ObjectServer, - #[zbus(connection)] conn: &Connection, - parent_window: &str, - title: &str, - fd: zvariant::Fd<'_>, - options: HashMap<&str, zvariant::Value<'_>>, - ) -> Result { - ReqHandler::prepare(&self.host, hdr, server, conn, &options) - .perform(async || self.host.print(parent_window, title, fd, options).await) - .await - } - - #[zbus(property, name = "version")] - fn version(&self) -> Result { - Ok(3) - } -} - -impl Print { - pub async fn new(host_session_conn: &Connection) -> Result { - let host = PrintProxy::builder(host_session_conn).build().await?; - Ok(Self { host }) - } -} diff --git a/sidebus-broker/src/portal/settings.rs b/sidebus-broker/src/portal/settings.rs deleted file mode 100644 index de03b8b..0000000 --- a/sidebus-broker/src/portal/settings.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::collections::HashMap; - -use tokio_stream::StreamExt; -use tracing::warn; -use zbus::{Connection, fdo::Result, object_server::SignalEmitter, zvariant}; - -#[derive(Clone)] -pub struct Settings { - host: SettingsProxy<'static>, -} - -#[zbus::interface( - name = "org.freedesktop.portal.Settings", - proxy( - default_service = "org.freedesktop.portal.Desktop", - default_path = "/org/freedesktop/portal/desktop" - ) -)] -impl Settings { - async fn read(&self, namespace: &str, key: &str) -> Result { - self.host.read(namespace, key).await - } - - async fn read_all( - &self, - namespaces: Vec<&str>, - ) -> Result>> { - self.host.read_all(namespaces).await - } - - async fn read_one(&self, namespace: &str, key: &str) -> Result { - self.host.read_one(namespace, key).await - } - - /// SettingChanged signal - #[zbus(signal)] - async fn setting_changed( - signal_emitter: &SignalEmitter<'_>, - namespace: &str, - key: &str, - value: zvariant::Value<'_>, - ) -> zbus::Result<()>; - - #[zbus(property, name = "version")] - async fn version(&self) -> Result { - Ok(2) - } -} - -impl Settings { - pub(crate) async fn new(host_session_conn: &Connection) -> Result { - let host = SettingsProxy::builder(host_session_conn).build().await?; - Ok(Self { host }) - } - - pub async fn forward_changes(&self, signal_emitter: &SignalEmitter<'static>) -> Result<()> { - let mut stream = self.host.receive_setting_changed().await?; - while let Some(x) = stream.next().await { - let args = x.args()?; - Settings::setting_changed(signal_emitter, args.namespace, args.key, args.value).await?; - () - } - warn!("settings change stream end"); - Ok(()) - } -} diff --git a/sidebus-broker/src/vsock.rs b/sidebus-broker/src/vsock.rs index 23d6c54..f3524a0 100644 --- a/sidebus-broker/src/vsock.rs +++ b/sidebus-broker/src/vsock.rs @@ -13,11 +13,12 @@ impl ConnectionBuilder { &self.remote_addr } - pub async fn build<'a>(self) -> eyre::Result { + pub async fn build<'a>(self, guid: zbus::Guid<'a>) -> eyre::Result { zbus::connection::Builder::vsock_stream(self.socket) + .server(guid) + .unwrap() + .p2p() .auth_mechanism(zbus::AuthMechanism::Anonymous) - .name("org.freedesktop.portal.Desktop")? - .name("org.freedesktop.portal.Documents")? .build() .await .map_err(|e| e.into())