use std::{fmt, ops::Range, sync::Arc};
use crate::{
Error, ObjectPath, Result,
names::{ErrorName, InterfaceName, MemberName},
utils::padding_for_8_bytes,
wire::{Endian, serialized},
};
mod builder;
pub use builder::Builder;
mod field_code;
pub(crate) use field_code::FieldCode;
mod fields;
pub(crate) use fields::Fields;
mod body;
pub use body::Body;
pub(crate) mod header;
use header::PROTOCOL_VERSION;
pub use header::{EndianSig, Flags, Header, NATIVE_ENDIAN_SIG, PrimaryHeader, Type};
#[cfg(feature = "bus-impl")]
use header::{MAX_MESSAGE_SIZE, PRIMARY_HEADER_SIZE};
pub(crate) mod parser;
use parser::QuickFields;
#[derive(Debug, Default, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Sequence {
recv_seq: u64,
}
impl Sequence {
pub(crate) const LAST: Self = Self { recv_seq: u64::MAX };
}
#[derive(Clone)]
pub struct Message {
pub(super) inner: Arc<Inner>,
}
pub(super) struct Inner {
pub(crate) primary_header: PrimaryHeader,
quick_fields: std::sync::OnceLock<QuickFields>,
pub(crate) bytes: serialized::Data<'static, 'static>,
pub(crate) body_offset: usize,
pub(crate) recv_seq: Sequence,
}
impl Message {
#[must_use]
pub fn method_call<'b, 'p: 'b, 'm: 'b, P, M>(path: P, method_name: M) -> Builder<'b>
where
P: TryInto<ObjectPath<'p>>,
M: TryInto<MemberName<'m>>,
P::Error: Into<Error>,
M::Error: Into<Error>,
{
Builder::new(Type::MethodCall)
.path(path)
.member(method_name)
}
#[must_use]
pub fn signal<'b, 'p: 'b, 'i: 'b, 'm: 'b, P, I, M>(
path: P,
iface: I,
signal_name: M,
) -> Builder<'b>
where
P: TryInto<ObjectPath<'p>>,
I: TryInto<InterfaceName<'i>>,
M: TryInto<MemberName<'m>>,
P::Error: Into<Error>,
I::Error: Into<Error>,
M::Error: Into<Error>,
{
Builder::new(Type::Signal)
.path(path)
.interface(iface)
.member(signal_name)
}
#[must_use]
pub fn method_return(reply_to: &Header<'_>) -> Builder<'static> {
Builder::new(Type::MethodReturn).reply_to(reply_to)
}
#[must_use]
pub fn error<'b, 'e: 'b, E>(reply_to: &Header<'_>, name: E) -> Builder<'b>
where
E: TryInto<ErrorName<'e>>,
E::Error: Into<Error>,
{
Builder::new(Type::Error)
.reply_to(reply_to)
.error_name(name)
}
pub unsafe fn from_bytes(bytes: serialized::Data<'static, 'static>) -> Result<Self> {
Self::from_raw_parts(bytes, 0)
}
pub(crate) fn from_raw_parts(
bytes: serialized::Data<'static, 'static>,
recv_seq: u64,
) -> Result<Self> {
let (primary_header, header_len, quick_fields) = parser::parse(&bytes)?;
if Endian::from(primary_header.endian_sig()) != bytes.context().endian() {
return Err(Error::IncorrectEndian);
}
let body_offset = header_len + padding_for_8_bytes(header_len);
check_whole(
&primary_header,
&quick_fields,
&bytes,
header_len..body_offset,
)?;
let quick_fields = quick_fields.into();
Ok(Self {
inner: Arc::new(Inner {
primary_header,
quick_fields,
bytes,
body_offset,
recv_seq: Sequence { recv_seq },
}),
})
}
pub fn primary_header(&self) -> &PrimaryHeader {
&self.inner.primary_header
}
pub fn header(&self) -> Header<'_> {
let fields = unsafe { self.quick_fields().fields(&self.inner.bytes) };
Header::new(self.inner.primary_header.clone(), fields)
}
pub fn message_type(&self) -> Type {
self.inner.primary_header.msg_type()
}
pub fn body(&self) -> Body {
Body::new(
self.inner.bytes.slice(self.inner.body_offset..),
self.clone(),
)
}
pub fn data(&self) -> &serialized::Data<'static, 'static> {
&self.inner.bytes
}
pub fn recv_position(&self) -> Sequence {
self.inner.recv_seq
}
#[cfg(feature = "bus-impl")]
pub(crate) fn validate_body(&self) -> Result<()> {
let bytes = self.inner.bytes.bytes();
let quick_fields = self.quick_fields();
#[cfg(unix)]
let fds = quick_fields.unix_fds().unwrap_or(0);
#[cfg(not(unix))]
let fds = 0;
parser::validate_body(
&bytes[self.inner.body_offset..],
quick_fields.signature_bytes(bytes),
self.inner.primary_header.endian_sig(),
fds,
)
}
#[cfg(feature = "bus-impl")]
pub fn with_sender(&self, sender: &crate::names::UniqueName<'_>) -> Result<Self> {
let data = &self.inner.bytes;
let bytes = data.bytes();
let quick_fields = self.quick_fields();
let endian = Endian::from(self.inner.primary_header.endian_sig());
let fields_start = PRIMARY_HEADER_SIZE + 4;
let fields_len = endian.read_u32(&bytes[PRIMARY_HEADER_SIZE..fields_start]) as usize;
let fields_end = fields_start + fields_len;
let (kept, rest) = match quick_fields.sender_range() {
Some(name) => {
let end = name.end + 1;
let next = (end + padding_for_8_bytes(end)).min(fields_end);
(fields_start..name.start - 8, next..fields_end)
}
None => (fields_start..fields_end, fields_end..fields_end),
};
let kept_end = fields_start + kept.len() + rest.len();
let field_start = kept_end + padding_for_8_bytes(kept_end);
let name = field_start + 8..field_start + 8 + sender.len();
let new_fields_end = name.end + 1;
let body_offset = new_fields_end + padding_for_8_bytes(new_fields_end);
let body = &bytes[self.inner.body_offset..];
let len = body_offset + body.len();
if len > MAX_MESSAGE_SIZE {
return Err(Error::ExcessData);
}
let u32_bytes = |value: usize| {
let mut bytes = [0; 4];
endian.write_u32(&mut bytes, value as u32);
bytes
};
let mut new = Vec::with_capacity(len);
new.extend_from_slice(&bytes[..PRIMARY_HEADER_SIZE]);
new.extend_from_slice(&u32_bytes(new_fields_end - fields_start));
new.extend_from_slice(&bytes[kept]);
new.extend_from_slice(&bytes[rest]);
new.resize(field_start, 0);
new.extend_from_slice(&[FieldCode::Sender as u8, 1, b's', 0]);
new.extend_from_slice(&u32_bytes(sender.len()));
new.extend_from_slice(sender.as_bytes());
new.push(0);
new.resize(body_offset, 0);
new.extend_from_slice(body);
#[cfg(unix)]
let new = serialized::Data::new_fds(
new,
data.context(),
data.fds()
.iter()
.map(|fd| fd.try_to_owned())
.collect::<Result<Vec<_>>>()?,
);
#[cfg(not(unix))]
let new = serialized::Data::new(new, data.context());
match quick_fields.sender_range() {
None => Ok(Self {
inner: Arc::new(Inner {
primary_header: self.inner.primary_header.clone(),
quick_fields: quick_fields.with_sender(name).into(),
bytes: new,
body_offset,
recv_seq: self.inner.recv_seq,
}),
}),
Some(_) => Self::from_raw_parts(new, self.inner.recv_seq.recv_seq),
}
}
fn quick_fields(&self) -> &QuickFields {
self.inner.quick_fields.get_or_init(|| {
let (_, _, quick_fields) =
parser::parse(&self.inner.bytes).expect("Invalid field in a built message");
quick_fields
})
}
}
fn check_whole(
primary_header: &PrimaryHeader,
quick_fields: &QuickFields,
bytes: &serialized::Data<'static, 'static>,
padding: Range<usize>,
) -> Result<()> {
if primary_header.protocol_version() != PROTOCOL_VERSION {
return Err(Error::InvalidField);
}
quick_fields.check_required(primary_header.msg_type())?;
let Some(padding) = bytes.get(padding) else {
return Err(Error::OutOfBounds);
};
if let Some(byte) = padding.iter().find(|byte| **byte != 0) {
return Err(Error::PaddingNot0(*byte));
}
#[cfg(unix)]
if bytes.fds().len() < quick_fields.unix_fds().unwrap_or(0) as usize {
return Err(Error::MissingParameter("Missing file descriptors"));
}
Ok(())
}
impl fmt::Debug for Message {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut msg = f.debug_struct("Msg");
let h = self.header();
msg.field("type", &h.message_type());
msg.field("serial", &self.primary_header().serial_num());
if let Some(sender) = h.sender() {
msg.field("sender", &sender);
}
if let Some(serial) = h.reply_serial() {
msg.field("reply-serial", &serial);
}
if let Some(path) = h.path() {
msg.field("path", &path);
}
if let Some(iface) = h.interface() {
msg.field("iface", &iface);
}
if let Some(member) = h.member() {
msg.field("member", &member);
}
match self.body().signature() {
crate::Signature::Unit => (),
s => {
msg.field("body", &s);
}
}
#[cfg(unix)]
{
msg.field("fds", &self.data().fds());
}
msg.finish()
}
}
impl fmt::Display for Message {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let header = self.header();
let (ty, error_name, sender, member) = (
header.message_type(),
header.error_name(),
header.sender(),
header.member(),
);
match ty {
Type::MethodCall => {
write!(f, "Method call")?;
if let Some(m) = member {
write!(f, " {m}")?;
}
}
Type::MethodReturn => {
write!(f, "Method return")?;
}
Type::Error => {
write!(f, "Error")?;
if let Some(e) = error_name {
write!(f, " {e}")?;
}
let body = self.body();
let msg = body.deserialize_ignore_signature::<&str>();
if let Ok(msg) = msg {
write!(f, ": {msg}")?;
}
}
Type::Signal => {
write!(f, "Signal")?;
if let Some(m) = member {
write!(f, " {m}")?;
}
}
}
if let Some(s) = sender {
write!(f, " from {s}")?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
#[cfg(unix)]
use crate::Fd;
use crate::Signature;
#[cfg(unix)]
use std::os::fd::{AsFd, AsRawFd};
use test_log::test;
use super::{Message, Type, parser};
use crate::{Error, wire::serialized::Data};
#[test]
fn test() {
#[cfg(unix)]
let stdout = std::io::stdout();
let m = Message::method_call("/", "do")
.sender(":1.72")
.build(&(
#[cfg(unix)]
Fd::from(&stdout),
"foo",
))
.unwrap();
#[cfg(unix)]
assert_eq!(
m.body().signature(),
&Signature::static_structure(&[&Signature::Fd, &Signature::Str]),
);
#[cfg(not(unix))]
assert_eq!(m.body().signature(), &Signature::Str,);
#[cfg(unix)]
{
let fds = m.data().fds();
assert_eq!(fds.len(), 1);
assert_ne!(fds[0].as_fd().as_raw_fd(), stdout.as_raw_fd());
}
let body: Result<u32, Error> = m.body().deserialize();
assert!(matches!(body.unwrap_err(), Error::SignatureMismatch(..)));
assert_eq!(m.to_string(), "Method call do from :1.72");
let r = Message::method_return(&m.header())
.build(&("all fine!"))
.unwrap();
assert_eq!(r.to_string(), "Method return");
let e = Message::error(&m.header(), "org.freedesktop.zbus.Error")
.build(&("kaboom!", 32))
.unwrap();
assert_eq!(e.to_string(), "Error org.freedesktop.zbus.Error: kaboom!");
}
#[cfg(feature = "bus-impl")]
#[test]
fn with_sender() {
use crate::{
names::UniqueName,
wire::{BE, LE},
};
let sender = UniqueName::try_from(":busd.42").unwrap();
for endian in [LE, BE] {
#[cfg(unix)]
let stdout = std::io::stdout();
let call = || {
Message::method_call("/org/zbus/Test", "Test")
.destination("org.zbus.Test")
.interface("org.zbus.Test")
.endian(endian)
};
let built = call().build(&(7u32, "seven")).unwrap();
let messages = [
built.clone(),
Message::signal("/org/zbus/Test", "org.zbus.Test", "Test")
.endian(endian)
.build(&())
.unwrap(),
Message::method_return(&built.header())
.endian(endian)
.build(&[7u8; 13])
.unwrap(),
Message::error(&built.header(), "org.zbus.Error")
.endian(endian)
.build(&"seven")
.unwrap(),
#[cfg(unix)]
call().build(&(Fd::from(&stdout), 7u8)).unwrap(),
call().sender(":1.7").build(&"seven").unwrap(),
call().sender(sender.clone()).build(&"seven").unwrap(),
Message::method_return(&built.header())
.sender(":1.7")
.endian(endian)
.build(&())
.unwrap(),
];
for msg in messages {
let new = msg.with_sender(&sender).unwrap();
assert_eq!(new.header().sender(), Some(&sender));
assert_eq!(new.body().data().bytes(), msg.body().data().bytes());
assert_eq!(new.recv_position(), msg.recv_position());
new.body().validate().unwrap();
let header = msg.header();
let signature = header.signature().clone();
#[cfg(unix)]
let fds = msg
.data()
.fds()
.iter()
.map(|fd| fd.try_to_owned().unwrap().into())
.collect();
let builder = super::Builder::from(header).sender(sender.clone());
let expected = unsafe {
builder.build_raw_body(
msg.body().data().bytes(),
signature,
#[cfg(unix)]
fds,
)
}
.unwrap();
let received = Message::from_raw_parts(new.data().clone(), 0).unwrap();
for header in [new.header(), received.header()] {
assert_eq!(format!("{header:?}"), format!("{:?}", expected.header()));
}
#[cfg(unix)]
assert_eq!(new.data().fds().len(), msg.data().fds().len());
}
}
}
#[test]
fn invalid_path_field() {
let m = Message::method_call("/org/zbus/Test", "Ping")
.build(&())
.unwrap();
let mut bytes = m.data().bytes().to_vec();
let path = bytes
.windows(14)
.position(|w| w == b"/org/zbus/Test")
.unwrap();
bytes[path + 4] = b'.';
let data = Data::new(bytes, m.data().context());
let error = Message::from_raw_parts(data, 0).unwrap_err();
assert_eq!(error, Error::InvalidObjectPath);
}
#[test]
fn protocol_version() {
let m = Message::method_call("/org/zbus/Test", "Ping")
.build(&())
.unwrap();
let mut bytes = m.data().bytes().to_vec();
bytes[3] = 2;
let data = Data::new(bytes, m.data().context());
let error = Message::from_raw_parts(data, 0).unwrap_err();
assert_eq!(error, Error::InvalidField);
}
#[test]
fn required_fields() {
let m = Message::method_call("/org/zbus/Test", "Ping")
.build(&())
.unwrap();
Message::from_raw_parts(m.data().clone(), 0).unwrap();
for msg_type in [Type::MethodReturn, Type::Error, Type::Signal] {
let mut bytes = m.data().bytes().to_vec();
bytes[1] = msg_type as u8;
let data = Data::new(bytes, m.data().context());
let error = Message::from_raw_parts(data, 0).unwrap_err();
assert_eq!(error, Error::MissingField, "{msg_type:?}");
}
let reply = Message::method_return(&m.header())
.reply_serial(None)
.build(&())
.unwrap();
let error = Message::from_raw_parts(reply.data().clone(), 0).unwrap_err();
assert_eq!(error, Error::MissingField);
}
#[test]
fn body_padding() {
let m = Message::method_call("/org/zbus/Test", "Ping")
.build(&"Pong")
.unwrap();
let (_, header_len, _) = parser::parse(m.data()).unwrap();
assert_ne!(
header_len, m.inner.body_offset,
"the header needs no padding"
);
let mut bytes = m.data().bytes().to_vec();
bytes[header_len] = 7;
let data = Data::new(bytes, m.data().context());
let error = Message::from_raw_parts(data, 0).unwrap_err();
assert_eq!(error, Error::PaddingNot0(7));
let bytes = m.data().bytes()[..header_len].to_vec();
let data = Data::new(bytes, m.data().context());
let error = Message::from_raw_parts(data, 0).unwrap_err();
assert_eq!(error, Error::OutOfBounds);
}
#[cfg(unix)]
#[test]
fn missing_fds() {
let stdout = std::io::stdout();
let m = Message::method_call("/org/zbus/Test", "Ping")
.build(&(Fd::from(&stdout), Fd::from(&stdout)))
.unwrap();
let fds = m
.data()
.fds()
.iter()
.map(|fd| fd.try_clone().unwrap())
.collect::<Vec<_>>();
let bytes = m.data().bytes().to_vec();
let data = Data::new_fds(bytes.clone(), m.data().context(), fds);
Message::from_raw_parts(data, 0).unwrap();
let fds = vec![m.data().fds()[0].try_clone().unwrap()];
let data = Data::new_fds(bytes, m.data().context(), fds);
let error = Message::from_raw_parts(data, 0).unwrap_err();
assert!(matches!(error, Error::MissingParameter(_)), "{error:?}");
}
}