1 | use std::{ |
2 | num::NonZeroU32, |
3 | sync::atomic::{AtomicU32, Ordering::SeqCst}, |
4 | }; |
5 | |
6 | use enumflags2::{bitflags , BitFlags}; |
7 | use serde::{Deserialize, Serialize}; |
8 | use serde_repr::{Deserialize_repr, Serialize_repr}; |
9 | |
10 | use static_assertions::assert_impl_all; |
11 | use zbus_names::{BusName, ErrorName, InterfaceName, MemberName, UniqueName}; |
12 | use zvariant::{ |
13 | serialized::{self, Context}, |
14 | Endian, ObjectPath, Signature, Type as VariantType, |
15 | }; |
16 | |
17 | use crate::{ |
18 | message::{Field, FieldCode, Fields}, |
19 | Error, |
20 | }; |
21 | |
22 | pub(crate) const PRIMARY_HEADER_SIZE: usize = 12; |
23 | pub(crate) const MIN_MESSAGE_SIZE: usize = PRIMARY_HEADER_SIZE + 4; |
24 | pub(crate) const MAX_MESSAGE_SIZE: usize = 128 * 1024 * 1024; // 128 MiB |
25 | |
26 | /// D-Bus code for endianness. |
27 | #[repr (u8)] |
28 | #[derive (Debug, Copy, Clone, Deserialize_repr, PartialEq, Eq, Serialize_repr, VariantType)] |
29 | pub enum EndianSig { |
30 | /// The D-Bus message is in big-endian (network) byte order. |
31 | Big = b'B' , |
32 | |
33 | /// The D-Bus message is in little-endian byte order. |
34 | Little = b'l' , |
35 | } |
36 | |
37 | assert_impl_all!(EndianSig: Send, Sync, Unpin); |
38 | |
39 | // Such a shame I've to do this manually |
40 | impl TryFrom<u8> for EndianSig { |
41 | type Error = Error; |
42 | |
43 | fn try_from(val: u8) -> Result<EndianSig, Error> { |
44 | match val { |
45 | b'B' => Ok(EndianSig::Big), |
46 | b'l' => Ok(EndianSig::Little), |
47 | _ => Err(Error::IncorrectEndian), |
48 | } |
49 | } |
50 | } |
51 | |
52 | #[cfg (target_endian = "big" )] |
53 | /// Signature of the target's native endian. |
54 | pub const NATIVE_ENDIAN_SIG: EndianSig = EndianSig::Big; |
55 | #[cfg (target_endian = "little" )] |
56 | /// Signature of the target's native endian. |
57 | pub const NATIVE_ENDIAN_SIG: EndianSig = EndianSig::Little; |
58 | |
59 | impl From<Endian> for EndianSig { |
60 | fn from(endian: Endian) -> Self { |
61 | match endian { |
62 | Endian::Little => EndianSig::Little, |
63 | Endian::Big => EndianSig::Big, |
64 | } |
65 | } |
66 | } |
67 | |
68 | impl From<EndianSig> for Endian { |
69 | fn from(endian_sig: EndianSig) -> Self { |
70 | match endian_sig { |
71 | EndianSig::Little => Endian::Little, |
72 | EndianSig::Big => Endian::Big, |
73 | } |
74 | } |
75 | } |
76 | |
77 | /// Message header representing the D-Bus type of the message. |
78 | #[repr (u8)] |
79 | #[derive ( |
80 | Debug, Copy, Clone, Deserialize_repr, PartialEq, Eq, Hash, Serialize_repr, VariantType, |
81 | )] |
82 | pub enum Type { |
83 | /// Method call. This message type may prompt a reply (and typically does). |
84 | MethodCall = 1, |
85 | /// A reply to a method call. |
86 | MethodReturn = 2, |
87 | /// An error in response to a method call. |
88 | Error = 3, |
89 | /// Signal emission. |
90 | Signal = 4, |
91 | } |
92 | |
93 | assert_impl_all!(Type: Send, Sync, Unpin); |
94 | |
95 | /// Pre-defined flags that can be passed in Message header. |
96 | #[bitflags ] |
97 | #[repr (u8)] |
98 | #[derive (Debug, Copy, Clone, PartialEq, Eq, VariantType)] |
99 | pub enum Flags { |
100 | /// This message does not expect method return replies or error replies, even if it is of a |
101 | /// type that can have a reply; the reply should be omitted. |
102 | /// |
103 | /// Note that `Type::MethodCall` is the only message type currently defined in the |
104 | /// specification that can expect a reply, so the presence or absence of this flag in the other |
105 | /// three message types that are currently documented is meaningless: replies to those message |
106 | /// types should not be sent, whether this flag is present or not. |
107 | NoReplyExpected = 0x1, |
108 | /// The bus must not launch an owner for the destination name in response to this message. |
109 | NoAutoStart = 0x2, |
110 | /// This flag may be set on a method call message to inform the receiving side that the caller |
111 | /// is prepared to wait for interactive authorization, which might take a considerable time to |
112 | /// complete. For instance, if this flag is set, it would be appropriate to query the user for |
113 | /// passwords or confirmation via Polkit or a similar framework. |
114 | AllowInteractiveAuth = 0x4, |
115 | } |
116 | |
117 | assert_impl_all!(Flags: Send, Sync, Unpin); |
118 | |
119 | /// The primary message header, which is present in all D-Bus messages. |
120 | /// |
121 | /// This header contains all the essential information about a message, regardless of its type. |
122 | #[derive (Clone, Debug, Serialize, Deserialize, VariantType)] |
123 | pub struct PrimaryHeader { |
124 | endian_sig: EndianSig, |
125 | msg_type: Type, |
126 | flags: BitFlags<Flags>, |
127 | protocol_version: u8, |
128 | body_len: u32, |
129 | serial_num: NonZeroU32, |
130 | } |
131 | |
132 | assert_impl_all!(PrimaryHeader: Send, Sync, Unpin); |
133 | |
134 | impl PrimaryHeader { |
135 | /// Create a new `PrimaryHeader` instance. |
136 | pub fn new(msg_type: Type, body_len: u32) -> Self { |
137 | Self { |
138 | endian_sig: NATIVE_ENDIAN_SIG, |
139 | msg_type, |
140 | flags: BitFlags::empty(), |
141 | protocol_version: 1, |
142 | body_len, |
143 | serial_num: SERIAL_NUM.fetch_add(1, SeqCst).try_into().unwrap(), |
144 | } |
145 | } |
146 | |
147 | pub(crate) fn read(buf: &[u8]) -> Result<(PrimaryHeader, u32), Error> { |
148 | let endian = Endian::from(EndianSig::try_from(buf[0])?); |
149 | let ctx = Context::new_dbus(endian, 0); |
150 | let data = serialized::Data::new(buf, ctx); |
151 | |
152 | Self::read_from_data(&data) |
153 | } |
154 | |
155 | pub(crate) fn read_from_data( |
156 | data: &serialized::Data<'_, '_>, |
157 | ) -> Result<(PrimaryHeader, u32), Error> { |
158 | let (primary_header, size) = data.deserialize()?; |
159 | assert_eq!(size, PRIMARY_HEADER_SIZE); |
160 | let (fields_len, _) = data.slice(PRIMARY_HEADER_SIZE..).deserialize()?; |
161 | Ok((primary_header, fields_len)) |
162 | } |
163 | |
164 | /// D-Bus code for endian encoding of the message. |
165 | pub fn endian_sig(&self) -> EndianSig { |
166 | self.endian_sig |
167 | } |
168 | |
169 | /// Set the D-Bus code for endian encoding of the message. |
170 | pub fn set_endian_sig(&mut self, sig: EndianSig) { |
171 | self.endian_sig = sig; |
172 | } |
173 | |
174 | /// The message type. |
175 | pub fn msg_type(&self) -> Type { |
176 | self.msg_type |
177 | } |
178 | |
179 | /// Set the message type. |
180 | pub fn set_msg_type(&mut self, msg_type: Type) { |
181 | self.msg_type = msg_type; |
182 | } |
183 | |
184 | /// The message flags. |
185 | pub fn flags(&self) -> BitFlags<Flags> { |
186 | self.flags |
187 | } |
188 | |
189 | /// Set the message flags. |
190 | pub fn set_flags(&mut self, flags: BitFlags<Flags>) { |
191 | self.flags = flags; |
192 | } |
193 | |
194 | /// The major version of the protocol the message is compliant to. |
195 | /// |
196 | /// Currently only `1` is valid. |
197 | pub fn protocol_version(&self) -> u8 { |
198 | self.protocol_version |
199 | } |
200 | |
201 | /// Set the major version of the protocol the message is compliant to. |
202 | /// |
203 | /// Currently only `1` is valid. |
204 | pub fn set_protocol_version(&mut self, version: u8) { |
205 | self.protocol_version = version; |
206 | } |
207 | |
208 | /// The byte length of the message body. |
209 | pub fn body_len(&self) -> u32 { |
210 | self.body_len |
211 | } |
212 | |
213 | /// Set the byte length of the message body. |
214 | pub fn set_body_len(&mut self, len: u32) { |
215 | self.body_len = len; |
216 | } |
217 | |
218 | /// The serial number of the message. |
219 | /// |
220 | /// This is used to match a reply to a method call. |
221 | pub fn serial_num(&self) -> NonZeroU32 { |
222 | self.serial_num |
223 | } |
224 | |
225 | /// Set the serial number of the message. |
226 | /// |
227 | /// This is used to match a reply to a method call. |
228 | pub fn set_serial_num(&mut self, serial_num: NonZeroU32) { |
229 | self.serial_num = serial_num; |
230 | } |
231 | } |
232 | |
233 | /// The message header, containing all the metadata about the message. |
234 | /// |
235 | /// This includes both the [`PrimaryHeader`] and [`Fields`]. |
236 | /// |
237 | /// [`PrimaryHeader`]: struct.PrimaryHeader.html |
238 | /// [`Fields`]: struct.Fields.html |
239 | #[derive (Debug, Clone, Serialize, Deserialize, VariantType)] |
240 | pub struct Header<'m> { |
241 | primary: PrimaryHeader, |
242 | #[serde(borrow)] |
243 | fields: Fields<'m>, |
244 | } |
245 | |
246 | assert_impl_all!(Header<'_>: Send, Sync, Unpin); |
247 | |
248 | macro_rules! get_field { |
249 | ($self:ident, $kind:ident) => { |
250 | get_field!($self, $kind, (|v| v)) |
251 | }; |
252 | ($self:ident, $kind:ident, $closure:tt) => { |
253 | #[allow(clippy::redundant_closure_call)] |
254 | match $self.fields().get_field(FieldCode::$kind) { |
255 | Some(Field::$kind(value)) => Some($closure(value)), |
256 | // SAFETY: `Deserialize` impl for `Field` ensures that the code and field match. |
257 | Some(_) => unreachable!("FieldCode and Field mismatch" ), |
258 | None => None, |
259 | } |
260 | }; |
261 | } |
262 | |
263 | macro_rules! get_field_u32 { |
264 | ($self:ident, $kind:ident) => { |
265 | get_field!($self, $kind, (|v: &u32| *v)) |
266 | }; |
267 | } |
268 | |
269 | impl<'m> Header<'m> { |
270 | /// Create a new `Header` instance. |
271 | pub(super) fn new(primary: PrimaryHeader, fields: Fields<'m>) -> Self { |
272 | Self { primary, fields } |
273 | } |
274 | |
275 | /// Get a reference to the primary header. |
276 | pub fn primary(&self) -> &PrimaryHeader { |
277 | &self.primary |
278 | } |
279 | |
280 | /// Get a mutable reference to the primary header. |
281 | pub fn primary_mut(&mut self) -> &mut PrimaryHeader { |
282 | &mut self.primary |
283 | } |
284 | |
285 | /// Get the primary header, consuming `self`. |
286 | pub fn into_primary(self) -> PrimaryHeader { |
287 | self.primary |
288 | } |
289 | |
290 | /// Get a reference to the message fields. |
291 | fn fields(&self) -> &Fields<'m> { |
292 | &self.fields |
293 | } |
294 | |
295 | /// Get a mutable reference to the message fields. |
296 | pub(super) fn fields_mut(&mut self) -> &mut Fields<'m> { |
297 | &mut self.fields |
298 | } |
299 | |
300 | /// The message type |
301 | pub fn message_type(&self) -> Type { |
302 | self.primary().msg_type() |
303 | } |
304 | |
305 | /// The object to send a call to, or the object a signal is emitted from. |
306 | pub fn path(&self) -> Option<&ObjectPath<'m>> { |
307 | get_field!(self, Path) |
308 | } |
309 | |
310 | /// The interface to invoke a method call on, or that a signal is emitted from. |
311 | pub fn interface(&self) -> Option<&InterfaceName<'m>> { |
312 | get_field!(self, Interface) |
313 | } |
314 | |
315 | /// The member, either the method name or signal name. |
316 | pub fn member(&self) -> Option<&MemberName<'m>> { |
317 | get_field!(self, Member) |
318 | } |
319 | |
320 | /// The name of the error that occurred, for errors. |
321 | pub fn error_name(&self) -> Option<&ErrorName<'m>> { |
322 | get_field!(self, ErrorName) |
323 | } |
324 | |
325 | /// The serial number of the message this message is a reply to. |
326 | pub fn reply_serial(&self) -> Option<NonZeroU32> { |
327 | match self.fields().get_field(FieldCode::ReplySerial) { |
328 | Some(Field::ReplySerial(value)) => Some(*value), |
329 | // SAFETY: `Deserialize` impl for `Field` ensures that the code and field match. |
330 | Some(_) => unreachable!("FieldCode and Field mismatch" ), |
331 | None => None, |
332 | } |
333 | } |
334 | |
335 | /// The name of the connection this message is intended for. |
336 | pub fn destination(&self) -> Option<&BusName<'m>> { |
337 | get_field!(self, Destination) |
338 | } |
339 | |
340 | /// Unique name of the sending connection. |
341 | pub fn sender(&self) -> Option<&UniqueName<'m>> { |
342 | get_field!(self, Sender) |
343 | } |
344 | |
345 | /// The signature of the message body. |
346 | pub fn signature(&self) -> Option<&Signature<'m>> { |
347 | get_field!(self, Signature) |
348 | } |
349 | |
350 | /// The number of Unix file descriptors that accompany the message. |
351 | pub fn unix_fds(&self) -> Option<u32> { |
352 | get_field_u32!(self, UnixFDs) |
353 | } |
354 | } |
355 | |
356 | static SERIAL_NUM: AtomicU32 = AtomicU32::new(1); |
357 | |
358 | #[cfg (test)] |
359 | mod tests { |
360 | use crate::message::{Field, Fields, Header, PrimaryHeader, Type}; |
361 | |
362 | use std::error::Error; |
363 | use test_log::test; |
364 | use zbus_names::{InterfaceName, MemberName}; |
365 | use zvariant::{ObjectPath, Signature}; |
366 | |
367 | #[test ] |
368 | fn header() -> Result<(), Box<dyn Error>> { |
369 | let path = ObjectPath::try_from("/some/path" )?; |
370 | let iface = InterfaceName::try_from("some.interface" )?; |
371 | let member = MemberName::try_from("Member" )?; |
372 | let mut f = Fields::new(); |
373 | f.add(Field::Path(path.clone())); |
374 | f.add(Field::Interface(iface.clone())); |
375 | f.add(Field::Member(member.clone())); |
376 | f.add(Field::Sender(":1.84" .try_into()?)); |
377 | let h = Header::new(PrimaryHeader::new(Type::Signal, 77), f); |
378 | |
379 | assert_eq!(h.message_type(), Type::Signal); |
380 | assert_eq!(h.path(), Some(&path)); |
381 | assert_eq!(h.interface(), Some(&iface)); |
382 | assert_eq!(h.member(), Some(&member)); |
383 | assert_eq!(h.error_name(), None); |
384 | assert_eq!(h.destination(), None); |
385 | assert_eq!(h.reply_serial(), None); |
386 | assert_eq!(h.sender().unwrap(), ":1.84" ); |
387 | assert_eq!(h.signature(), None); |
388 | assert_eq!(h.unix_fds(), None); |
389 | |
390 | let mut f = Fields::new(); |
391 | f.add(Field::ErrorName("org.zbus.Error" .try_into()?)); |
392 | f.add(Field::Destination(":1.11" .try_into()?)); |
393 | f.add(Field::ReplySerial(88.try_into()?)); |
394 | f.add(Field::Signature(Signature::from_str_unchecked("say" ))); |
395 | f.add(Field::UnixFDs(12)); |
396 | let h = Header::new(PrimaryHeader::new(Type::MethodReturn, 77), f); |
397 | |
398 | assert_eq!(h.message_type(), Type::MethodReturn); |
399 | assert_eq!(h.path(), None); |
400 | assert_eq!(h.interface(), None); |
401 | assert_eq!(h.member(), None); |
402 | assert_eq!(h.error_name().unwrap(), "org.zbus.Error" ); |
403 | assert_eq!(h.destination().unwrap(), ":1.11" ); |
404 | assert_eq!(h.reply_serial().map(Into::into), Some(88)); |
405 | assert_eq!(h.sender(), None); |
406 | assert_eq!(h.signature(), Some(&Signature::from_str_unchecked("say" ))); |
407 | assert_eq!(h.unix_fds(), Some(12)); |
408 | |
409 | Ok(()) |
410 | } |
411 | } |
412 | |