use std::{
fmt,
num::NonZeroU32,
sync::atomic::{AtomicU32, Ordering::Relaxed},
};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::{
Basic, Error, ObjectPath, OwnedVariant, Signature, Type as VariantType, Variant,
message::Fields,
names::{BusName, ErrorName, InterfaceName, MemberName, UniqueName},
utils::fmt_bitflags,
wire::Endian,
};
pub(crate) const PRIMARY_HEADER_SIZE: usize = 12;
pub(crate) const MIN_MESSAGE_SIZE: usize = PRIMARY_HEADER_SIZE + 4;
pub(crate) const MAX_MESSAGE_SIZE: usize = 128 * 1024 * 1024; pub(crate) const PROTOCOL_VERSION: u8 = 1;
#[repr(u8)]
#[derive(Debug, Copy, Clone, Deserialize_repr, PartialEq, Eq, Serialize_repr, VariantType)]
pub enum EndianSig {
Big = b'B',
Little = b'l',
}
impl TryFrom<u8> for EndianSig {
type Error = Error;
fn try_from(val: u8) -> Result<EndianSig, Error> {
match val {
b'B' => Ok(EndianSig::Big),
b'l' => Ok(EndianSig::Little),
_ => Err(Error::IncorrectEndian),
}
}
}
#[cfg(target_endian = "big")]
pub const NATIVE_ENDIAN_SIG: EndianSig = EndianSig::Big;
#[cfg(target_endian = "little")]
pub const NATIVE_ENDIAN_SIG: EndianSig = EndianSig::Little;
impl From<Endian> for EndianSig {
fn from(endian: Endian) -> Self {
match endian {
Endian::Little => EndianSig::Little,
Endian::Big => EndianSig::Big,
}
}
}
impl From<EndianSig> for Endian {
fn from(endian_sig: EndianSig) -> Self {
match endian_sig {
EndianSig::Little => Endian::Little,
EndianSig::Big => Endian::Big,
}
}
}
#[repr(u8)]
#[derive(
Debug, Copy, Clone, Deserialize_repr, PartialEq, Eq, Hash, Serialize_repr, VariantType,
)]
pub enum Type {
MethodCall = 1,
MethodReturn = 2,
Error = 3,
Signal = 4,
}
#[derive(
Copy,
Clone,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
VariantType,
Variant,
OwnedVariant,
)]
pub struct Flags(u8);
bitflags::bitflags! {
impl Flags: u8 {
const NO_REPLY_EXPECTED = 0x1;
const NO_AUTO_START = 0x2;
const ALLOW_INTERACTIVE_AUTH = 0x4;
}
}
impl fmt::Debug for Flags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_bitflags("Flags", self, f)
}
}
impl Basic for Flags {
const SIGNATURE_CHAR: char = u8::SIGNATURE_CHAR;
const SIGNATURE_STR: &'static str = u8::SIGNATURE_STR;
}
#[derive(Clone, Debug, Serialize, Deserialize, VariantType)]
pub struct PrimaryHeader {
endian_sig: EndianSig,
msg_type: Type,
flags: Flags,
protocol_version: u8,
body_len: u32,
serial_num: NonZeroU32,
}
impl PrimaryHeader {
pub fn new(msg_type: Type, body_len: u32) -> Self {
let mut serial_num = SERIAL_NUM.fetch_add(1, Relaxed);
if serial_num == 0 {
serial_num = SERIAL_NUM.fetch_add(1, Relaxed);
}
Self {
endian_sig: NATIVE_ENDIAN_SIG,
msg_type,
flags: Flags::empty(),
protocol_version: PROTOCOL_VERSION,
body_len,
serial_num: serial_num.try_into().unwrap(),
}
}
pub(super) fn from_parts(
endian_sig: EndianSig,
msg_type: Type,
flags: Flags,
protocol_version: u8,
body_len: u32,
serial_num: NonZeroU32,
) -> Self {
Self {
endian_sig,
msg_type,
flags,
protocol_version,
body_len,
serial_num,
}
}
pub(crate) fn read(buf: &[u8]) -> Result<(PrimaryHeader, u32), Error> {
super::parser::parse_primary_header(buf)
}
pub fn endian_sig(&self) -> EndianSig {
self.endian_sig
}
pub fn set_endian_sig(&mut self, sig: EndianSig) {
self.endian_sig = sig;
}
pub fn msg_type(&self) -> Type {
self.msg_type
}
pub fn set_msg_type(&mut self, msg_type: Type) {
self.msg_type = msg_type;
}
pub fn flags(&self) -> Flags {
self.flags
}
pub fn set_flags(&mut self, flags: Flags) {
self.flags = flags;
}
pub fn protocol_version(&self) -> u8 {
self.protocol_version
}
pub fn set_protocol_version(&mut self, version: u8) {
self.protocol_version = version;
}
pub fn body_len(&self) -> u32 {
self.body_len
}
pub fn set_body_len(&mut self, len: u32) {
self.body_len = len;
}
pub fn serial_num(&self) -> NonZeroU32 {
self.serial_num
}
pub fn set_serial_num(&mut self, serial_num: NonZeroU32) {
self.serial_num = serial_num;
}
}
#[derive(Debug, Clone, Serialize, Deserialize, VariantType)]
pub struct Header<'m> {
primary: PrimaryHeader,
#[serde(borrow)]
fields: Fields<'m>,
}
impl<'m> Header<'m> {
pub(super) fn new(primary: PrimaryHeader, fields: Fields<'m>) -> Self {
Self { primary, fields }
}
pub fn primary(&self) -> &PrimaryHeader {
&self.primary
}
pub fn primary_mut(&mut self) -> &mut PrimaryHeader {
&mut self.primary
}
pub fn into_primary(self) -> PrimaryHeader {
self.primary
}
pub(super) fn fields_mut(&mut self) -> &mut Fields<'m> {
&mut self.fields
}
pub fn message_type(&self) -> Type {
self.primary().msg_type()
}
pub fn path(&self) -> Option<&ObjectPath<'m>> {
self.fields.path.as_ref()
}
pub fn interface(&self) -> Option<&InterfaceName<'m>> {
self.fields.interface.as_ref()
}
pub fn member(&self) -> Option<&MemberName<'m>> {
self.fields.member.as_ref()
}
pub fn error_name(&self) -> Option<&ErrorName<'m>> {
self.fields.error_name.as_ref()
}
pub fn reply_serial(&self) -> Option<NonZeroU32> {
self.fields.reply_serial
}
pub fn destination(&self) -> Option<&BusName<'m>> {
self.fields.destination.as_ref()
}
pub fn sender(&self) -> Option<&UniqueName<'m>> {
self.fields.sender.as_ref()
}
pub fn signature(&self) -> &Signature {
&self.fields.signature
}
pub fn unix_fds(&self) -> Option<u32> {
self.fields.unix_fds
}
}
static SERIAL_NUM: AtomicU32 = AtomicU32::new(0);
#[cfg(test)]
mod tests {
use crate::message::{Fields, Flags, Header, PrimaryHeader, Type};
use crate::{
ObjectPath, Signature, Type as _,
names::{InterfaceName, MemberName},
signature,
};
use std::{borrow::Cow, error::Error};
use test_log::test;
#[test]
fn header() -> Result<(), Box<dyn Error>> {
let path = ObjectPath::try_from("/some/path")?;
let iface = InterfaceName::try_from("some.interface")?;
let member = MemberName::try_from("Member")?;
let mut f = Fields::new();
f.path = Some(path.clone());
f.interface = Some(iface.clone());
f.member = Some(member.clone());
f.sender = Some(":1.84".try_into()?);
let h = Header::new(PrimaryHeader::new(Type::Signal, 77), f);
assert_eq!(h.message_type(), Type::Signal);
assert_eq!(h.path(), Some(&path));
assert_eq!(h.interface(), Some(&iface));
assert_eq!(h.member(), Some(&member));
assert_eq!(h.error_name(), None);
assert_eq!(h.destination(), None);
assert_eq!(h.reply_serial(), None);
assert_eq!(h.sender().unwrap(), ":1.84");
assert_eq!(h.signature(), &Signature::Unit);
assert_eq!(h.unix_fds(), None);
let mut f = Fields::new();
f.error_name = Some("org.zbus.Error".try_into()?);
f.destination = Some(":1.11".try_into()?);
f.reply_serial = Some(88.try_into()?);
f.signature = Cow::Owned("say".try_into().unwrap());
f.unix_fds = Some(12);
let h = Header::new(PrimaryHeader::new(Type::MethodReturn, 77), f);
assert_eq!(h.message_type(), Type::MethodReturn);
assert_eq!(h.path(), None);
assert_eq!(h.interface(), None);
assert_eq!(h.member(), None);
assert_eq!(h.error_name().unwrap(), "org.zbus.Error");
assert_eq!(h.destination().unwrap(), ":1.11");
assert_eq!(h.reply_serial().map(Into::into), Some(88));
assert_eq!(h.sender(), None);
assert_eq!(h.signature(), &signature!("say"));
assert_eq!(h.unix_fds(), Some(12));
Ok(())
}
#[test]
fn flags_signature_and_debug() {
assert_eq!(Flags::SIGNATURE, "y");
assert_eq!(format!("{:?}", Flags::empty()), "Flags(0x0)");
assert_eq!(
format!("{:?}", Flags::NO_REPLY_EXPECTED | Flags::NO_AUTO_START),
"Flags(NO_REPLY_EXPECTED | NO_AUTO_START)"
);
}
#[test]
fn flags_convert_from_borrowed_value() {
use crate::{
Variant,
wire::{LE, serialized::Context, to_bytes},
};
let flags = Flags::NO_REPLY_EXPECTED | Flags::NO_AUTO_START;
let encoded = to_bytes(Context::new(LE, 0), &Variant::from(flags)).unwrap();
let (value, _): (Variant<'_>, _) = encoded.deserialize().unwrap();
assert_eq!(Flags::try_from(value).unwrap(), flags);
}
#[test]
fn unknown_flags_are_retained() {
let bytes = [b'l', 1, 0x9, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0];
let (primary, _) = PrimaryHeader::read(&bytes).unwrap();
assert_eq!(primary.msg_type(), Type::MethodCall);
assert_eq!(primary.flags().bits(), 0x9);
assert!(primary.flags().contains(Flags::NO_REPLY_EXPECTED));
assert_eq!(
format!("{:?}", primary.flags()),
"Flags(NO_REPLY_EXPECTED | 0x8)"
);
}
}