dbus: expose more functionality
This commit is contained in:
parent
fc9795cb5d
commit
f84b4619ba
8 changed files with 605 additions and 25 deletions
|
|
@ -670,8 +670,13 @@ fn write_module<W: Write>(f: &mut W, element: Element, indent: &str) -> Result<(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_element<W: Write>(f: &mut W, element: Element, indent: &str) -> Result<()> {
|
fn write_element<W: Write>(f: &mut W, element: Element, indent: &str) -> Result<()> {
|
||||||
|
let name = if element.name == "impl" {
|
||||||
|
"impl_".as_bytes().as_bstr()
|
||||||
|
} else {
|
||||||
|
element.name.as_bstr()
|
||||||
|
};
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
writeln!(f, "{}pub mod {} {{", indent, element.name)?;
|
writeln!(f, "{}pub mod {} {{", indent, name)?;
|
||||||
writeln!(f, "{} use crate::dbus::prelude::*;", indent)?;
|
writeln!(f, "{} use crate::dbus::prelude::*;", indent)?;
|
||||||
{
|
{
|
||||||
let indent = format!("{} ", indent);
|
let indent = format!("{} ", indent);
|
||||||
|
|
|
||||||
338
src/dbus.rs
338
src/dbus.rs
|
|
@ -3,7 +3,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncEngine, SpawnedFuture},
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
dbus::{
|
dbus::{
|
||||||
property::GetReply,
|
property::{Get, GetReply},
|
||||||
types::{ObjectPath, Signature, Variant},
|
types::{ObjectPath, Signature, Variant},
|
||||||
},
|
},
|
||||||
io_uring::{IoUring, IoUringError},
|
io_uring::{IoUring, IoUringError},
|
||||||
|
|
@ -17,15 +17,20 @@ use {
|
||||||
vecstorage::VecStorage,
|
vecstorage::VecStorage,
|
||||||
xrd::{xrd, XRD},
|
xrd::{xrd, XRD},
|
||||||
},
|
},
|
||||||
|
wire_dbus::{
|
||||||
|
org,
|
||||||
|
org::freedesktop::dbus::properties::{GetAll, GetAllReply, PropertiesChanged},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
std::{
|
std::{
|
||||||
borrow::Cow,
|
borrow::{Borrow, Cow},
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
future::Future,
|
future::Future,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem,
|
mem,
|
||||||
|
ops::Deref,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
task::{Context, Poll, Waker},
|
task::{Context, Poll, Waker},
|
||||||
|
|
@ -69,6 +74,8 @@ pub enum DbusError {
|
||||||
NoReplySerial,
|
NoReplySerial,
|
||||||
#[error("Signal message contains no interface or member or path")]
|
#[error("Signal message contains no interface or member or path")]
|
||||||
MissingSignalHeaders,
|
MissingSignalHeaders,
|
||||||
|
#[error("Method call message contains no interface or member or path")]
|
||||||
|
MissingMethodCallHeaders,
|
||||||
#[error("Error has no error name")]
|
#[error("Error has no error name")]
|
||||||
NoErrorName,
|
NoErrorName,
|
||||||
#[error("The socket was killed")]
|
#[error("The socket was killed")]
|
||||||
|
|
@ -208,6 +215,24 @@ pub struct DbusSocket {
|
||||||
headers: RefCell<VecStorage<(u8, Variant<'static>)>>,
|
headers: RefCell<VecStorage<(u8, Variant<'static>)>>,
|
||||||
run_toplevel: Rc<RunToplevel>,
|
run_toplevel: Rc<RunToplevel>,
|
||||||
signal_handlers: RefCell<AHashMap<(&'static str, &'static str), InterfaceSignalHandlers>>,
|
signal_handlers: RefCell<AHashMap<(&'static str, &'static str), InterfaceSignalHandlers>>,
|
||||||
|
objects: CopyHashMap<Cow<'static, str>, Rc<DbusObjectData>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Hash, Eq, PartialEq)]
|
||||||
|
struct MemberHandlerOwnedKey {
|
||||||
|
key: MemberHandlerKey<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Hash, Eq, PartialEq)]
|
||||||
|
struct MemberHandlerKey<'a> {
|
||||||
|
interface: &'a str,
|
||||||
|
member: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Borrow<MemberHandlerKey<'a>> for MemberHandlerOwnedKey {
|
||||||
|
fn borrow(&self) -> &MemberHandlerKey<'a> {
|
||||||
|
&self.key
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TY_BYTE: u8 = b'y';
|
const TY_BYTE: u8 = b'y';
|
||||||
|
|
@ -247,6 +272,22 @@ const NO_AUTO_START: u8 = 0x2;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
const ALLOW_INTERACTIVE_AUTHORIZATION: u8 = 0x4;
|
const ALLOW_INTERACTIVE_AUTHORIZATION: u8 = 0x4;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const DBUS_NAME_FLAG_ALLOW_REPLACEMENT: u32 = 0x1;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const DBUS_NAME_FLAG_REPLACE_EXISTING: u32 = 0x2;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const DBUS_NAME_FLAG_DO_NOT_QUEUE: u32 = 0x4;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: u32 = 1;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const DBUS_REQUEST_NAME_REPLY_IN_QUEUE: u32 = 2;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const DBUS_REQUEST_NAME_REPLY_EXISTS: u32 = 3;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: u32 = 4;
|
||||||
|
|
||||||
pub const BUS_DEST: &str = "org.freedesktop.DBus";
|
pub const BUS_DEST: &str = "org.freedesktop.DBus";
|
||||||
pub const BUS_PATH: &str = "/org/freedesktop/DBus";
|
pub const BUS_PATH: &str = "/org/freedesktop/DBus";
|
||||||
|
|
||||||
|
|
@ -336,6 +377,31 @@ pub unsafe trait Message<'a>: Sized + 'a {
|
||||||
fn num_fds(&self) -> u32;
|
fn num_fds(&self) -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ErrorMessage<'a> {
|
||||||
|
pub msg: Cow<'a, str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a> Message<'a> for ErrorMessage<'a> {
|
||||||
|
const SIGNATURE: &'static str = "s";
|
||||||
|
const INTERFACE: &'static str = "";
|
||||||
|
const MEMBER: &'static str = "";
|
||||||
|
type Generic<'b> = ErrorMessage<'b>;
|
||||||
|
|
||||||
|
fn marshal(&self, w: &mut Formatter) {
|
||||||
|
self.msg.marshal(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmarshal(p: &mut Parser<'a>) -> Result<Self, DbusError> {
|
||||||
|
Ok(Self {
|
||||||
|
msg: p.unmarshal()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_fds(&self) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Property {
|
pub trait Property {
|
||||||
const INTERFACE: &'static str;
|
const INTERFACE: &'static str;
|
||||||
const PROPERTY: &'static str;
|
const PROPERTY: &'static str;
|
||||||
|
|
@ -520,6 +586,274 @@ struct InterfaceSignalHandlers {
|
||||||
conditional: AHashMap<String, Rc<dyn SignalHandlerApi>>,
|
conditional: AHashMap<String, Rc<dyn SignalHandlerApi>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DbusObjectData {
|
||||||
|
path: Cow<'static, str>,
|
||||||
|
methods: CopyHashMap<MemberHandlerOwnedKey, Rc<dyn MethodHandlerApi>>,
|
||||||
|
properties: CopyHashMap<MemberHandlerOwnedKey, Rc<dyn PropertyHandlerApi>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DbusObject {
|
||||||
|
socket: Rc<DbusSocket>,
|
||||||
|
data: Rc<DbusObjectData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for DbusObject {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.socket.objects.remove(&self.data.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DbusObject {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn add_method<T, F>(&self, handler: F)
|
||||||
|
where
|
||||||
|
T: MethodCall<'static>,
|
||||||
|
F: for<'a> Fn(T::Generic<'a>, PendingReply<T::Reply>) + 'static,
|
||||||
|
{
|
||||||
|
let rhd = Rc::new(MethodHandlerData {
|
||||||
|
handler,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
});
|
||||||
|
let key = MemberHandlerOwnedKey {
|
||||||
|
key: MemberHandlerKey {
|
||||||
|
interface: T::INTERFACE,
|
||||||
|
member: T::MEMBER,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.data.methods.set(key, rhd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_property<T>(&self, value: Variant<'static>)
|
||||||
|
where
|
||||||
|
T: Property + 'static,
|
||||||
|
{
|
||||||
|
self.emit_signal(&PropertiesChanged {
|
||||||
|
interface_name: T::INTERFACE.into(),
|
||||||
|
changed_properties: Cow::Borrowed(&[DictEntry {
|
||||||
|
key: T::PROPERTY.into(),
|
||||||
|
value: value.borrow(),
|
||||||
|
}]),
|
||||||
|
invalidated_properties: Default::default(),
|
||||||
|
});
|
||||||
|
let phd = Rc::new(PropertyHandlerData::<T> {
|
||||||
|
data: value,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
});
|
||||||
|
let key = MemberHandlerOwnedKey {
|
||||||
|
key: MemberHandlerKey {
|
||||||
|
interface: T::INTERFACE,
|
||||||
|
member: T::PROPERTY,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.data.properties.set(key, phd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn emit_signal<'a, T: Signal<'a>>(&self, signal: &T) {
|
||||||
|
self.socket.emit_signal(&self.data.path, signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn path(&self) -> &str {
|
||||||
|
&self.data.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait PropertyHandlerApi {
|
||||||
|
fn interface(&self) -> &'static str;
|
||||||
|
fn member(&self) -> &'static str;
|
||||||
|
fn value<'a>(&'a self) -> Variant<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PropertyHandlerData<T> {
|
||||||
|
data: Variant<'static>,
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PropertyHandlerApi for PropertyHandlerData<T>
|
||||||
|
where
|
||||||
|
T: Property,
|
||||||
|
{
|
||||||
|
fn interface(&self) -> &'static str {
|
||||||
|
T::INTERFACE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn member(&self) -> &'static str {
|
||||||
|
T::PROPERTY
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value<'a>(&'a self) -> Variant<'a> {
|
||||||
|
self.data.borrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PendingReply<T> {
|
||||||
|
reply_expected: bool,
|
||||||
|
socket: Rc<DbusSocket>,
|
||||||
|
destination: String,
|
||||||
|
serial: u32,
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PendingReply<T> {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn reply_expected(&self) -> bool {
|
||||||
|
self.reply_expected
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn err(&self, msg: &str) {
|
||||||
|
if self.reply_expected {
|
||||||
|
self.socket.send_error(&self.destination, self.serial, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PendingReply<T>
|
||||||
|
where
|
||||||
|
T: Message<'static>,
|
||||||
|
{
|
||||||
|
pub fn ok<'a>(&self, msg: &T::Generic<'a>) {
|
||||||
|
if self.reply_expected {
|
||||||
|
self.socket.send_reply(&self.destination, self.serial, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn complete<'a>(&self, res: Result<&T::Generic<'a>, &str>) {
|
||||||
|
match res {
|
||||||
|
Ok(m) => self.ok(m),
|
||||||
|
Err(e) => self.err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait MethodHandlerApi {
|
||||||
|
fn signature(&self) -> &'static str;
|
||||||
|
fn handle(
|
||||||
|
&self,
|
||||||
|
object: &DbusObjectData,
|
||||||
|
socket: &Rc<DbusSocket>,
|
||||||
|
dest: &str,
|
||||||
|
serial: u32,
|
||||||
|
reply_expected: bool,
|
||||||
|
parser: &mut Parser,
|
||||||
|
) -> Result<(), DbusError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MethodHandlerData<T, F> {
|
||||||
|
handler: F,
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F> MethodHandlerApi for MethodHandlerData<T, F>
|
||||||
|
where
|
||||||
|
T: MethodCall<'static>,
|
||||||
|
F: for<'a> Fn(T::Generic<'a>, PendingReply<T::Reply>) + 'static,
|
||||||
|
{
|
||||||
|
fn signature(&self) -> &'static str {
|
||||||
|
T::SIGNATURE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle<'a>(
|
||||||
|
&self,
|
||||||
|
_object: &DbusObjectData,
|
||||||
|
socket: &Rc<DbusSocket>,
|
||||||
|
dest: &str,
|
||||||
|
serial: u32,
|
||||||
|
reply_expected: bool,
|
||||||
|
parser: &mut Parser<'a>,
|
||||||
|
) -> Result<(), DbusError> {
|
||||||
|
let msg = T::Generic::<'a>::unmarshal(parser)?;
|
||||||
|
let pr = PendingReply {
|
||||||
|
reply_expected,
|
||||||
|
socket: socket.clone(),
|
||||||
|
destination: dest.to_string(),
|
||||||
|
serial,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
};
|
||||||
|
(self.handler)(msg, pr);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PropertyGetHandlerProxy;
|
||||||
|
|
||||||
|
impl MethodHandlerApi for PropertyGetHandlerProxy {
|
||||||
|
fn signature(&self) -> &'static str {
|
||||||
|
Get::<u32>::SIGNATURE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle<'a>(
|
||||||
|
&self,
|
||||||
|
object: &DbusObjectData,
|
||||||
|
socket: &Rc<DbusSocket>,
|
||||||
|
dest: &str,
|
||||||
|
serial: u32,
|
||||||
|
reply_expected: bool,
|
||||||
|
parser: &mut Parser<'a>,
|
||||||
|
) -> Result<(), DbusError> {
|
||||||
|
if !reply_expected {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let msg = org::freedesktop::dbus::properties::Get::unmarshal(parser)?;
|
||||||
|
let key = MemberHandlerKey {
|
||||||
|
interface: msg.interface_name.deref(),
|
||||||
|
member: msg.property_name.deref(),
|
||||||
|
};
|
||||||
|
match object.properties.get(&key) {
|
||||||
|
Some(h) => socket.send_reply(
|
||||||
|
dest,
|
||||||
|
serial,
|
||||||
|
&org::freedesktop::dbus::properties::GetReply { value: h.value() },
|
||||||
|
),
|
||||||
|
_ => socket.send_error(dest, serial, "Property does not exist"),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PropertyGetAllHandlerProxy;
|
||||||
|
|
||||||
|
impl MethodHandlerApi for PropertyGetAllHandlerProxy {
|
||||||
|
fn signature(&self) -> &'static str {
|
||||||
|
GetAll::SIGNATURE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle<'a>(
|
||||||
|
&self,
|
||||||
|
object: &DbusObjectData,
|
||||||
|
socket: &Rc<DbusSocket>,
|
||||||
|
dest: &str,
|
||||||
|
serial: u32,
|
||||||
|
reply_expected: bool,
|
||||||
|
parser: &mut Parser<'a>,
|
||||||
|
) -> Result<(), DbusError> {
|
||||||
|
if !reply_expected {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let msg = GetAll::unmarshal(parser)?;
|
||||||
|
let all_props = object.properties.lock();
|
||||||
|
let mut props = vec![];
|
||||||
|
for property in all_props.values() {
|
||||||
|
if property.interface() == msg.interface_name {
|
||||||
|
props.push(DictEntry {
|
||||||
|
key: property.member().into(),
|
||||||
|
value: property.value(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
socket.send_reply(
|
||||||
|
dest,
|
||||||
|
serial,
|
||||||
|
&GetAllReply {
|
||||||
|
props: props.into(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use {
|
pub use {
|
||||||
super::{
|
super::{
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ fn connect(
|
||||||
headers: Default::default(),
|
headers: Default::default(),
|
||||||
run_toplevel: run_toplevel.clone(),
|
run_toplevel: run_toplevel.clone(),
|
||||||
signal_handlers: Default::default(),
|
signal_handlers: Default::default(),
|
||||||
|
objects: Default::default(),
|
||||||
});
|
});
|
||||||
let skt = socket.clone();
|
let skt = socket.clone();
|
||||||
socket.call(
|
socket.call(
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,17 @@ use {
|
||||||
},
|
},
|
||||||
crate::{
|
crate::{
|
||||||
dbus::{
|
dbus::{
|
||||||
CallError, DbusError, DbusSocket, Headers, Parser, MSG_ERROR, MSG_METHOD_RETURN,
|
CallError, DbusError, DbusSocket, Headers, MemberHandlerKey, Message, MethodHandlerApi,
|
||||||
MSG_SIGNAL,
|
Parser, PropertyGetAllHandlerProxy, PropertyGetHandlerProxy, MSG_ERROR,
|
||||||
|
MSG_METHOD_CALL, MSG_METHOD_RETURN, MSG_SIGNAL, NO_REPLY_EXPECTED,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
|
bitflags::BitflagsExt,
|
||||||
bufio::BufIoIncoming,
|
bufio::BufIoIncoming,
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
ptr_ext::{MutPtrExt, PtrExt},
|
ptr_ext::{MutPtrExt, PtrExt},
|
||||||
},
|
},
|
||||||
|
wire_dbus::org::freedesktop::dbus::properties::{Get, GetAll},
|
||||||
},
|
},
|
||||||
std::{cell::UnsafeCell, ops::Deref, rc::Rc},
|
std::{cell::UnsafeCell, ops::Deref, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -60,14 +63,14 @@ impl Incoming {
|
||||||
return Err(DbusError::InvalidEndianess);
|
return Err(DbusError::InvalidEndianess);
|
||||||
}
|
}
|
||||||
let msg_ty = msg_buf[1];
|
let msg_ty = msg_buf[1];
|
||||||
let _flags = msg_buf[2];
|
let flags = msg_buf[2];
|
||||||
let protocol = msg_buf[3];
|
let protocol = msg_buf[3];
|
||||||
if protocol != 1 {
|
if protocol != 1 {
|
||||||
return Err(DbusError::InvalidProtocol);
|
return Err(DbusError::InvalidProtocol);
|
||||||
}
|
}
|
||||||
let mut fields2 = [0u32; 3];
|
let mut fields2 = [0u32; 3];
|
||||||
uapi::pod_write(&msg_buf[4..], &mut fields2[..]).unwrap();
|
uapi::pod_write(&msg_buf[4..], &mut fields2[..]).unwrap();
|
||||||
let [body_len, _serial, headers_len] = fields2;
|
let [body_len, serial, headers_len] = fields2;
|
||||||
let dyn_header_len = headers_len + (headers_len.wrapping_neg() & 7);
|
let dyn_header_len = headers_len + (headers_len.wrapping_neg() & 7);
|
||||||
let remaining = dyn_header_len + body_len;
|
let remaining = dyn_header_len + body_len;
|
||||||
self.incoming
|
self.incoming
|
||||||
|
|
@ -89,6 +92,68 @@ impl Incoming {
|
||||||
fds: &fds,
|
fds: &fds,
|
||||||
};
|
};
|
||||||
match msg_ty {
|
match msg_ty {
|
||||||
|
MSG_METHOD_CALL => {
|
||||||
|
let (sender, interface, member, path) = match (
|
||||||
|
&headers.sender,
|
||||||
|
&headers.interface,
|
||||||
|
&headers.member,
|
||||||
|
&headers.path,
|
||||||
|
) {
|
||||||
|
(Some(s), Some(i), Some(m), Some(p)) => (s, i, m, p),
|
||||||
|
_ => return Err(DbusError::MissingMethodCallHeaders),
|
||||||
|
};
|
||||||
|
if let Some(object) = self.socket.objects.get(path.deref()) {
|
||||||
|
let method_handler;
|
||||||
|
let handler: Option<&dyn MethodHandlerApi> =
|
||||||
|
if (interface.deref(), member.deref()) == (Get::INTERFACE, Get::MEMBER) {
|
||||||
|
Some(&PropertyGetHandlerProxy)
|
||||||
|
} else if (interface.deref(), member.deref())
|
||||||
|
== (GetAll::INTERFACE, GetAll::MEMBER)
|
||||||
|
{
|
||||||
|
Some(&PropertyGetAllHandlerProxy)
|
||||||
|
} else {
|
||||||
|
let key = MemberHandlerKey {
|
||||||
|
interface: interface.deref(),
|
||||||
|
member: member.deref(),
|
||||||
|
};
|
||||||
|
method_handler = object.methods.get(&key);
|
||||||
|
method_handler.as_ref().map(|mh| mh.deref())
|
||||||
|
};
|
||||||
|
if let Some(handler) = handler {
|
||||||
|
let sig = headers.signature.as_deref().unwrap_or("");
|
||||||
|
if sig != handler.signature() {
|
||||||
|
let msg = format!(
|
||||||
|
"Method call has an invalid signature: expected: {}, actual: {}",
|
||||||
|
handler.signature(),
|
||||||
|
sig,
|
||||||
|
);
|
||||||
|
self.socket.send_error(sender.deref(), serial, &msg);
|
||||||
|
} else {
|
||||||
|
let reply_expected = !flags.contains(NO_REPLY_EXPECTED);
|
||||||
|
if let Err(e) = handler.handle(
|
||||||
|
&object,
|
||||||
|
&self.socket,
|
||||||
|
&sender,
|
||||||
|
serial,
|
||||||
|
reply_expected,
|
||||||
|
&mut parser,
|
||||||
|
) {
|
||||||
|
log::error!(
|
||||||
|
"{}: Could not handle method call: {}",
|
||||||
|
self.socket.bus_name,
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.socket
|
||||||
|
.send_error(sender.deref(), serial, "Method does not exist");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.socket
|
||||||
|
.send_error(sender.deref(), serial, "Object does not exist");
|
||||||
|
}
|
||||||
|
}
|
||||||
MSG_METHOD_RETURN | MSG_ERROR => {
|
MSG_METHOD_RETURN | MSG_ERROR => {
|
||||||
let serial = match headers.reply_serial {
|
let serial = match headers.reply_serial {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,20 @@ use {
|
||||||
dbus::{
|
dbus::{
|
||||||
property::Get,
|
property::Get,
|
||||||
types::{ObjectPath, Signature, Variant},
|
types::{ObjectPath, Signature, Variant},
|
||||||
AsyncProperty, AsyncReply, AsyncReplySlot, DbusError, DbusSocket, DbusType, Formatter,
|
AsyncProperty, AsyncReply, AsyncReplySlot, DbusError, DbusObject, DbusObjectData,
|
||||||
Headers, InterfaceSignalHandlers, Message, MethodCall, Parser, Property, Reply,
|
DbusSocket, DbusType, ErrorMessage, Formatter, Headers, InterfaceSignalHandlers,
|
||||||
ReplyHandler, Signal, SignalHandler, SignalHandlerApi, SignalHandlerData, BUS_DEST,
|
Message, MethodCall, Parser, Property, Reply, ReplyHandler, Signal, SignalHandler,
|
||||||
BUS_PATH, HDR_DESTINATION, HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_SIGNATURE,
|
SignalHandlerApi, SignalHandlerData, BUS_DEST, BUS_PATH, HDR_DESTINATION,
|
||||||
HDR_UNIX_FDS, MSG_METHOD_CALL, NO_REPLY_EXPECTED,
|
HDR_ERROR_NAME, HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_REPLY_SERIAL, HDR_SIGNATURE,
|
||||||
|
HDR_UNIX_FDS, MSG_ERROR, MSG_METHOD_CALL, MSG_METHOD_RETURN, MSG_SIGNAL,
|
||||||
|
NO_REPLY_EXPECTED,
|
||||||
},
|
},
|
||||||
utils::{bufio::BufIoMessage, errorfmt::ErrorFmt},
|
utils::{bufio::BufIoMessage, errorfmt::ErrorFmt},
|
||||||
wire_dbus::org,
|
wire_dbus::org,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::Cell, collections::hash_map::Entry, fmt::Write, marker::PhantomData, mem,
|
borrow::Cow, cell::Cell, collections::hash_map::Entry, fmt::Write, marker::PhantomData,
|
||||||
ops::DerefMut, rc::Rc,
|
mem, ops::DerefMut, rc::Rc,
|
||||||
},
|
},
|
||||||
uapi::c,
|
uapi::c,
|
||||||
};
|
};
|
||||||
|
|
@ -26,6 +28,7 @@ impl DbusSocket {
|
||||||
self.outgoing_.take();
|
self.outgoing_.take();
|
||||||
self.reply_handlers.clear();
|
self.reply_handlers.clear();
|
||||||
self.signal_handlers.borrow_mut().clear();
|
self.signal_handlers.borrow_mut().clear();
|
||||||
|
self.objects.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn kill(self: &Rc<Self>) {
|
pub(super) fn kill(self: &Rc<Self>) {
|
||||||
|
|
@ -132,6 +135,29 @@ impl DbusSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn add_object(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
object: impl Into<Cow<'static, str>>,
|
||||||
|
) -> Result<DbusObject, DbusError> {
|
||||||
|
let object = object.into();
|
||||||
|
let data = Rc::new(DbusObjectData {
|
||||||
|
path: object.clone(),
|
||||||
|
methods: Default::default(),
|
||||||
|
properties: Default::default(),
|
||||||
|
});
|
||||||
|
match self.objects.lock().entry(object) {
|
||||||
|
Entry::Occupied(_) => Err(DbusError::AlreadyHandled),
|
||||||
|
Entry::Vacant(v) => {
|
||||||
|
v.insert(data.clone());
|
||||||
|
Ok(DbusObject {
|
||||||
|
socket: self.clone(),
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn handle_signal<T, F>(
|
pub fn handle_signal<T, F>(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
|
|
@ -245,6 +271,30 @@ impl DbusSocket {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn emit_signal<'a, T: Signal<'a>>(&self, path: &str, msg: &T) -> u32 {
|
||||||
|
let (msg, serial) = self.format_signal(path, msg);
|
||||||
|
self.bufio.send(msg);
|
||||||
|
serial
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_error(&self, destination: &str, reply_serial: u32, msg: &str) -> u32 {
|
||||||
|
let (msg, serial) = self.format_error(destination, reply_serial, msg);
|
||||||
|
self.bufio.send(msg);
|
||||||
|
serial
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_reply<'a, T: Message<'a>>(
|
||||||
|
&self,
|
||||||
|
destination: &str,
|
||||||
|
reply_serial: u32,
|
||||||
|
msg: &T,
|
||||||
|
) -> u32 {
|
||||||
|
let (msg, serial) = self.format_reply(destination, reply_serial, msg);
|
||||||
|
self.bufio.send(msg);
|
||||||
|
serial
|
||||||
|
}
|
||||||
|
|
||||||
fn send_call<'a, T: Message<'a>>(
|
fn send_call<'a, T: Message<'a>>(
|
||||||
&self,
|
&self,
|
||||||
path: &str,
|
path: &str,
|
||||||
|
|
@ -257,26 +307,99 @@ impl DbusSocket {
|
||||||
serial
|
serial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_signal<'a, T: Signal<'a>>(&self, path: &str, msg: &T) -> (BufIoMessage, u32) {
|
||||||
|
self.format_generic(MSG_SIGNAL, Some(path), None, None, 0, msg, None, true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_error(&self, destination: &str, reply_serial: u32, msg: &str) -> (BufIoMessage, u32) {
|
||||||
|
let em = ErrorMessage { msg: msg.into() };
|
||||||
|
self.format_generic(
|
||||||
|
MSG_ERROR,
|
||||||
|
None,
|
||||||
|
Some(reply_serial),
|
||||||
|
Some(destination),
|
||||||
|
0,
|
||||||
|
&em,
|
||||||
|
Some("jay.Error"),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_reply<'a, T: Message<'a>>(
|
||||||
|
&self,
|
||||||
|
destination: &str,
|
||||||
|
reply_serial: u32,
|
||||||
|
msg: &T,
|
||||||
|
) -> (BufIoMessage, u32) {
|
||||||
|
self.format_generic(
|
||||||
|
MSG_METHOD_RETURN,
|
||||||
|
None,
|
||||||
|
Some(reply_serial),
|
||||||
|
Some(destination),
|
||||||
|
0,
|
||||||
|
msg,
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn format_call<'a, T: Message<'a>>(
|
fn format_call<'a, T: Message<'a>>(
|
||||||
&self,
|
&self,
|
||||||
path: &str,
|
path: &str,
|
||||||
destination: &str,
|
destination: &str,
|
||||||
flags: u8,
|
flags: u8,
|
||||||
msg: &T,
|
msg: &T,
|
||||||
|
) -> (BufIoMessage, u32) {
|
||||||
|
self.format_generic(
|
||||||
|
MSG_METHOD_CALL,
|
||||||
|
Some(path),
|
||||||
|
None,
|
||||||
|
Some(destination),
|
||||||
|
flags,
|
||||||
|
msg,
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_generic<'a, T: Message<'a>>(
|
||||||
|
&self,
|
||||||
|
ty: u8,
|
||||||
|
path: Option<&str>,
|
||||||
|
reply_serial: Option<u32>,
|
||||||
|
destination: Option<&str>,
|
||||||
|
flags: u8,
|
||||||
|
msg: &T,
|
||||||
|
error_name: Option<&str>,
|
||||||
|
include_interface: bool,
|
||||||
|
include_member: bool,
|
||||||
) -> (BufIoMessage, u32) {
|
) -> (BufIoMessage, u32) {
|
||||||
let num_fds = msg.num_fds();
|
let num_fds = msg.num_fds();
|
||||||
let mut fds = Vec::with_capacity(num_fds as _);
|
let mut fds = Vec::with_capacity(num_fds as _);
|
||||||
let serial = self.serial();
|
let serial = self.serial();
|
||||||
let mut buf = self.bufio.buf();
|
let mut buf = self.bufio.buf();
|
||||||
let mut fmt = Formatter::new(&mut fds, &mut buf);
|
let mut fmt = Formatter::new(&mut fds, &mut buf);
|
||||||
|
let interface = match include_interface {
|
||||||
|
true => Some(T::INTERFACE),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let member = match include_member {
|
||||||
|
true => Some(T::MEMBER),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
self.format_header(
|
self.format_header(
|
||||||
&mut fmt,
|
&mut fmt,
|
||||||
MSG_METHOD_CALL,
|
ty,
|
||||||
flags,
|
flags,
|
||||||
serial,
|
serial,
|
||||||
|
reply_serial,
|
||||||
path,
|
path,
|
||||||
T::INTERFACE,
|
error_name,
|
||||||
T::MEMBER,
|
interface,
|
||||||
|
member,
|
||||||
destination,
|
destination,
|
||||||
T::SIGNATURE,
|
T::SIGNATURE,
|
||||||
num_fds,
|
num_fds,
|
||||||
|
|
@ -294,10 +417,12 @@ impl DbusSocket {
|
||||||
ty: u8,
|
ty: u8,
|
||||||
flags: u8,
|
flags: u8,
|
||||||
serial: u32,
|
serial: u32,
|
||||||
path: &str,
|
reply_serial: Option<u32>,
|
||||||
interface: &str,
|
path: Option<&str>,
|
||||||
member: &str,
|
error_name: Option<&str>,
|
||||||
destination: &str,
|
interface: Option<&str>,
|
||||||
|
member: Option<&str>,
|
||||||
|
destination: Option<&str>,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
fds: u32,
|
fds: u32,
|
||||||
) {
|
) {
|
||||||
|
|
@ -312,10 +437,24 @@ impl DbusSocket {
|
||||||
serial.marshal(fmt);
|
serial.marshal(fmt);
|
||||||
let mut headers = self.headers.borrow_mut();
|
let mut headers = self.headers.borrow_mut();
|
||||||
let mut headers = headers.take_as::<(u8, Variant)>();
|
let mut headers = headers.take_as::<(u8, Variant)>();
|
||||||
headers.push((HDR_PATH, Variant::ObjectPath(ObjectPath(path.into()))));
|
if let Some(path) = path {
|
||||||
headers.push((HDR_INTERFACE, Variant::String(interface.into())));
|
headers.push((HDR_PATH, Variant::ObjectPath(ObjectPath(path.into()))));
|
||||||
headers.push((HDR_MEMBER, Variant::String(member.into())));
|
}
|
||||||
headers.push((HDR_DESTINATION, Variant::String(destination.into())));
|
if let Some(interface) = interface {
|
||||||
|
headers.push((HDR_INTERFACE, Variant::String(interface.into())));
|
||||||
|
}
|
||||||
|
if let Some(member) = member {
|
||||||
|
headers.push((HDR_MEMBER, Variant::String(member.into())));
|
||||||
|
}
|
||||||
|
if let Some(error_name) = error_name {
|
||||||
|
headers.push((HDR_ERROR_NAME, Variant::String(error_name.into())));
|
||||||
|
}
|
||||||
|
if let Some(destination) = destination {
|
||||||
|
headers.push((HDR_DESTINATION, Variant::String(destination.into())));
|
||||||
|
}
|
||||||
|
if let Some(rs) = reply_serial {
|
||||||
|
headers.push((HDR_REPLY_SERIAL, Variant::U32(rs)));
|
||||||
|
}
|
||||||
if signature.len() > 0 {
|
if signature.len() > 0 {
|
||||||
headers.push((
|
headers.push((
|
||||||
HDR_SIGNATURE,
|
HDR_SIGNATURE,
|
||||||
|
|
|
||||||
|
|
@ -497,6 +497,32 @@ impl<'a> Variant<'a> {
|
||||||
};
|
};
|
||||||
w.push(c);
|
w.push(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn borrow<'b>(&'b self) -> Variant<'b> {
|
||||||
|
match self {
|
||||||
|
Variant::U8(v) => Variant::U8(*v),
|
||||||
|
Variant::Bool(v) => Variant::Bool(*v),
|
||||||
|
Variant::I16(v) => Variant::I16(*v),
|
||||||
|
Variant::U16(v) => Variant::U16(*v),
|
||||||
|
Variant::I32(v) => Variant::I32(*v),
|
||||||
|
Variant::U32(v) => Variant::U32(*v),
|
||||||
|
Variant::I64(v) => Variant::I64(*v),
|
||||||
|
Variant::U64(v) => Variant::U64(*v),
|
||||||
|
Variant::F64(v) => Variant::F64(*v),
|
||||||
|
Variant::String(v) => Variant::String(v.deref().into()),
|
||||||
|
Variant::ObjectPath(v) => Variant::ObjectPath(ObjectPath(v.0.deref().into())),
|
||||||
|
Variant::Signature(v) => Variant::Signature(Signature(v.0.deref().into())),
|
||||||
|
Variant::Variant(v) => Variant::Variant(Box::new(v.deref().borrow())),
|
||||||
|
Variant::Fd(v) => Variant::Fd(v.clone()),
|
||||||
|
Variant::Array(t, v) => {
|
||||||
|
Variant::Array(t.clone(), v.iter().map(|v| v.borrow()).collect())
|
||||||
|
}
|
||||||
|
Variant::DictEntry(k, v) => {
|
||||||
|
Variant::DictEntry(Box::new(k.deref().borrow()), Box::new(v.deref().borrow()))
|
||||||
|
}
|
||||||
|
Variant::Struct(v) => Variant::Struct(v.iter().map(|v| v.borrow()).collect()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a> DbusType<'a> for Variant<'a> {
|
unsafe impl<'a> DbusType<'a> for Variant<'a> {
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,9 @@ fn Set(interface_name: string, property_name: string, value: variant) {
|
||||||
fn GetAll(interface_name: string) {
|
fn GetAll(interface_name: string) {
|
||||||
props: array(dict(string, variant)),
|
props: array(dict(string, variant)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sig PropertiesChanged {
|
||||||
|
interface_name: string,
|
||||||
|
changed_properties: array(dict(string, variant)),
|
||||||
|
invalidated_properties: array(string),
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,3 +7,7 @@ fn AddMatch(rule: string) { }
|
||||||
fn RemoveMatch(rule: string) { }
|
fn RemoveMatch(rule: string) { }
|
||||||
|
|
||||||
fn UpdateActivationEnvironment(environment: array(dict(string, string))) { }
|
fn UpdateActivationEnvironment(environment: array(dict(string, string))) { }
|
||||||
|
|
||||||
|
fn RequestName(name: string, flags: u32) {
|
||||||
|
rv: u32,
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue