| 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 | |