1 //! A connection that uses FFI callbacks to dispatch messages. 2 //! 3 //! This is the legacy design used up to 0.6.x. It is not recommended for new development. 4 5 6 use super::{Error, ffi, Message, MessageType}; 7 use crate::strings::{BusName, Path, Member, Interface}; 8 use crate::arg::{AppendAll, ReadAll, IterAppend}; 9 use crate::message::SignalArgs; 10 11 pub mod stdintf; 12 13 mod connection; 14 15 pub use connection::{Connection, ConnMsgs}; 16 17 /// A convenience struct that wraps connection, destination and path. 18 /// 19 /// Useful if you want to make many method calls to the same destination path. 20 #[derive(Clone, Debug)] 21 pub struct ConnPath<'a, C> { 22 /// Some way to access the connection, e g a &Connection or Rc<Connection> 23 pub conn: C, 24 /// Destination, i e what D-Bus service you're communicating with 25 pub dest: BusName<'a>, 26 /// Object path on the destination 27 pub path: Path<'a>, 28 /// Timeout in milliseconds for blocking method calls 29 pub timeout: i32, 30 } 31 32 impl<'a, C: ::std::ops::Deref<Target=Connection>> ConnPath<'a, C> { 33 /// Make a D-Bus method call, where you can append arguments inside the closure. method_call_with_args<F: FnOnce(&mut Message)>(&self, i: &Interface, m: &Member, f: F) -> Result<Message, Error>34 pub fn method_call_with_args<F: FnOnce(&mut Message)>(&self, i: &Interface, m: &Member, f: F) -> Result<Message, Error> { 35 let mut msg = Message::method_call(&self.dest, &self.path, i, m); 36 f(&mut msg); 37 self.conn.send_with_reply_and_block(msg, self.timeout) 38 } 39 40 /// Emit a D-Bus signal, where you can append arguments inside the closure. signal_with_args<F: FnOnce(&mut Message)>(&self, i: &Interface, m: &Member, f: F) -> Result<u32, Error>41 pub fn signal_with_args<F: FnOnce(&mut Message)>(&self, i: &Interface, m: &Member, f: F) -> Result<u32, Error> { 42 let mut msg = Message::signal(&self.path, i, m); 43 f(&mut msg); 44 self.conn.send(msg).map_err(|_| Error::new_failed("Sending signal failed")) 45 } 46 47 /// Emit a D-Bus signal, where the arguments are in a struct. emit<S: SignalArgs + AppendAll>(&self, signal: &S) -> Result<u32, Error>48 pub fn emit<S: SignalArgs + AppendAll>(&self, signal: &S) -> Result<u32, Error> { 49 let msg = signal.to_emit_message(&self.path); 50 self.conn.send(msg).map_err(|_| Error::new_failed("Sending signal failed")) 51 } 52 53 /// Make a method call using typed input and output arguments. 54 /// 55 /// # Example 56 /// 57 /// ``` 58 /// use dbus::ffidisp::{Connection, BusType}; 59 /// 60 /// let conn = Connection::get_private(BusType::Session)?; 61 /// let dest = conn.with_path("org.freedesktop.DBus", "/", 5000); 62 /// let (has_owner,): (bool,) = dest.method_call("org.freedesktop.DBus", "NameHasOwner", ("dummy.name.without.owner",))?; 63 /// assert_eq!(has_owner, false); 64 /// # Ok::<(), Box<dyn std::error::Error>>(()) 65 /// ``` method_call<'i, 'm, R: ReadAll, A: AppendAll, I: Into<Interface<'i>>, M: Into<Member<'m>>>(&self, i: I, m: M, args: A) -> Result<R, Error>66 pub fn method_call<'i, 'm, R: ReadAll, A: AppendAll, I: Into<Interface<'i>>, M: Into<Member<'m>>>(&self, i: I, m: M, args: A) -> Result<R, Error> { 67 let mut r = self.method_call_with_args(&i.into(), &m.into(), |mut msg| { 68 args.append(&mut IterAppend::new(&mut msg)); 69 })?; 70 r.as_result()?; 71 Ok(R::read(&mut r.iter_init())?) 72 } 73 } 74 75 /// The type of function to use for replacing the message callback. 76 /// 77 /// See the documentation for Connection::replace_message_callback for more information. 78 pub type MessageCallback = Box<dyn FnMut(&Connection, Message) -> bool + 'static>; 79 80 pub use crate::ffi::DBusRequestNameReply as RequestNameReply; 81 pub use crate::ffi::DBusReleaseNameReply as ReleaseNameReply; 82 pub use crate::ffi::DBusBusType as BusType; 83 84 mod watch; 85 86 pub use self::watch::{Watch, WatchEvent}; 87 use watch::WatchList; 88 89 #[repr(C)] 90 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] 91 /// Flags to use for Connection::register_name. 92 /// 93 /// More than one flag can be specified, if so just add their values. 94 pub enum NameFlag { 95 /// Allow another service to become the primary owner if requested 96 AllowReplacement = ffi::DBUS_NAME_FLAG_ALLOW_REPLACEMENT as isize, 97 /// Request to replace the current primary owner 98 ReplaceExisting = ffi::DBUS_NAME_FLAG_REPLACE_EXISTING as isize, 99 /// If we can not become the primary owner do not place us in the queue 100 DoNotQueue = ffi::DBUS_NAME_FLAG_DO_NOT_QUEUE as isize, 101 } 102 103 impl NameFlag { 104 /// u32 value of flag. value(self) -> u32105 pub fn value(self) -> u32 { self as u32 } 106 } 107 108 /// When listening for incoming events on the D-Bus, this enum will tell you what type 109 /// of incoming event has happened. 110 #[derive(Debug)] 111 pub enum ConnectionItem { 112 /// No event between now and timeout 113 Nothing, 114 /// Incoming method call 115 MethodCall(Message), 116 /// Incoming signal 117 Signal(Message), 118 /// Incoming method return, including method return errors (mostly used for Async I/O) 119 MethodReturn(Message), 120 } 121 122 impl From<Message> for ConnectionItem { from(m: Message) -> Self123 fn from(m: Message) -> Self { 124 let mtype = m.msg_type(); 125 match mtype { 126 MessageType::Signal => ConnectionItem::Signal(m), 127 MessageType::MethodReturn => ConnectionItem::MethodReturn(m), 128 MessageType::Error => ConnectionItem::MethodReturn(m), 129 MessageType::MethodCall => ConnectionItem::MethodCall(m), 130 } 131 } 132 } 133 134 135 136 137 #[derive(Clone, Debug)] 138 /// Type of messages to be handled by a MsgHandler. 139 /// 140 /// Note: More variants can be added in the future; but unless you're writing your own D-Bus engine 141 /// you should not have to match on these anyway. 142 pub enum MsgHandlerType { 143 /// Handle all messages 144 All, 145 /// Handle only messages of a specific type 146 MsgType(MessageType), 147 /// Handle only method replies with this serial number 148 Reply(u32), 149 } 150 151 impl MsgHandlerType { matches_msg(&self, m: &Message) -> bool152 fn matches_msg(&self, m: &Message) -> bool { 153 match *self { 154 MsgHandlerType::All => true, 155 MsgHandlerType::MsgType(t) => m.msg_type() == t, 156 MsgHandlerType::Reply(serial) => { 157 let t = m.msg_type(); 158 ((t == MessageType::MethodReturn) || (t == MessageType::Error)) && (m.get_reply_serial() == Some(serial)) 159 } 160 } 161 } 162 } 163 164 /// A trait for handling incoming messages. 165 pub trait MsgHandler { 166 /// Type of messages for which the handler will be called 167 /// 168 /// Note: The return value of this function might be cached, so it must return the same value all the time. handler_type(&self) -> MsgHandlerType169 fn handler_type(&self) -> MsgHandlerType; 170 171 /// Function to be called if the message matches the MsgHandlerType handle_msg(&mut self, _msg: &Message) -> Option<MsgHandlerResult>172 fn handle_msg(&mut self, _msg: &Message) -> Option<MsgHandlerResult> { None } 173 } 174 175 /// The result from MsgHandler::handle. 176 #[derive(Debug, Default)] 177 pub struct MsgHandlerResult { 178 /// Indicates that the message has been dealt with and should not be processed further. 179 pub handled: bool, 180 /// Indicates that this MsgHandler no longer wants to receive messages and should be removed. 181 pub done: bool, 182 /// Messages to send (e g, a reply to a method call) 183 pub reply: Vec<Message>, 184 } 185 186 187 type MsgHandlerList = Vec<Box<dyn MsgHandler>>; 188 189 /// The struct returned from `Connection::send_and_reply`. 190 /// 191 /// It implements the `MsgHandler` trait so you can use `Connection::add_handler`. 192 pub struct MessageReply<F>(Option<F>, u32); 193 194 impl<'a, F: FnOnce(Result<&Message, Error>) + 'a> MsgHandler for MessageReply<F> { handler_type(&self) -> MsgHandlerType195 fn handler_type(&self) -> MsgHandlerType { MsgHandlerType::Reply(self.1) } handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult>196 fn handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult> { 197 let e = match msg.msg_type() { 198 MessageType::MethodReturn => Ok(msg), 199 MessageType::Error => Err(msg.set_error_from_msg().unwrap_err()), 200 _ => unreachable!(), 201 }; 202 debug_assert_eq!(msg.get_reply_serial(), Some(self.1)); 203 self.0.take().unwrap()(e); 204 return Some(MsgHandlerResult { handled: true, done: true, reply: Vec::new() }) 205 } 206 } 207 208 #[cfg(test)] 209 mod test { 210 use super::{Connection, BusType, ConnectionItem, NameFlag, 211 RequestNameReply, ReleaseNameReply}; 212 use crate::Message; 213 214 #[test] connection()215 fn connection() { 216 let c = Connection::get_private(BusType::Session).unwrap(); 217 let n = c.unique_name(); 218 assert!(n.starts_with(":1.")); 219 println!("Connected to DBus, unique name: {}", n); 220 } 221 222 #[test] invalid_message()223 fn invalid_message() { 224 let c = Connection::get_private(BusType::Session).unwrap(); 225 let m = Message::new_method_call("foo.bar", "/", "foo.bar", "FooBar").unwrap(); 226 let e = c.send_with_reply_and_block(m, 2000).err().unwrap(); 227 assert!(e.name().unwrap() == "org.freedesktop.DBus.Error.ServiceUnknown"); 228 } 229 230 #[test] object_path()231 fn object_path() { 232 use std::sync::mpsc; 233 let (tx, rx) = mpsc::channel(); 234 let thread = ::std::thread::spawn(move || { 235 let c = Connection::get_private(BusType::Session).unwrap(); 236 c.register_object_path("/hello").unwrap(); 237 // println!("Waiting..."); 238 tx.send(c.unique_name()).unwrap(); 239 for n in c.iter(1000) { 240 // println!("Found message... ({})", n); 241 match n { 242 ConnectionItem::MethodCall(ref m) => { 243 let reply = Message::new_method_return(m).unwrap(); 244 c.send(reply).unwrap(); 245 break; 246 } 247 _ => {} 248 } 249 } 250 c.unregister_object_path("/hello"); 251 }); 252 253 let c = Connection::get_private(BusType::Session).unwrap(); 254 let n = rx.recv().unwrap(); 255 let m = Message::new_method_call(&n, "/hello", "com.example.hello", "Hello").unwrap(); 256 println!("Sending..."); 257 let r = c.send_with_reply_and_block(m, 8000).unwrap(); 258 let reply = r.get_items(); 259 println!("{:?}", reply); 260 thread.join().unwrap(); 261 262 } 263 264 #[test] register_name()265 fn register_name() { 266 let c = Connection::get_private(BusType::Session).unwrap(); 267 let n = format!("com.example.hello.test.register_name"); 268 assert_eq!(c.register_name(&n, NameFlag::ReplaceExisting as u32).unwrap(), RequestNameReply::PrimaryOwner); 269 assert_eq!(c.release_name(&n).unwrap(), ReleaseNameReply::Released); 270 } 271 272 #[test] signal()273 fn signal() { 274 let c = Connection::get_private(BusType::Session).unwrap(); 275 let iface = "com.example.signaltest"; 276 let mstr = format!("interface='{}',member='ThisIsASignal'", iface); 277 c.add_match(&mstr).unwrap(); 278 let m = Message::new_signal("/mysignal", iface, "ThisIsASignal").unwrap(); 279 let uname = c.unique_name(); 280 c.send(m).unwrap(); 281 for n in c.iter(1000) { 282 match n { 283 ConnectionItem::Signal(s) => { 284 let (p, i, m) = (s.path(), s.interface(), s.member()); 285 match (&*p.unwrap(), &*i.unwrap(), &*m.unwrap()) { 286 ("/mysignal", "com.example.signaltest", "ThisIsASignal") => { 287 assert_eq!(&*s.sender().unwrap(), &*uname); 288 break; 289 }, 290 (_, _, _) => println!("Other signal: {:?}", s), 291 } 292 } 293 _ => {}, 294 } 295 } 296 c.remove_match(&mstr).unwrap(); 297 } 298 299 300 #[test] watch()301 fn watch() { 302 let c = Connection::get_private(BusType::Session).unwrap(); 303 let d = c.watch_fds(); 304 assert!(d.len() > 0); 305 println!("Fds to watch: {:?}", d); 306 } 307 } 308