dbus: expose more functionality
This commit is contained in:
parent
fc9795cb5d
commit
f84b4619ba
8 changed files with 605 additions and 25 deletions
|
|
@ -70,6 +70,7 @@ fn connect(
|
|||
headers: Default::default(),
|
||||
run_toplevel: run_toplevel.clone(),
|
||||
signal_handlers: Default::default(),
|
||||
objects: Default::default(),
|
||||
});
|
||||
let skt = socket.clone();
|
||||
socket.call(
|
||||
|
|
|
|||
|
|
@ -5,14 +5,17 @@ use {
|
|||
},
|
||||
crate::{
|
||||
dbus::{
|
||||
CallError, DbusError, DbusSocket, Headers, Parser, MSG_ERROR, MSG_METHOD_RETURN,
|
||||
MSG_SIGNAL,
|
||||
CallError, DbusError, DbusSocket, Headers, MemberHandlerKey, Message, MethodHandlerApi,
|
||||
Parser, PropertyGetAllHandlerProxy, PropertyGetHandlerProxy, MSG_ERROR,
|
||||
MSG_METHOD_CALL, MSG_METHOD_RETURN, MSG_SIGNAL, NO_REPLY_EXPECTED,
|
||||
},
|
||||
utils::{
|
||||
bitflags::BitflagsExt,
|
||||
bufio::BufIoIncoming,
|
||||
errorfmt::ErrorFmt,
|
||||
ptr_ext::{MutPtrExt, PtrExt},
|
||||
},
|
||||
wire_dbus::org::freedesktop::dbus::properties::{Get, GetAll},
|
||||
},
|
||||
std::{cell::UnsafeCell, ops::Deref, rc::Rc},
|
||||
};
|
||||
|
|
@ -60,14 +63,14 @@ impl Incoming {
|
|||
return Err(DbusError::InvalidEndianess);
|
||||
}
|
||||
let msg_ty = msg_buf[1];
|
||||
let _flags = msg_buf[2];
|
||||
let flags = msg_buf[2];
|
||||
let protocol = msg_buf[3];
|
||||
if protocol != 1 {
|
||||
return Err(DbusError::InvalidProtocol);
|
||||
}
|
||||
let mut fields2 = [0u32; 3];
|
||||
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 remaining = dyn_header_len + body_len;
|
||||
self.incoming
|
||||
|
|
@ -89,6 +92,68 @@ impl Incoming {
|
|||
fds: &fds,
|
||||
};
|
||||
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 => {
|
||||
let serial = match headers.reply_serial {
|
||||
Some(s) => s,
|
||||
|
|
|
|||
|
|
@ -3,18 +3,20 @@ use {
|
|||
dbus::{
|
||||
property::Get,
|
||||
types::{ObjectPath, Signature, Variant},
|
||||
AsyncProperty, AsyncReply, AsyncReplySlot, DbusError, DbusSocket, DbusType, Formatter,
|
||||
Headers, InterfaceSignalHandlers, Message, MethodCall, Parser, Property, Reply,
|
||||
ReplyHandler, Signal, SignalHandler, SignalHandlerApi, SignalHandlerData, BUS_DEST,
|
||||
BUS_PATH, HDR_DESTINATION, HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_SIGNATURE,
|
||||
HDR_UNIX_FDS, MSG_METHOD_CALL, NO_REPLY_EXPECTED,
|
||||
AsyncProperty, AsyncReply, AsyncReplySlot, DbusError, DbusObject, DbusObjectData,
|
||||
DbusSocket, DbusType, ErrorMessage, Formatter, Headers, InterfaceSignalHandlers,
|
||||
Message, MethodCall, Parser, Property, Reply, ReplyHandler, Signal, SignalHandler,
|
||||
SignalHandlerApi, SignalHandlerData, BUS_DEST, BUS_PATH, HDR_DESTINATION,
|
||||
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},
|
||||
wire_dbus::org,
|
||||
},
|
||||
std::{
|
||||
cell::Cell, collections::hash_map::Entry, fmt::Write, marker::PhantomData, mem,
|
||||
ops::DerefMut, rc::Rc,
|
||||
borrow::Cow, cell::Cell, collections::hash_map::Entry, fmt::Write, marker::PhantomData,
|
||||
mem, ops::DerefMut, rc::Rc,
|
||||
},
|
||||
uapi::c,
|
||||
};
|
||||
|
|
@ -26,6 +28,7 @@ impl DbusSocket {
|
|||
self.outgoing_.take();
|
||||
self.reply_handlers.clear();
|
||||
self.signal_handlers.borrow_mut().clear();
|
||||
self.objects.clear();
|
||||
}
|
||||
|
||||
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)]
|
||||
pub fn handle_signal<T, F>(
|
||||
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>>(
|
||||
&self,
|
||||
path: &str,
|
||||
|
|
@ -257,26 +307,99 @@ impl DbusSocket {
|
|||
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>>(
|
||||
&self,
|
||||
path: &str,
|
||||
destination: &str,
|
||||
flags: u8,
|
||||
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) {
|
||||
let num_fds = msg.num_fds();
|
||||
let mut fds = Vec::with_capacity(num_fds as _);
|
||||
let serial = self.serial();
|
||||
let mut buf = self.bufio.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(
|
||||
&mut fmt,
|
||||
MSG_METHOD_CALL,
|
||||
ty,
|
||||
flags,
|
||||
serial,
|
||||
reply_serial,
|
||||
path,
|
||||
T::INTERFACE,
|
||||
T::MEMBER,
|
||||
error_name,
|
||||
interface,
|
||||
member,
|
||||
destination,
|
||||
T::SIGNATURE,
|
||||
num_fds,
|
||||
|
|
@ -294,10 +417,12 @@ impl DbusSocket {
|
|||
ty: u8,
|
||||
flags: u8,
|
||||
serial: u32,
|
||||
path: &str,
|
||||
interface: &str,
|
||||
member: &str,
|
||||
destination: &str,
|
||||
reply_serial: Option<u32>,
|
||||
path: Option<&str>,
|
||||
error_name: Option<&str>,
|
||||
interface: Option<&str>,
|
||||
member: Option<&str>,
|
||||
destination: Option<&str>,
|
||||
signature: &str,
|
||||
fds: u32,
|
||||
) {
|
||||
|
|
@ -312,10 +437,24 @@ impl DbusSocket {
|
|||
serial.marshal(fmt);
|
||||
let mut headers = self.headers.borrow_mut();
|
||||
let mut headers = headers.take_as::<(u8, Variant)>();
|
||||
headers.push((HDR_PATH, Variant::ObjectPath(ObjectPath(path.into()))));
|
||||
headers.push((HDR_INTERFACE, Variant::String(interface.into())));
|
||||
headers.push((HDR_MEMBER, Variant::String(member.into())));
|
||||
headers.push((HDR_DESTINATION, Variant::String(destination.into())));
|
||||
if let Some(path) = path {
|
||||
headers.push((HDR_PATH, Variant::ObjectPath(ObjectPath(path.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 {
|
||||
headers.push((
|
||||
HDR_SIGNATURE,
|
||||
|
|
|
|||
|
|
@ -497,6 +497,32 @@ impl<'a> Variant<'a> {
|
|||
};
|
||||
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> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue