1 | //! D-Bus Message. |
2 | use std::{fmt, num::NonZeroU32, sync::Arc}; |
3 | |
4 | use static_assertions::assert_impl_all; |
5 | use zbus_names::{ErrorName, InterfaceName, MemberName}; |
6 | use zvariant::{serialized, Endian}; |
7 | |
8 | use crate::{utils::padding_for_8_bytes, zvariant::ObjectPath, Error, Result}; |
9 | |
10 | mod builder; |
11 | pub use builder::Builder; |
12 | |
13 | mod field; |
14 | pub(crate) use field::{Field, FieldCode}; |
15 | |
16 | mod fields; |
17 | pub(crate) use fields::Fields; |
18 | use fields::QuickFields; |
19 | |
20 | mod body; |
21 | pub use body::Body; |
22 | |
23 | pub(crate) mod header; |
24 | use header::MIN_MESSAGE_SIZE; |
25 | pub use header::{EndianSig, Flags, Header, PrimaryHeader, Type, NATIVE_ENDIAN_SIG}; |
26 | |
27 | /// A position in the stream of [`Message`] objects received by a single [`zbus::Connection`]. |
28 | /// |
29 | /// Note: the relative ordering of values obtained from distinct [`zbus::Connection`] objects is |
30 | /// not specified; only sequence numbers originating from the same connection should be compared. |
31 | #[derive (Debug, Default, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] |
32 | pub struct Sequence { |
33 | recv_seq: u64, |
34 | } |
35 | |
36 | impl Sequence { |
37 | /// A sequence number that is higher than any other; used by errors that terminate a stream. |
38 | pub(crate) const LAST: Self = Self { recv_seq: u64::MAX }; |
39 | } |
40 | |
41 | /// A D-Bus Message. |
42 | /// |
43 | /// The content of the message are stored in serialized format. To get the body of the message, use |
44 | /// the [`Message::body`] method, and use [`Body`] methods to deserialize it. You may also access |
45 | /// the header and other details with the various other getters. |
46 | /// |
47 | /// Also provided are constructors for messages of different types. These will mainly be useful for |
48 | /// very advanced use cases as typically you will want to create a message for immediate dispatch |
49 | /// and hence use the API provided by [`Connection`], even when using the low-level API. |
50 | /// |
51 | /// **Note**: The message owns the received FDs and will close them when dropped. You can |
52 | /// deserialize to [`zvariant::OwnedFd`] the body (that you get using [`Message::body`]) if you want |
53 | /// to keep the FDs around after the containing message is dropped. |
54 | /// |
55 | /// [`Connection`]: struct.Connection#method.call_method |
56 | #[derive (Clone)] |
57 | pub struct Message { |
58 | pub(super) inner: Arc<Inner>, |
59 | } |
60 | |
61 | pub(super) struct Inner { |
62 | pub(crate) primary_header: PrimaryHeader, |
63 | pub(crate) quick_fields: QuickFields, |
64 | pub(crate) bytes: serialized::Data<'static, 'static>, |
65 | pub(crate) body_offset: usize, |
66 | pub(crate) recv_seq: Sequence, |
67 | } |
68 | |
69 | assert_impl_all!(Message: Send, Sync, Unpin); |
70 | |
71 | impl Message { |
72 | /// Create a builder for message of type [`Type::MethodCall`]. |
73 | pub fn method<'b, 'p: 'b, 'm: 'b, P, M>(path: P, method_name: M) -> Result<Builder<'b>> |
74 | where |
75 | P: TryInto<ObjectPath<'p>>, |
76 | M: TryInto<MemberName<'m>>, |
77 | P::Error: Into<Error>, |
78 | M::Error: Into<Error>, |
79 | { |
80 | #[allow (deprecated)] |
81 | Builder::method_call(path, method_name) |
82 | } |
83 | |
84 | /// Create a builder for message of type [`Type::Signal`]. |
85 | pub fn signal<'b, 'p: 'b, 'i: 'b, 'm: 'b, P, I, M>( |
86 | path: P, |
87 | iface: I, |
88 | signal_name: M, |
89 | ) -> Result<Builder<'b>> |
90 | where |
91 | P: TryInto<ObjectPath<'p>>, |
92 | I: TryInto<InterfaceName<'i>>, |
93 | M: TryInto<MemberName<'m>>, |
94 | P::Error: Into<Error>, |
95 | I::Error: Into<Error>, |
96 | M::Error: Into<Error>, |
97 | { |
98 | #[allow (deprecated)] |
99 | Builder::signal(path, iface, signal_name) |
100 | } |
101 | |
102 | /// Create a builder for message of type [`Type::MethodReturn`]. |
103 | pub fn method_reply(call: &Self) -> Result<Builder<'_>> { |
104 | #[allow (deprecated)] |
105 | Builder::method_return(&call.header()) |
106 | } |
107 | |
108 | /// Create a builder for message of type [`Type::Error`]. |
109 | pub fn method_error<'b, 'e: 'b, E>(call: &Self, name: E) -> Result<Builder<'b>> |
110 | where |
111 | E: TryInto<ErrorName<'e>>, |
112 | E::Error: Into<Error>, |
113 | { |
114 | #[allow (deprecated)] |
115 | Builder::error(&call.header(), name) |
116 | } |
117 | |
118 | /// Create a message from bytes. |
119 | /// |
120 | /// **Note:** Since the constructed message is not construct by zbus, the receive sequence, |
121 | /// which can be acquired from [`Message::recv_position`], is not applicable and hence set |
122 | /// to `0`. |
123 | /// |
124 | /// # Safety |
125 | /// |
126 | /// This method is unsafe as bytes may have an invalid encoding. |
127 | pub unsafe fn from_bytes(bytes: serialized::Data<'static, 'static>) -> Result<Self> { |
128 | Self::from_raw_parts(bytes, 0) |
129 | } |
130 | |
131 | /// Create a message from its full contents |
132 | pub(crate) fn from_raw_parts( |
133 | bytes: serialized::Data<'static, 'static>, |
134 | recv_seq: u64, |
135 | ) -> Result<Self> { |
136 | let endian = Endian::from(EndianSig::try_from(bytes[0])?); |
137 | if endian != bytes.context().endian() { |
138 | return Err(Error::IncorrectEndian); |
139 | } |
140 | |
141 | let (primary_header, fields_len) = PrimaryHeader::read_from_data(&bytes)?; |
142 | let (header, _) = bytes.deserialize()?; |
143 | |
144 | let header_len = MIN_MESSAGE_SIZE + fields_len as usize; |
145 | let body_offset = header_len + padding_for_8_bytes(header_len); |
146 | let quick_fields = QuickFields::new(&bytes, &header)?; |
147 | |
148 | Ok(Self { |
149 | inner: Arc::new(Inner { |
150 | primary_header, |
151 | quick_fields, |
152 | bytes, |
153 | body_offset, |
154 | recv_seq: Sequence { recv_seq }, |
155 | }), |
156 | }) |
157 | } |
158 | |
159 | pub fn primary_header(&self) -> &PrimaryHeader { |
160 | &self.inner.primary_header |
161 | } |
162 | |
163 | /// The message header. |
164 | /// |
165 | /// Note: This method does not deserialize the header but it does currently allocate so its not |
166 | /// zero-cost. While the allocation is small and will hopefully be removed in the future, it's |
167 | /// best to keep the header around if you need to access it a lot. |
168 | pub fn header(&self) -> Header<'_> { |
169 | let mut fields = Fields::new(); |
170 | let quick_fields = &self.inner.quick_fields; |
171 | if let Some(p) = quick_fields.path(self) { |
172 | fields.add(Field::Path(p)); |
173 | } |
174 | if let Some(i) = quick_fields.interface(self) { |
175 | fields.add(Field::Interface(i)); |
176 | } |
177 | if let Some(m) = quick_fields.member(self) { |
178 | fields.add(Field::Member(m)); |
179 | } |
180 | if let Some(e) = quick_fields.error_name(self) { |
181 | fields.add(Field::ErrorName(e)); |
182 | } |
183 | if let Some(r) = quick_fields.reply_serial() { |
184 | fields.add(Field::ReplySerial(r)); |
185 | } |
186 | if let Some(d) = quick_fields.destination(self) { |
187 | fields.add(Field::Destination(d)); |
188 | } |
189 | if let Some(s) = quick_fields.sender(self) { |
190 | fields.add(Field::Sender(s)); |
191 | } |
192 | if let Some(s) = quick_fields.signature(self) { |
193 | fields.add(Field::Signature(s)); |
194 | } |
195 | if let Some(u) = quick_fields.unix_fds() { |
196 | fields.add(Field::UnixFDs(u)); |
197 | } |
198 | |
199 | Header::new(self.inner.primary_header.clone(), fields) |
200 | } |
201 | |
202 | /// The message type. |
203 | pub fn message_type(&self) -> Type { |
204 | self.inner.primary_header.msg_type() |
205 | } |
206 | |
207 | /// The object to send a call to, or the object a signal is emitted from. |
208 | #[deprecated ( |
209 | since = "4.0.0" , |
210 | note = "Use `Message::header` with `message::Header::path` instead" |
211 | )] |
212 | pub fn path(&self) -> Option<ObjectPath<'_>> { |
213 | self.inner.quick_fields.path(self) |
214 | } |
215 | |
216 | /// The interface to invoke a method call on, or that a signal is emitted from. |
217 | #[deprecated ( |
218 | since = "4.0.0" , |
219 | note = "Use `Message::header` with `message::Header::interface` instead" |
220 | )] |
221 | pub fn interface(&self) -> Option<InterfaceName<'_>> { |
222 | self.inner.quick_fields.interface(self) |
223 | } |
224 | |
225 | /// The member, either the method name or signal name. |
226 | #[deprecated ( |
227 | since = "4.0.0" , |
228 | note = "Use `Message::header` with `message::Header::member` instead" |
229 | )] |
230 | pub fn member(&self) -> Option<MemberName<'_>> { |
231 | self.inner.quick_fields.member(self) |
232 | } |
233 | |
234 | /// The serial number of the message this message is a reply to. |
235 | #[deprecated ( |
236 | since = "4.0.0" , |
237 | note = "Use `Message::header` with `message::Header::reply_serial` instead" |
238 | )] |
239 | pub fn reply_serial(&self) -> Option<NonZeroU32> { |
240 | self.inner.quick_fields.reply_serial() |
241 | } |
242 | |
243 | /// The body that you can deserialize using [`Body::deserialize`]. |
244 | /// |
245 | /// # Example |
246 | /// |
247 | /// ``` |
248 | /// # use zbus::message::Message; |
249 | /// # (|| -> zbus::Result<()> { |
250 | /// let send_body = (7i32, (2i32, "foo" ), vec!["bar" ]); |
251 | /// let message = Message::method("/" , "ping" )? |
252 | /// .destination("zbus.test" )? |
253 | /// .interface("zbus.test" )? |
254 | /// .build(&send_body)?; |
255 | /// let body = message.body(); |
256 | /// let body: zbus::zvariant::Structure = body.deserialize()?; |
257 | /// let fields = body.fields(); |
258 | /// assert!(matches!(fields[0], zvariant::Value::I32(7))); |
259 | /// assert!(matches!(fields[1], zvariant::Value::Structure(_))); |
260 | /// assert!(matches!(fields[2], zvariant::Value::Array(_))); |
261 | /// |
262 | /// let reply_body = Message::method_reply(&message)?.build(&body)?.body(); |
263 | /// let reply_value : (i32, (i32, &str), Vec<String>) = reply_body.deserialize()?; |
264 | /// |
265 | /// assert_eq!(reply_value.0, 7); |
266 | /// assert_eq!(reply_value.2.len(), 1); |
267 | /// # Ok(()) })().unwrap() |
268 | /// ``` |
269 | pub fn body(&self) -> Body { |
270 | Body::new( |
271 | self.inner.bytes.slice(self.inner.body_offset..), |
272 | self.clone(), |
273 | ) |
274 | } |
275 | |
276 | /// Get a reference to the underlying byte encoding of the message. |
277 | pub fn data(&self) -> &serialized::Data<'static, 'static> { |
278 | &self.inner.bytes |
279 | } |
280 | |
281 | /// Get the receive ordering of a message. |
282 | /// |
283 | /// This may be used to identify how two events were ordered on the bus. It only produces a |
284 | /// useful ordering for messages that were produced by the same [`zbus::Connection`]. |
285 | /// |
286 | /// This is completely unrelated to the serial number on the message, which is set by the peer |
287 | /// and might not be ordered at all. |
288 | pub fn recv_position(&self) -> Sequence { |
289 | self.inner.recv_seq |
290 | } |
291 | } |
292 | |
293 | impl fmt::Debug for Message { |
294 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
295 | let mut msg = f.debug_struct("Msg" ); |
296 | let h = self.header(); |
297 | msg.field("type" , &h.message_type()); |
298 | msg.field("serial" , &self.primary_header().serial_num()); |
299 | if let Some(sender) = h.sender() { |
300 | msg.field("sender" , &sender); |
301 | } |
302 | if let Some(serial) = h.reply_serial() { |
303 | msg.field("reply-serial" , &serial); |
304 | } |
305 | if let Some(path) = h.path() { |
306 | msg.field("path" , &path); |
307 | } |
308 | if let Some(iface) = h.interface() { |
309 | msg.field("iface" , &iface); |
310 | } |
311 | if let Some(member) = h.member() { |
312 | msg.field("member" , &member); |
313 | } |
314 | if let Some(s) = self.body().signature() { |
315 | msg.field("body" , &s); |
316 | } |
317 | #[cfg (unix)] |
318 | { |
319 | msg.field("fds" , &self.data().fds()); |
320 | } |
321 | msg.finish() |
322 | } |
323 | } |
324 | |
325 | impl fmt::Display for Message { |
326 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
327 | let header = self.header(); |
328 | let (ty, error_name, sender, member) = ( |
329 | header.message_type(), |
330 | header.error_name(), |
331 | header.sender(), |
332 | header.member(), |
333 | ); |
334 | |
335 | match ty { |
336 | Type::MethodCall => { |
337 | write!(f, "Method call" )?; |
338 | if let Some(m) = member { |
339 | write!(f, " {m}" )?; |
340 | } |
341 | } |
342 | Type::MethodReturn => { |
343 | write!(f, "Method return" )?; |
344 | } |
345 | Type::Error => { |
346 | write!(f, "Error" )?; |
347 | if let Some(e) = error_name { |
348 | write!(f, " {e}" )?; |
349 | } |
350 | |
351 | let body = self.body(); |
352 | let msg = body.deserialize_unchecked::<&str>(); |
353 | if let Ok(msg) = msg { |
354 | write!(f, ": {msg}" )?; |
355 | } |
356 | } |
357 | Type::Signal => { |
358 | write!(f, "Signal" )?; |
359 | if let Some(m) = member { |
360 | write!(f, " {m}" )?; |
361 | } |
362 | } |
363 | } |
364 | |
365 | if let Some(s) = sender { |
366 | write!(f, " from {s}" )?; |
367 | } |
368 | |
369 | Ok(()) |
370 | } |
371 | } |
372 | |
373 | #[cfg (test)] |
374 | mod tests { |
375 | #[cfg (unix)] |
376 | use std::os::fd::{AsFd, AsRawFd}; |
377 | use test_log::test; |
378 | #[cfg (unix)] |
379 | use zvariant::Fd; |
380 | |
381 | use super::Message; |
382 | use crate::Error; |
383 | |
384 | #[test ] |
385 | fn test() { |
386 | #[cfg (unix)] |
387 | let stdout = std::io::stdout(); |
388 | let m = Message::method("/" , "do" ) |
389 | .unwrap() |
390 | .sender(":1.72" ) |
391 | .unwrap() |
392 | .build(&( |
393 | #[cfg (unix)] |
394 | Fd::from(&stdout), |
395 | "foo" , |
396 | )) |
397 | .unwrap(); |
398 | assert_eq!( |
399 | m.body().signature().unwrap().to_string(), |
400 | if cfg!(unix) { "hs" } else { "s" } |
401 | ); |
402 | #[cfg (unix)] |
403 | { |
404 | let fds = m.data().fds(); |
405 | assert_eq!(fds.len(), 1); |
406 | // FDs get dup'ed so it has to be a different FD now. |
407 | assert_ne!(fds[0].as_fd().as_raw_fd(), stdout.as_raw_fd()); |
408 | } |
409 | |
410 | let body: Result<u32, Error> = m.body().deserialize(); |
411 | assert!(matches!( |
412 | body.unwrap_err(), |
413 | Error::Variant(zvariant::Error::SignatureMismatch { .. }) |
414 | )); |
415 | |
416 | assert_eq!(m.to_string(), "Method call do from :1.72" ); |
417 | let r = Message::method_reply(&m) |
418 | .unwrap() |
419 | .build(&("all fine!" )) |
420 | .unwrap(); |
421 | assert_eq!(r.to_string(), "Method return" ); |
422 | let e = Message::method_error(&m, "org.freedesktop.zbus.Error" ) |
423 | .unwrap() |
424 | .build(&("kaboom!" , 32)) |
425 | .unwrap(); |
426 | assert_eq!(e.to_string(), "Error org.freedesktop.zbus.Error: kaboom!" ); |
427 | } |
428 | } |
429 | |