zbus/message/
mod.rs

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