From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- third_party/rust/dbus/src/connection2.rs | 214 +++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 third_party/rust/dbus/src/connection2.rs (limited to 'third_party/rust/dbus/src/connection2.rs') diff --git a/third_party/rust/dbus/src/connection2.rs b/third_party/rust/dbus/src/connection2.rs new file mode 100644 index 0000000000..e318e921ee --- /dev/null +++ b/third_party/rust/dbus/src/connection2.rs @@ -0,0 +1,214 @@ +use crate::{BusType, Error, Message, to_c_str, Watch}; +use std::{ptr, str}; +use std::ffi::CStr; +use std::os::raw::{c_void}; + +#[derive(Debug)] +pub struct ConnHandle(*mut ffi::DBusConnection); + +unsafe impl Send for ConnHandle {} +unsafe impl Sync for ConnHandle {} + +impl Drop for ConnHandle { + fn drop(&mut self) { + unsafe { + ffi::dbus_connection_close(self.0); + ffi::dbus_connection_unref(self.0); + } + } +} + +/// Experimental rewrite of Connection [unstable / experimental] +/// +/// Slightly lower level, with better support for async operations. +/// Also, this struct is Send + Sync. +/// +/// Blocking operations should be clearly marked as such, although if you +/// try to access the connection from several threads at the same time, +/// blocking might occur due to an internal mutex inside the dbus library. +/// +/// This version avoids dbus_connection_dispatch, and thus avoids +/// callbacks from that function. Instead the same functionality needs to be +/// implemented by these bindings somehow - this is not done yet. +#[derive(Debug)] +pub struct TxRx { + handle: ConnHandle, +} + +impl TxRx { + #[inline(always)] + pub (crate) fn conn(&self) -> *mut ffi::DBusConnection { + self.handle.0 + } + + fn conn_from_ptr(ptr: *mut ffi::DBusConnection) -> Result { + let handle = ConnHandle(ptr); + + /* No, we don't want our app to suddenly quit if dbus goes down */ + unsafe { ffi::dbus_connection_set_exit_on_disconnect(ptr, 0) }; + + let c = TxRx { handle }; + + Ok(c) + } + + + /// Creates a new D-Bus connection. + /// + /// Blocking: until the connection is up and running. + pub fn get_private(bus: BusType) -> Result { + let mut e = Error::empty(); + let conn = unsafe { ffi::dbus_bus_get_private(bus, e.get_mut()) }; + if conn == ptr::null_mut() { + return Err(e) + } + Self::conn_from_ptr(conn) + } + + /// Creates a new D-Bus connection to a remote address. + /// + /// Note: for all common cases (System / Session bus) you probably want "get_private" instead. + /// + /// Blocking: until the connection is established. + pub fn open_private(address: &str) -> Result { + let mut e = Error::empty(); + let conn = unsafe { ffi::dbus_connection_open_private(to_c_str(address).as_ptr(), e.get_mut()) }; + if conn == ptr::null_mut() { + return Err(e) + } + Self::conn_from_ptr(conn) + } + + /// Registers a new D-Bus connection with the bus. + /// + /// Note: `get_private` does this automatically, useful with `open_private` + /// + /// Blocking: until a "Hello" response is received from the server. + pub fn register(&mut self) -> Result<(), Error> { + // This function needs to take &mut self, because it changes unique_name and unique_name takes a &self + let mut e = Error::empty(); + if unsafe { ffi::dbus_bus_register(self.conn(), e.get_mut()) == 0 } { + Err(e) + } else { + Ok(()) + } + } + + /// Gets whether the connection is currently open. + pub fn is_connected(&self) -> bool { + unsafe { ffi::dbus_connection_get_is_connected(self.conn()) != 0 } + } + + /// Get the connection's unique name. + /// + /// It's usually something like ":1.54" + pub fn unique_name(&self) -> Option<&str> { + let c = unsafe { ffi::dbus_bus_get_unique_name(self.conn()) }; + if c == ptr::null_mut() { return None; } + let s = unsafe { CStr::from_ptr(c) }; + str::from_utf8(s.to_bytes()).ok() + } + + + /// Puts a message into libdbus out queue. Use "flush" or "read_write" to make sure it is sent over the wire. + /// + /// Returns a serial number than can be used to match against a reply. + pub fn send(&self, msg: Message) -> Result { + let mut serial = 0u32; + let r = unsafe { ffi::dbus_connection_send(self.conn(), msg.ptr(), &mut serial) }; + if r == 0 { return Err(()); } + Ok(serial) + } + + /// Flush the queue of outgoing messages. + /// + /// Blocking: until the outgoing queue is empty. + pub fn flush(&self) { unsafe { ffi::dbus_connection_flush(self.conn()) } } + + /// Read and write to the connection. + /// + /// Incoming messages are put in the internal queue, outgoing messages are written. + /// + /// Blocking: If there are no messages, for up to timeout_ms milliseconds, or forever if timeout_ms is None. + /// For non-blocking behaviour, set timeout_ms to Some(0). + pub fn read_write(&self, timeout_ms: Option) -> Result<(), ()> { + let t = timeout_ms.unwrap_or(-1); + if unsafe { ffi::dbus_connection_read_write(self.conn(), t) == 0 } { + Err(()) + } else { + Ok(()) + } + } + + /// Removes a message from the incoming queue, or returns None if the queue is empty. + /// + /// Use "read_write" first, so that messages are put into the incoming queue. + /// For unhandled messages, please call MessageDispatcher::default_dispatch to return + /// default replies for method calls. + pub fn pop_message(&self) -> Option { + let mptr = unsafe { ffi::dbus_connection_pop_message(self.conn()) }; + if mptr == ptr::null_mut() { + None + } else { + Some(Message::from_ptr(mptr, false)) + } + } + + /// Get an up-to-date list of file descriptors to watch. + /// + /// Might be changed into something that allows for callbacks when the watch list is changed. + pub fn watch_fds(&mut self) -> Result, ()> { + extern "C" fn add_watch_cb(watch: *mut ffi::DBusWatch, data: *mut c_void) -> u32 { + unsafe { + let wlist: &mut Vec = &mut *(data as *mut _); + wlist.push(Watch::from_raw(watch)); + } + 1 + } + let mut r = vec!(); + if unsafe { ffi::dbus_connection_set_watch_functions(self.conn(), + Some(add_watch_cb), None, None, &mut r as *mut _ as *mut _, None) } == 0 { return Err(()) } + assert!(unsafe { ffi::dbus_connection_set_watch_functions(self.conn(), + None, None, None, ptr::null_mut(), None) } != 0); + Ok(r) + } +} + +#[test] +fn test_txrx_send_sync() { + fn is_send(_: &T) {} + fn is_sync(_: &T) {} + let c = TxRx::get_private(BusType::Session).unwrap(); + is_send(&c); + is_sync(&c); +} + +#[test] +fn txrx_simple_test() { + let mut c = TxRx::get_private(BusType::Session).unwrap(); + assert!(c.is_connected()); + let fds = c.watch_fds().unwrap(); + println!("{:?}", fds); + assert!(fds.len() > 0); + let m = Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames").unwrap(); + let reply = c.send(m).unwrap(); + let my_name = c.unique_name().unwrap(); + loop { + while let Some(mut msg) = c.pop_message() { + println!("{:?}", msg); + if msg.get_reply_serial() == Some(reply) { + let r = msg.as_result().unwrap(); + let z: ::arg::Array<&str, _> = r.get1().unwrap(); + for n in z { + println!("{}", n); + if n == my_name { return; } // Hooray, we found ourselves! + } + assert!(false); + } else if let Some(r) = crate::MessageDispatcher::<()>::default_dispatch(&msg) { + c.send(r).unwrap(); + } + } + c.read_write(Some(100)).unwrap(); + } +} + -- cgit v1.2.3