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
6use super::{Error, ffi, Message, MessageType};
7use crate::strings::{BusName, Path, Member, Interface};
8use crate::arg::{AppendAll, ReadAll, IterAppend};
9use crate::message::SignalArgs;
10
11pub mod stdintf;
12
13mod connection;
14
15pub 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)]
21pub 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
32impl<'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.
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.
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.
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 /// ```
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.
78pub type MessageCallback = Box<dyn FnMut(&Connection, Message) -> bool + 'static>;
79
80pub use crate::ffi::DBusRequestNameReply as RequestNameReply;
81pub use crate::ffi::DBusReleaseNameReply as ReleaseNameReply;
82pub use crate::ffi::DBusBusType as BusType;
83
84mod watch;
85
86pub use self::watch::{Watch, WatchEvent};
87use 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.
94pub 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
103impl NameFlag {
104 /// u32 value of flag.
105 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)]
111pub 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
122impl From<Message> for ConnectionItem {
123 fn from(m: Message) -> Self {
124 let mtype: MessageType = 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.
142pub 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
151impl MsgHandlerType {
152 fn matches_msg(&self, m: &Message) -> bool {
153 match *self {
154 MsgHandlerType::All => true,
155 MsgHandlerType::MsgType(t: MessageType) => m.msg_type() == t,
156 MsgHandlerType::Reply(serial: u32) => {
157 let t: MessageType = 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.
165pub 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.
169 fn handler_type(&self) -> MsgHandlerType;
170
171 /// Function to be called if the message matches the MsgHandlerType
172 fn handle_msg(&mut self, _msg: &Message) -> Option<MsgHandlerResult> { None }
173}
174
175/// The result from MsgHandler::handle.
176#[derive(Debug, Default)]
177pub 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
187type 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`.
192pub struct MessageReply<F>(Option<F>, u32);
193
194impl<'a, F: FnOnce(Result<&Message, Error>) + 'a> MsgHandler for MessageReply<F> {
195 fn handler_type(&self) -> MsgHandlerType { MsgHandlerType::Reply(self.1) }
196 fn handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult> {
197 let e: Result<&Message, Error> = 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)]
209mod test {
210 use super::{Connection, BusType, ConnectionItem, NameFlag,
211 RequestNameReply, ReleaseNameReply};
212 use crate::Message;
213
214 #[test]
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]
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]
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]
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]
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]
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