async_rustbus/conn/
addr.rs1use std::collections::HashMap;
2use std::ffi::OsStr;
3use std::os::unix::ffi::{OsStrExt, OsStringExt};
4
5use std::io::ErrorKind;
6use std::path::{Path, PathBuf};
7use tokio::net::ToSocketAddrs;
8
9pub const DBUS_SYS_PATH: &str = "/run/dbus/system_bus_socket";
11pub const DBUS_SESS_ENV: &str = "DBUS_SESSION_BUS_ADDRESS";
13
14pub enum DBusAddr<P: AsRef<Path>, S: ToSocketAddrs, B: AsRef<[u8]>> {
18 Path(P),
19 Tcp(S),
20 #[cfg(target_os = "linux")]
21 Abstract(B),
22}
23impl<P: AsRef<Path>> DBusAddr<P, &str, [u8; 0]> {
25 pub fn unix_path(path: P) -> Self {
26 Self::Path(path)
27 }
28}
29
30impl<S: ToSocketAddrs> DBusAddr<&str, S, [u8; 0]> {
32 pub fn tcp_addr(s: S) -> Self {
33 Self::Tcp(s)
34 }
35}
36
37#[cfg(target_os = "linux")]
39impl<B: AsRef<[u8]>> DBusAddr<&str, &str, B> {
40 pub fn unx_abstract(b: B) -> Self {
41 Self::Abstract(b)
42 }
43}
44
45pub async fn get_system_bus_addr() -> std::io::Result<DBusAddr<&'static Path, &'static str, [u8; 0]>>
47{
48 let path = Path::new(DBUS_SYS_PATH);
49 if path.exists() {
50 Ok(DBusAddr::Path(path))
51 } else {
52 Err(std::io::Error::new(
53 ErrorKind::NotFound,
54 "Could not find system bus.",
55 ))
56 }
57}
58
59const BAD_SESSION_ERR_MSG: &str = "Invalid session bus address in environment.";
60fn default_session_err() -> std::io::Error {
61 std::io::Error::new(ErrorKind::InvalidData, BAD_SESSION_ERR_MSG)
62}
63pub async fn get_session_bus_addr() -> std::io::Result<DBusAddr<PathBuf, String, Vec<u8>>> {
65 let bytes = std::env::var_os(DBUS_SESS_ENV)
66 .ok_or_else(|| std::io::Error::new(ErrorKind::NotFound, "No DBus session in environment."))?
67 .into_vec();
68 let mut iter = bytes.split(|b| *b == b':');
69 let family = iter.next().unwrap();
70 if family.len() == bytes.len() {
71 return Err(default_session_err());
72 }
73 let data = &bytes[family.len() + 1..];
74 let data_pairs: HashMap<&[u8], &[u8]> = data
75 .split(|b| *b == b',')
76 .filter_map(|pair| {
77 let mut split = pair.split(|b| *b == b'=');
78 let name = split.next().unwrap();
79 let data = split.next()?;
80 match split.next() {
81 Some(_) => None,
82 None => Some((name, data)),
83 }
84 })
85 .collect();
86 match family {
87 b"unix" => {
88 #[cfg(target_os = "linux")]
89 {
90 if let Some(abs) = data_pairs.get(&b"abstract"[..]) {
91 return Ok(DBusAddr::Abstract((*abs).to_owned()));
93 }
94 }
95 if let Some(path) = data_pairs.get(&b"path"[..]) {
96 let path: &Path = OsStr::from_bytes(path).as_ref();
97 return if path.exists() {
98 Ok(DBusAddr::Path(path.to_path_buf()))
99 } else {
100 Err(std::io::Error::new(
101 ErrorKind::NotFound,
102 format!("Could not find session bus at {:?}.", path),
103 ))
104 };
105 }
106 Err(default_session_err())
107 }
108 b"tcp" => {
109 let addr = || {
110 let host_data = data_pairs.get(&b"host"[..])?;
111 let mut host_str = std::str::from_utf8(host_data).ok()?.to_string();
112 let port_data = data_pairs.get(&b"port"[..])?;
113 let port_str = std::str::from_utf8(port_data).ok()?;
114 host_str.push(':');
115 host_str.push_str(port_str);
116 Some(host_str)
117 };
118 let addr = addr().ok_or_else(default_session_err)?;
119 Ok(DBusAddr::Tcp(addr))
120 }
121 _ => Err(default_session_err()),
122 }
123}