From b02ce9a5f2828db82b74cc75ea308416b6ee70e2 Mon Sep 17 00:00:00 2001 From: Ron Waldon-Howe Date: Sat, 14 Dec 2024 12:17:57 +1100 Subject: [PATCH 1/6] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20Add=20`BusType`=20e?= =?UTF-8?q?num?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'll borrow this from #159 so that we can be clearer about the default address. --- src/config/bus_type.rs | 6 ++++++ src/config/mod.rs | 3 +++ src/lib.rs | 1 + 3 files changed, 10 insertions(+) create mode 100644 src/config/bus_type.rs create mode 100644 src/config/mod.rs diff --git a/src/config/bus_type.rs b/src/config/bus_type.rs new file mode 100644 index 0000000..c48f7d3 --- /dev/null +++ b/src/config/bus_type.rs @@ -0,0 +1,6 @@ +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub enum BusType { + #[default] + Session, + System, +} diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..5d183a7 --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,3 @@ +pub mod bus_type; + +pub use bus_type::BusType; diff --git a/src/lib.rs b/src/lib.rs index 07a5f33..be211b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod bus; +pub mod config; pub mod fdo; pub mod match_rules; pub mod name_registry; From 655afecd8f3507ee99ea62bb9f4286050cc5e4da Mon Sep 17 00:00:00 2001 From: Ron Waldon-Howe Date: Sat, 14 Dec 2024 16:43:59 +1100 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20Implement=20`TryFro?= =?UTF-8?q?m`=20for=20`Address`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'll use this later when we need the default bus address for each type. --- src/config/bus_type.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/config/bus_type.rs b/src/config/bus_type.rs index c48f7d3..1b23d83 100644 --- a/src/config/bus_type.rs +++ b/src/config/bus_type.rs @@ -1,6 +1,43 @@ +#[cfg(unix)] +use std::{env, path::PathBuf}; + +use anyhow::{Error, Result}; +use zbus::Address; + #[derive(Clone, Copy, Debug, Default, PartialEq)] pub enum BusType { #[default] Session, System, } + +impl TryFrom for Address { + type Error = Error; + #[cfg(unix)] + fn try_from(value: BusType) -> Result { + if value == BusType::System { + return Address::try_from("unix:path=/run/dbus/system_bus_socket").map_err(Error::msg); + } + + // BusType::Session + Address::try_from(format!("unix:tmpdir={}", default_session_dir().display()).as_str()) + .map_err(Error::msg) + } + + #[cfg(not(unix))] + fn try_from(_value: BusType) -> Result { + Address::try_from("tcp:host=127.0.0.1,port=4242").map_err(Error::msg) + } +} + +#[cfg(unix)] +fn default_session_dir() -> PathBuf { + env::var("XDG_RUNTIME_DIR") + .map(|s| PathBuf::from(s).to_path_buf()) + .ok() + .unwrap_or_else(|| { + PathBuf::from("/run") + .join("user") + .join(format!("{}", nix::unistd::Uid::current())) + }) +} From 008ab64ae44af57dd2fdf32830a3d8581b36de13 Mon Sep 17 00:00:00 2001 From: Ron Waldon-Howe Date: Sat, 30 Nov 2024 12:09:35 +1100 Subject: [PATCH 3/6] =?UTF-8?q?=F0=9F=94=A7=20Support=20`--session`=20(def?= =?UTF-8?q?ault),=20and=20`--system`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bin/busd.rs | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/bin/busd.rs b/src/bin/busd.rs index fdd1424..5aee66e 100644 --- a/src/bin/busd.rs +++ b/src/bin/busd.rs @@ -3,8 +3,6 @@ extern crate busd; #[cfg(unix)] use std::{fs::File, io::Write, os::fd::FromRawFd}; -use busd::bus; - use anyhow::Result; use clap::Parser; #[cfg(unix)] @@ -12,12 +10,16 @@ use tokio::{select, signal::unix::SignalKind}; use tracing::error; #[cfg(unix)] use tracing::{info, warn}; +use zbus::Address; + +use busd::{bus, config::BusType}; /// A simple D-Bus broker. #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args { /// The address to listen on. + /// Takes precedence over any `` element in the configuration file. #[clap(short = 'a', long, value_parser)] address: Option, @@ -36,6 +38,17 @@ struct Args { #[cfg(unix)] #[clap(long)] ready_fd: Option, + + /// Equivalent to `--address unix:tmpdir=$XDG_RUNTIME_DIR` + /// and --config /usr/share/dbus-1/session.conf`. + /// This is the default if `--system` is absent. + #[clap(long)] + session: bool, + + /// Equivalent to `--address unix:path=/run/dbus/system_bus_socket` + /// and `--config /usr/share/dbus-1/system.conf`. + #[clap(long)] + system: bool, } #[tokio::main] @@ -44,7 +57,21 @@ async fn main() -> Result<()> { let args = Args::parse(); - let mut bus = bus::Bus::for_address(args.address.as_deref()).await?; + // TODO: when we have `Config` from #159, prefer `config.r#type` before `BusType::default()` + let bus_type = if args.system { + BusType::System + } else { + BusType::default() + }; + + // TODO: when we have `Config` from #159, prefer `config.listen` before `try_from(bus_type)` + let address = if let Some(address) = args.address { + Address::try_from(address.as_str())? + } else { + Address::try_from(bus_type)? + }; + + let mut bus = bus::Bus::for_address(Some(&format!("{address}"))).await?; #[cfg(unix)] if let Some(fd) = args.ready_fd { From f004d14b098268f670f845d9c623e37972141e84 Mon Sep 17 00:00:00 2001 From: Ron Waldon-Howe Date: Sat, 14 Dec 2024 17:00:13 +1100 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=94=A5=20Remove=20`default=5Faddress(?= =?UTF-8?q?)`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can rely on `TryFrom for Address` to produce the default address for `--session` and `--system`. --- src/bin/busd.rs | 2 +- src/bus/mod.rs | 29 ++--------------------------- tests/fdo.rs | 2 +- tests/greet.rs | 2 +- tests/monitor.rs | 2 +- tests/multiple_conns.rs | 2 +- 6 files changed, 7 insertions(+), 32 deletions(-) diff --git a/src/bin/busd.rs b/src/bin/busd.rs index 5aee66e..bca2a9a 100644 --- a/src/bin/busd.rs +++ b/src/bin/busd.rs @@ -71,7 +71,7 @@ async fn main() -> Result<()> { Address::try_from(bus_type)? }; - let mut bus = bus::Bus::for_address(Some(&format!("{address}"))).await?; + let mut bus = bus::Bus::for_address(&format!("{address}")).await?; #[cfg(unix)] if let Some(fd) = args.ready_fd { diff --git a/src/bus/mod.rs b/src/bus/mod.rs index fc686dd..958f725 100644 --- a/src/bus/mod.rs +++ b/src/bus/mod.rs @@ -1,6 +1,4 @@ use anyhow::{bail, Ok, Result}; -#[cfg(unix)] -use std::{env, path::Path}; use std::{str::FromStr, sync::Arc}; #[cfg(unix)] use tokio::fs::remove_file; @@ -45,11 +43,8 @@ enum Listener { } impl Bus { - pub async fn for_address(address: Option<&str>) -> Result { - let mut address = match address { - Some(address) => Address::from_str(address)?, - None => Address::from_str(&default_address())?, - }; + pub async fn for_address(address: &str) -> Result { + let mut address = Address::from_str(address)?; let guid: OwnedGuid = match address.guid() { Some(guid) => guid.to_owned().into(), None => { @@ -246,23 +241,3 @@ impl Bus { self.inner.next_id } } - -#[cfg(unix)] -fn default_address() -> String { - let runtime_dir = env::var("XDG_RUNTIME_DIR") - .as_ref() - .map(|s| Path::new(s).to_path_buf()) - .ok() - .unwrap_or_else(|| { - Path::new("/run") - .join("user") - .join(format!("{}", nix::unistd::Uid::current())) - }); - - format!("unix:dir={}", runtime_dir.display()) -} - -#[cfg(not(unix))] -fn default_address() -> String { - "tcp:host=127.0.0.1,port=4242".to_string() -} diff --git a/tests/fdo.rs b/tests/fdo.rs index 332b44c..55542d4 100644 --- a/tests/fdo.rs +++ b/tests/fdo.rs @@ -40,7 +40,7 @@ async fn name_ownership_changes() { } async fn name_ownership_changes_(address: &str) { - let mut bus = Bus::for_address(Some(address)).await.unwrap(); + let mut bus = Bus::for_address(address).await.unwrap(); let (tx, rx) = tokio::sync::oneshot::channel(); let handle = tokio::spawn(async move { diff --git a/tests/greet.rs b/tests/greet.rs index 777ecc2..02718b3 100644 --- a/tests/greet.rs +++ b/tests/greet.rs @@ -45,7 +45,7 @@ async fn greet() { } async fn greet_(socket_addr: &str) { - let mut bus = Bus::for_address(Some(socket_addr)).await.unwrap(); + let mut bus = Bus::for_address(socket_addr).await.unwrap(); let (tx, mut rx) = channel(1); let handle = tokio::spawn(async move { diff --git a/tests/monitor.rs b/tests/monitor.rs index 5169a9c..1a5a96e 100644 --- a/tests/monitor.rs +++ b/tests/monitor.rs @@ -20,7 +20,7 @@ async fn become_monitor() { busd::tracing_subscriber::init(); let address = "tcp:host=127.0.0.1,port=4242".to_string(); - let mut bus = Bus::for_address(Some(&address)).await.unwrap(); + let mut bus = Bus::for_address(&address).await.unwrap(); let (tx, rx) = tokio::sync::oneshot::channel(); let handle = tokio::spawn(async move { diff --git a/tests/multiple_conns.rs b/tests/multiple_conns.rs index 4125c96..78a3386 100644 --- a/tests/multiple_conns.rs +++ b/tests/multiple_conns.rs @@ -33,7 +33,7 @@ async fn multi_conenct() { } async fn multi_conenct_(socket_addr: &str) { - let mut bus = Bus::for_address(Some(socket_addr)).await.unwrap(); + let mut bus = Bus::for_address(socket_addr).await.unwrap(); let (tx, rx) = channel(); let handle = tokio::spawn(async move { From 36e3b1a30d3b45169c386d814859b5d4e8b36980 Mon Sep 17 00:00:00 2001 From: Ron Waldon-Howe Date: Sat, 14 Dec 2024 17:07:28 +1100 Subject: [PATCH 5/6] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20`unix=5Faddr?= =?UTF-8?q?()`=20out=20of=20`unix=5Fstream()`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we'd take the `--address` or default address, resolve it into the socket address, and start listening on that address. But we need to be able to expose that address to clients, too. So we break `Bus::unix_stream()` apart giving us a separate `Bus::unix_addr()` and access to the intermediate socket address. --- src/bus/mod.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/bus/mod.rs b/src/bus/mod.rs index 958f725..82c429b 100644 --- a/src/bus/mod.rs +++ b/src/bus/mod.rs @@ -1,5 +1,6 @@ -use anyhow::{bail, Ok, Result}; use std::{str::FromStr, sync::Arc}; + +use anyhow::{bail, Ok, Result}; #[cfg(unix)] use tokio::fs::remove_file; use tokio::spawn; @@ -56,7 +57,11 @@ impl Bus { }; let (listener, auth_mechanism) = match address.transport() { #[cfg(unix)] - Transport::Unix(unix) => (Self::unix_stream(unix).await?, AuthMechanism::External), + Transport::Unix(unix) => { + let addr = Self::unix_addr(unix)?; + + (Self::unix_stream(addr).await?, AuthMechanism::External) + } Transport::Tcp(tcp) => { #[cfg(not(windows))] let auth_mechanism = AuthMechanism::Anonymous; @@ -130,14 +135,10 @@ impl Bus { } #[cfg(unix)] - async fn unix_stream(unix: &Unix) -> Result { - // TODO: Use tokio::net::UnixListener directly once it supports abstract sockets: - // - // https://github.com/tokio-rs/tokio/issues/4610 - + fn unix_addr(unix: &Unix) -> Result { use std::os::unix::net::SocketAddr; - let addr = match unix.path() { + Ok(match unix.path() { #[cfg(target_os = "linux")] UnixSocket::Abstract(name) => { use std::os::linux::net::SocketAddrExt; @@ -170,7 +171,15 @@ impl Bus { addr } _ => bail!("Unsupported address."), - }; + }) + } + + #[cfg(unix)] + async fn unix_stream(addr: std::os::unix::net::SocketAddr) -> Result { + // TODO: Use tokio::net::UnixListener directly once it supports abstract sockets: + // + // https://github.com/tokio-rs/tokio/issues/4610 + let std_listener = tokio::task::spawn_blocking(move || std::os::unix::net::UnixListener::bind_addr(&addr)) .await??; From aa8fa3b2a93b91552c0f1e2361b3daae6787503b Mon Sep 17 00:00:00 2001 From: Ron Waldon-Howe Date: Sat, 14 Dec 2024 17:11:07 +1100 Subject: [PATCH 6/6] =?UTF-8?q?=F0=9F=90=9B=20Expose=20the=20socket=20addr?= =?UTF-8?q?ess=20clients=20can=20use?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now, `--print-address` would print the address specification, that is, the input used to determine how and where the server would listen. This would be useful for clients for `unix:path=...`, but for `unix:dir=...` and `unix:tmpdir=...` this would not work. So now we share the socket address that is produced from the address specification. --- src/bus/mod.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/bus/mod.rs b/src/bus/mod.rs index 82c429b..4810fe8 100644 --- a/src/bus/mod.rs +++ b/src/bus/mod.rs @@ -58,9 +58,16 @@ impl Bus { let (listener, auth_mechanism) = match address.transport() { #[cfg(unix)] Transport::Unix(unix) => { + // resolve address specification into address that clients can use let addr = Self::unix_addr(unix)?; - - (Self::unix_stream(addr).await?, AuthMechanism::External) + address = Address::try_from( + format!("unix:path={}", addr.as_pathname().unwrap().display()).as_str(), + )?; + + ( + Self::unix_stream(addr.clone()).await?, + AuthMechanism::External, + ) } Transport::Tcp(tcp) => { #[cfg(not(windows))]