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