1
0
Fork 0
forked from wry/wry

autocommit 2022-02-27 01:35:49 CET

This commit is contained in:
Julian Orth 2022-02-27 01:35:49 +01:00
parent 6e466360a8
commit db88f2db42
26 changed files with 2696 additions and 6 deletions

112
src/dbus/auth.rs Normal file
View file

@ -0,0 +1,112 @@
use crate::dbus::incoming::handle_incoming;
use crate::dbus::outgoing::handle_outgoing;
use crate::dbus::{DbusError, DbusSocket};
use crate::utils::hex;
use crate::ErrorFmt;
use std::io::Write;
use std::rc::Rc;
use uapi::{c, Errno};
pub(super) async fn handle_auth(socket: Rc<DbusSocket>) {
let mut auth = Auth {
socket: socket.clone(),
buf: Box::new([0; BUF_SIZE]),
buf_start: 0,
buf_stop: 0,
};
auth.run().await;
}
const BUF_SIZE: usize = 128;
struct Auth {
socket: Rc<DbusSocket>,
buf: Box<[u8; BUF_SIZE]>,
buf_start: usize,
buf_stop: usize,
}
impl Auth {
async fn run(&mut self) {
if let Err(e) = self.handle_auth().await {
log::error!("Could not authenticate to dbus socket: {}", ErrorFmt(e));
self.socket.dead.set(true);
self.socket.auth.take();
return;
}
log::info!("Authenticated");
self.socket.incoming.set(Some(
self.socket.eng.spawn(handle_incoming(self.socket.clone())),
));
self.socket.outgoing_.set(Some(
self.socket.eng.spawn(handle_outgoing(self.socket.clone())),
));
self.socket.auth.take();
}
async fn handle_auth(&mut self) -> Result<(), DbusError> {
let uid = hex::to_hex(&uapi::getuid().to_string());
let mut out_buf = Vec::new();
let _ = write!(out_buf, "\0AUTH EXTERNAL {}\r\n", uid);
self.write_buf(&mut out_buf).await?;
let line = self.readline().await?;
let (cmd, _) = line_to_cmd(&line);
if cmd != "OK" {
return Err(DbusError::Auth);
}
let _ = write!(out_buf, "NEGOTIATE_UNIX_FD\r\n");
self.write_buf(&mut out_buf).await?;
let line = self.readline().await?;
let (cmd, _) = line_to_cmd(&line);
if cmd != "AGREE_UNIX_FD" {
return Err(DbusError::UnixFd);
}
let _ = write!(out_buf, "BEGIN\r\n");
self.write_buf(&mut out_buf).await?;
Ok(())
}
async fn readline(&mut self) -> Result<String, DbusError> {
let mut s = String::new();
loop {
for i in self.buf_start..self.buf_stop {
let c = self.buf[i % BUF_SIZE] as char;
s.push(c);
if c == '\n' {
self.buf_start = i + 1;
return Ok(s);
}
}
self.buf_start = 0;
self.buf_stop = 0;
match uapi::read(self.socket.fd.raw(), &mut self.buf[..]) {
Ok(n) => self.buf_stop = n.len(),
Err(Errno(c::EAGAIN)) => {
let _ = self.socket.fd.readable().await;
}
Err(e) => return Err(DbusError::ReadError(e.into())),
}
}
}
async fn write_buf(&mut self, buf: &mut Vec<u8>) -> Result<(), DbusError> {
let mut start = 0;
while start < buf.len() {
match uapi::write(self.socket.fd.raw(), &buf[start..]) {
Ok(n) => start += n,
Err(Errno(c::EAGAIN)) => {
let _ = self.socket.fd.writable().await;
}
Err(e) => return Err(DbusError::WriteError(e.into())),
}
}
buf.clear();
Ok(())
}
}
fn line_to_cmd(line: &str) -> (&str, &str) {
let line = line.trim();
line.split_once(' ').unwrap_or((line, ""))
}

182
src/dbus/dynamic_type.rs Normal file
View file

@ -0,0 +1,182 @@
use super::{
TY_ARRAY, TY_BOOLEAN, TY_BYTE, TY_DOUBLE, TY_INT16, TY_INT32, TY_INT64, TY_OBJECT_PATH,
TY_SIGNATURE, TY_STRING, TY_UINT16, TY_UINT32, TY_UINT64, TY_UNIX_FD, TY_VARIANT,
};
use crate::dbus::types::Variant;
use crate::dbus::{DbusError, DynamicType, Parser};
use std::ops::Deref;
impl DynamicType {
pub fn from_signature<'a>(mut s: &'a [u8]) -> Result<(DynamicType, &'a [u8]), DbusError> {
if s.is_empty() {
return Err(DbusError::EmptySignature);
}
let first = s[0];
s = &s[1..];
let dp = match first {
TY_BYTE => DynamicType::U8,
TY_BOOLEAN => DynamicType::Bool,
TY_INT16 => DynamicType::I16,
TY_UINT16 => DynamicType::U16,
TY_INT32 => DynamicType::I32,
TY_UINT32 => DynamicType::U32,
TY_INT64 => DynamicType::I64,
TY_UINT64 => DynamicType::U64,
TY_DOUBLE => DynamicType::F64,
TY_STRING => DynamicType::String,
TY_OBJECT_PATH => DynamicType::ObjectPath,
TY_SIGNATURE => DynamicType::Signature,
TY_VARIANT => DynamicType::Variant,
TY_UNIX_FD => DynamicType::Fd,
TY_ARRAY => {
let (elty, rem) = Self::from_signature(s)?;
s = rem;
DynamicType::Array(Box::new(elty))
}
b'{' => {
let (keyty, rem) = Self::from_signature(s)?;
let (valty, rem) = Self::from_signature(rem)?;
if rem.is_empty() {
return Err(DbusError::UnterminatedDict);
}
if rem[0] != b'}' {
return Err(DbusError::DictTrailing);
}
s = &rem[1..];
DynamicType::DictEntry(Box::new(keyty), Box::new(valty))
}
b'(' => {
let mut fields = vec![];
loop {
if s.is_empty() {
return Err(DbusError::UnterminatedStruct);
}
if s[0] == b')' {
s = &s[1..];
break DynamicType::Struct(fields);
}
let (fieldty, rem) = Self::from_signature(s)?;
s = rem;
fields.push(fieldty);
}
}
_ => return Err(DbusError::UnknownType),
};
Ok((dp, s))
}
pub fn alignment(&self) -> usize {
match self {
DynamicType::U8 => 1,
DynamicType::Bool => 4,
DynamicType::I16 => 2,
DynamicType::U16 => 2,
DynamicType::I32 => 4,
DynamicType::U32 => 4,
DynamicType::I64 => 8,
DynamicType::U64 => 8,
DynamicType::F64 => 8,
DynamicType::String => 4,
DynamicType::ObjectPath => 4,
DynamicType::Signature => 1,
DynamicType::Variant => 1,
DynamicType::Array(_) => 4,
DynamicType::DictEntry(_, _) => 8,
DynamicType::Struct(_) => 8,
DynamicType::Fd => 4,
}
}
pub fn write_signature(&self, w: &mut Vec<u8>) {
let c = match self {
DynamicType::U8 => TY_BYTE,
DynamicType::Bool => TY_BOOLEAN,
DynamicType::I16 => TY_INT16,
DynamicType::U16 => TY_UINT16,
DynamicType::I32 => TY_INT32,
DynamicType::U32 => TY_UINT32,
DynamicType::I64 => TY_INT64,
DynamicType::U64 => TY_UINT64,
DynamicType::F64 => TY_DOUBLE,
DynamicType::String => TY_STRING,
DynamicType::ObjectPath => TY_OBJECT_PATH,
DynamicType::Signature => TY_SIGNATURE,
DynamicType::Variant => TY_VARIANT,
DynamicType::Fd => TY_UNIX_FD,
DynamicType::Array(el) => {
w.push(TY_ARRAY);
el.write_signature(w);
return;
}
DynamicType::DictEntry(k, v) => {
w.push(b'{');
k.write_signature(w);
v.write_signature(w);
w.push(b'}');
return;
}
DynamicType::Struct(f) => {
w.push(b'(');
for f in f {
f.write_signature(w);
}
w.push(b')');
return;
}
};
w.push(c);
}
pub fn parse<'a>(&self, parser: &mut Parser<'a>) -> Result<Variant<'a>, DbusError> {
let var = match self {
DynamicType::U8 => Variant::U8(parser.read_pod()?),
DynamicType::Bool => Variant::Bool(parser.read_bool()?),
DynamicType::I16 => Variant::I16(parser.read_pod()?),
DynamicType::U16 => Variant::U16(parser.read_pod()?),
DynamicType::I32 => Variant::I32(parser.read_pod()?),
DynamicType::U32 => Variant::U32(parser.read_pod()?),
DynamicType::I64 => Variant::I64(parser.read_pod()?),
DynamicType::U64 => Variant::U64(parser.read_pod()?),
DynamicType::F64 => Variant::F64(parser.read_pod()?),
DynamicType::String => Variant::String(parser.read_string()?),
DynamicType::ObjectPath => Variant::ObjectPath(parser.read_object_path()?),
DynamicType::Signature => Variant::Signature(parser.read_signature()?),
DynamicType::Variant => Variant::Variant(Box::new(parser.read_variant()?)),
DynamicType::Fd => Variant::Fd(parser.read_fd()?),
DynamicType::Array(el) => {
let len: u32 = parser.read_pod()?;
parser.align_to(el.alignment());
let len = len as usize;
if parser.buf.len() - parser.pos < len {
return Err(DbusError::UnexpectedEof);
}
let mut vals = vec![];
{
let mut parser = Parser {
buf: &parser.buf[..parser.pos + len],
pos: parser.pos,
fds: parser.fds,
};
while !parser.eof() {
vals.push(el.parse(&mut parser)?);
}
}
parser.pos += len;
Variant::Array(el.deref().clone(), vals)
}
DynamicType::DictEntry(k, v) => {
parser.align_to(8);
Variant::DictEntry(Box::new(k.parse(parser)?), Box::new(v.parse(parser)?))
}
DynamicType::Struct(fields) => {
let mut vals = vec![];
parser.align_to(8);
for field in fields {
vals.push(field.parse(parser)?);
}
Variant::Struct(vals)
}
};
Ok(var)
}
}

110
src/dbus/formatter.rs Normal file
View file

@ -0,0 +1,110 @@
use crate::dbus::types::Variant;
use crate::dbus::{DbusType, Formatter};
use std::rc::Rc;
use uapi::{OwnedFd, Packed};
impl<'a> Formatter<'a> {
pub fn new(fds: &'a mut Vec<Rc<OwnedFd>>, buf: &'a mut Vec<u8>) -> Self {
Self { fds, buf }
}
pub fn marshal<'b, T: DbusType<'b>>(&mut self, t: &T) {
t.marshal(self)
}
pub fn pad_to(&mut self, alignment: usize) {
static BUF: [u8; 8] = [0; 8];
let len = self.buf.len().wrapping_neg() & (alignment - 1);
self.buf.extend_from_slice(&BUF[..len]);
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn write_packed<'b, T: DbusType<'b> + Packed>(&mut self, t: &T) {
self.pad_to(T::ALIGNMENT);
self.buf.extend_from_slice(uapi::as_bytes(t));
}
pub fn write_str(&mut self, s: &str) {
self.write_packed(&(s.len() as u32));
self.buf.extend_from_slice(s.as_bytes());
self.buf.push(0);
}
pub fn write_signature(&mut self, s: &[u8]) {
self.write_packed(&(s.len() as u8));
self.buf.extend_from_slice(s);
self.buf.push(0);
}
pub fn write_array<'b, T: DbusType<'b>>(&mut self, a: &[T]) {
self.pad_to(4);
let len_pos = self.buf.len();
self.write_packed(&0u32);
self.pad_to(T::ALIGNMENT);
let start = self.buf.len();
for v in a {
v.marshal(self);
}
let len = (self.buf.len() - start) as u32;
self.buf[len_pos..len_pos + 4].copy_from_slice(uapi::as_bytes(&len));
}
pub fn write_fd(&mut self, fd: &Rc<OwnedFd>) {
self.write_packed(&(self.fds.len() as u32));
self.fds.push(fd.clone());
}
pub fn write_variant(&mut self, variant: &Variant) {
let pos = self.buf.len();
self.buf.push(0);
variant.write_signature(&mut self.buf);
self.buf.push(0);
self.buf[pos] = (self.buf.len() - pos - 2) as u8;
self.write_variant_body(variant);
}
pub fn write_variant_body(&mut self, variant: &Variant) {
match variant {
Variant::U8(v) => v.marshal(self),
Variant::Bool(v) => v.marshal(self),
Variant::I16(v) => v.marshal(self),
Variant::U16(v) => v.marshal(self),
Variant::I32(v) => v.marshal(self),
Variant::U32(v) => v.marshal(self),
Variant::I64(v) => v.marshal(self),
Variant::U64(v) => v.marshal(self),
Variant::F64(v) => v.marshal(self),
Variant::String(v) => v.marshal(self),
Variant::ObjectPath(v) => v.marshal(self),
Variant::Signature(v) => v.marshal(self),
Variant::Variant(v) => v.marshal(self),
Variant::Fd(f) => f.marshal(self),
Variant::Array(el, v) => {
self.pad_to(4);
let len_pos = self.buf.len();
self.write_packed(&0u32);
self.pad_to(el.alignment());
let start = self.buf.len();
for v in v {
self.write_variant_body(v);
}
let len = (self.buf.len() - start) as u32;
self.buf[len_pos..len_pos + 4].copy_from_slice(uapi::as_bytes(&len));
}
Variant::DictEntry(k, v) => {
self.pad_to(8);
self.write_variant_body(k);
self.write_variant_body(v);
}
Variant::Struct(f) => {
self.pad_to(8);
for v in f {
self.write_variant_body(v);
}
}
}
}
}

60
src/dbus/holder.rs Normal file
View file

@ -0,0 +1,60 @@
use crate::dbus::auth::handle_auth;
use crate::dbus::{DbusError, DbusHolder, DbusSocket};
use crate::{AsyncEngine, NumCell};
use std::cell::Cell;
use std::rc::Rc;
use uapi::c;
impl DbusHolder {
pub(super) fn get(
self: &Rc<Self>,
eng: &Rc<AsyncEngine>,
addr: &str,
) -> Result<Rc<DbusSocket>, DbusError> {
if let Some(c) = self.socket.get() {
if c.dead.get() {
self.socket.take();
} else {
return Ok(c);
}
}
let socket = connect(eng, addr)?;
self.socket.set(Some(socket.clone()));
Ok(socket)
}
}
fn connect(eng: &Rc<AsyncEngine>, addr: &str) -> Result<Rc<DbusSocket>, DbusError> {
let socket = match uapi::socket(
c::AF_UNIX,
c::SOCK_STREAM | c::SOCK_NONBLOCK | c::SOCK_CLOEXEC,
0,
) {
Ok(s) => s,
Err(e) => return Err(DbusError::Socket(e.into())),
};
let mut sadr: c::sockaddr_un = uapi::pod_zeroed();
sadr.sun_family = c::AF_UNIX as _;
let sun_path = uapi::as_bytes_mut(&mut sadr.sun_path[..]);
sun_path[..addr.len()].copy_from_slice(addr.as_bytes());
if let Err(e) = uapi::connect(socket.raw(), &sadr) {
return Err(DbusError::Connect(e.into()));
}
let socket = Rc::new(DbusSocket {
fd: eng.fd(&Rc::new(socket))?,
eng: eng.clone(),
next_serial: NumCell::new(1),
bufs: Default::default(),
outgoing: Default::default(),
waiters: Default::default(),
replies: Default::default(),
incoming: Default::default(),
outgoing_: Default::default(),
auth: Default::default(),
dead: Cell::new(false),
headers: Default::default(),
});
let future = eng.spawn(handle_auth(socket.clone()));
socket.auth.set(Some(future));
Ok(socket)
}

173
src/dbus/incoming.rs Normal file
View file

@ -0,0 +1,173 @@
use super::{
HDR_DESTINATION, HDR_ERROR_NAME, HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_REPLY_SERIAL,
HDR_SENDER, HDR_SIGNATURE, HDR_UNIX_FDS,
};
use crate::dbus::{DbusError, DbusSocket, DynamicType, Headers, Parser};
use crate::ErrorFmt;
use std::collections::VecDeque;
use std::mem::MaybeUninit;
use std::rc::Rc;
use uapi::{c, Errno, MaybeUninitSliceExt, MsghdrMut, OwnedFd};
pub async fn handle_incoming(socket: Rc<DbusSocket>) {
let mut incoming = Incoming {
socket,
msg_buf: vec![],
buf: Box::new([MaybeUninit::uninit(); 4096]),
buf_start: 0,
buf_end: 0,
fds: Default::default(),
cmsg: Box::new([MaybeUninit::uninit(); 256]),
};
incoming.run().await;
}
pub struct Incoming {
socket: Rc<DbusSocket>,
msg_buf: Vec<u8>,
buf: Box<[MaybeUninit<u8>; 4096]>,
buf_start: usize,
buf_end: usize,
fds: VecDeque<Rc<OwnedFd>>,
cmsg: Box<[MaybeUninit<u8>; 256]>,
}
impl Incoming {
async fn run(&mut self) {
loop {
if let Err(e) = self.handle_msg().await {
log::error!("Could not process an incoming message: {}", ErrorFmt(e));
self.socket.incoming.take();
self.socket.outgoing_.take();
return;
}
}
}
async fn handle_msg(&mut self) -> Result<(), DbusError> {
self.msg_buf.clear();
const FIXED_HEADER_SIZE: usize = 16;
self.fill_msg_buf(FIXED_HEADER_SIZE).await?;
let endianess = self.msg_buf[0];
if (endianess == b'l') != cfg!(target_endian = "little") {
return Err(DbusError::InvalidEndianess);
}
let msg_ty = self.msg_buf[1];
let flags = self.msg_buf[2];
let protocol = self.msg_buf[3];
if protocol != 1 {
return Err(DbusError::InvalidEndianess);
}
let mut fields2 = [0u32; 3];
uapi::pod_write(&self.msg_buf[4..], &mut fields2[..]).unwrap();
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.fill_msg_buf(remaining as usize).await?;
let headers = &self.msg_buf[FIXED_HEADER_SIZE..FIXED_HEADER_SIZE + headers_len as usize];
let headers = self.parse_headers(headers)?;
let unix_fds = headers.unix_fds.unwrap_or(0) as usize;
if self.fds.len() < unix_fds {
return Err(DbusError::TooFewFds);
}
let fds: Vec<_> = self.fds.drain(..unix_fds).collect();
let mut parser = Parser {
buf: &self.msg_buf,
pos: FIXED_HEADER_SIZE + dyn_header_len as usize,
fds: &fds,
};
log::info!("headers = {:?}", headers);
if let Some(sig) = headers.signature {
let mut sig = sig.0.as_bytes();
while sig.len() > 0 {
let (dt, rem) = DynamicType::from_signature(sig)?;
sig = rem;
let val = dt.parse(&mut parser)?;
log::info!("{:?}", val);
}
}
Ok(())
}
fn parse_headers<'a>(&self, buf: &'a [u8]) -> Result<Headers<'a>, DbusError> {
let mut parser = Parser::new(buf, &[]);
let mut headers = Headers::default();
while !parser.eof() {
parser.align_to(8)?;
let ty: u8 = parser.read_pod()?;
let val = parser.read_variant()?;
match ty {
HDR_PATH => headers.path = Some(val.into_object_path()?),
HDR_INTERFACE => headers.interface = Some(val.into_string()?),
HDR_MEMBER => headers.member = Some(val.into_string()?),
HDR_ERROR_NAME => headers.error_name = Some(val.into_string()?),
HDR_REPLY_SERIAL => headers.reply_serial = Some(val.into_u32()?),
HDR_DESTINATION => headers.destination = Some(val.into_string()?),
HDR_SENDER => headers.sender = Some(val.into_string()?),
HDR_SIGNATURE => headers.signature = Some(val.into_signature()?),
HDR_UNIX_FDS => headers.unix_fds = Some(val.into_u32()?),
_ => {}
}
}
Ok(headers)
}
async fn fill_msg_buf(&mut self, mut n: usize) -> Result<(), DbusError> {
while n > 0 {
if self.buf_start == self.buf_end {
while let Err(e) = self.recvmsg() {
if e.0 != c::EAGAIN {
return Err(DbusError::ReadError(e.into()));
}
let _ = self.socket.fd.readable().await;
}
if self.buf_start == self.buf_end {
return Err(DbusError::Closed);
}
}
let read = n.min(self.buf_end - self.buf_start);
let buf_start = self.buf_start % self.buf.len();
unsafe {
if buf_start + read <= self.buf.len() {
self.msg_buf.extend_from_slice(
self.buf[buf_start..buf_start + read].slice_assume_init_ref(),
);
} else {
self.msg_buf
.extend_from_slice(self.buf[buf_start..].slice_assume_init_ref());
self.msg_buf.extend_from_slice(
self.buf[..read - (self.buf.len() - buf_start)].slice_assume_init_ref(),
);
}
}
n -= read;
self.buf_start += read;
}
Ok(())
}
fn recvmsg(&mut self) -> Result<(), Errno> {
self.buf_start = 0;
self.buf_end = 0;
let mut iov = [&mut self.buf[..]];
let mut hdr = MsghdrMut {
iov: &mut iov[..],
control: Some(&mut self.cmsg[..]),
name: uapi::sockaddr_none_mut(),
flags: 0,
};
let (ivec, _, mut cmsg) =
uapi::recvmsg(self.socket.fd.raw(), &mut hdr, c::MSG_CMSG_CLOEXEC)?;
self.buf_end += ivec.len();
while cmsg.len() > 0 {
let (_, hdr, body) = uapi::cmsg_read(&mut cmsg)?;
if hdr.cmsg_level == c::SOL_SOCKET && hdr.cmsg_type == c::SCM_RIGHTS {
for fd in uapi::pod_iter(body)? {
self.fds.push_back(Rc::new(OwnedFd::new(fd)));
}
}
}
Ok(())
}
}

102
src/dbus/outgoing.rs Normal file
View file

@ -0,0 +1,102 @@
use crate::dbus::{DbusMessage, DbusSocket};
use crate::utils::vec_ext::VecExt;
use crate::utils::vecstorage::VecStorage;
use std::collections::VecDeque;
use std::mem;
use std::ptr::NonNull;
use std::rc::Rc;
use uapi::{c, Errno, Msghdr};
pub async fn handle_outgoing(socket: Rc<DbusSocket>) {
let mut outgoing = Outgoing {
socket,
msgs: Default::default(),
cmsg: vec![],
fds: vec![],
iovecs: Default::default(),
};
outgoing.run().await
}
struct DbusMessageOffset {
msg: DbusMessage,
offset: usize,
}
struct Outgoing {
socket: Rc<DbusSocket>,
msgs: VecDeque<DbusMessageOffset>,
cmsg: Vec<u8>,
fds: Vec<c::c_int>,
iovecs: VecStorage<NonNull<[u8]>>,
}
impl Outgoing {
async fn run(&mut self) {
loop {
self.socket.outgoing.non_empty().await;
while let Err(e) = self.try_flush() {
if e != Errno(c::EAGAIN) {}
let _ = self.socket.fd.writable().await;
}
}
}
fn try_flush(&mut self) -> Result<(), Errno> {
loop {
while let Some(msg) = self.socket.outgoing.try_pop() {
self.msgs.push_back(DbusMessageOffset { msg, offset: 0 });
}
if self.msgs.is_empty() {
return Ok(());
}
let mut iovecs = self.iovecs.take_as();
let mut fds = &[][..];
for msg in &mut self.msgs {
if msg.msg.fds.len() > 0 {
if fds.len() > 0 || iovecs.len() > 0 {
break;
}
fds = &msg.msg.fds;
}
iovecs.push(&msg.msg.buf[msg.offset..]);
}
self.cmsg.clear();
if fds.len() > 0 {
self.fds.clear();
self.fds.extend(fds.iter().map(|f| f.raw()));
let cmsg_space = uapi::cmsg_space(fds.len() * mem::size_of::<c::c_int>());
self.cmsg.reserve(cmsg_space);
let (_, mut spare) = self.cmsg.split_at_spare_mut_ext();
let hdr = c::cmsghdr {
cmsg_len: 0,
cmsg_level: c::SOL_SOCKET,
cmsg_type: c::SCM_RIGHTS,
};
let len = uapi::cmsg_write(&mut spare, hdr, &self.fds).unwrap();
unsafe {
self.cmsg.set_len(len);
}
}
let msg = Msghdr {
iov: &iovecs[..],
control: Some(&self.cmsg[..]),
name: uapi::sockaddr_none_ref(),
};
let mut n = uapi::sendmsg(self.socket.fd.raw(), &msg, c::MSG_DONTWAIT)?;
drop(iovecs);
self.msgs[0].msg.fds.clear();
while n > 0 {
let len = self.msgs[0].msg.buf.len() - self.msgs[0].offset;
if n < len {
self.msgs[0].offset += n;
break;
}
n -= len;
let msg = self.msgs.pop_front().unwrap();
self.socket.bufs.push(msg.msg.buf);
}
}
}
}

131
src/dbus/parser.rs Normal file
View file

@ -0,0 +1,131 @@
use crate::dbus::types::{Bool, ObjectPath, Signature, Variant, FALSE, TRUE};
use crate::dbus::{DbusError, DbusType, DynamicType, Parser};
use bstr::ByteSlice;
use std::borrow::Cow;
use std::mem;
use std::rc::Rc;
use uapi::{OwnedFd, Pod};
impl<'a> Parser<'a> {
pub fn new(buf: &'a [u8], fds: &'a [Rc<OwnedFd>]) -> Self {
Self { buf, pos: 0, fds }
}
pub fn eof(&self) -> bool {
self.pos == self.buf.len()
}
pub fn unmarshal<T: DbusType<'a>>(&mut self) -> Result<T, DbusError> {
T::unmarshal(self)
}
pub fn align_to(&mut self, n: usize) -> Result<(), DbusError> {
let new = self.pos + (self.pos.wrapping_neg() & (n - 1));
if new > self.buf.len() {
return Err(DbusError::UnexpectedEof);
}
self.pos = new;
Ok(())
}
pub fn read_fd(&mut self) -> Result<Rc<OwnedFd>, DbusError> {
let idx: u32 = self.read_pod()?;
let idx = idx as usize;
if idx >= self.fds.len() {
return Err(DbusError::OobFds);
}
Ok(self.fds[idx].clone())
}
pub fn read_pod<'b, T: DbusType<'b> + Pod>(&mut self) -> Result<T, DbusError> {
self.align_to(T::ALIGNMENT);
match uapi::pod_read_init(&self.buf[self.pos..]) {
Ok(v) => {
self.pos += mem::size_of::<T>();
Ok(v)
}
_ => Err(DbusError::UnexpectedEof),
}
}
pub fn read_bool(&mut self) -> Result<Bool, DbusError> {
let v: u32 = self.read_pod()?;
match v {
0 => Ok(FALSE),
1 => Ok(TRUE),
_ => Err(DbusError::InvalidBoolValue),
}
}
pub fn read_object_path(&mut self) -> Result<ObjectPath<'a>, DbusError> {
self.read_string().map(ObjectPath)
}
pub fn read_string(&mut self) -> Result<Cow<'a, str>, DbusError> {
let len: u32 = self.read_pod()?;
let s = self.read_string_(len as usize)?;
Ok(Cow::Borrowed(s))
}
pub fn read_signature(&mut self) -> Result<Signature<'a>, DbusError> {
let len: u8 = self.read_pod()?;
let s = self.read_string_(len as usize)?;
Ok(Signature(Cow::Borrowed(s)))
}
fn read_string_(&mut self, len: usize) -> Result<&'a str, DbusError> {
if self.buf.len() - self.pos < len + 1 {
return Err(DbusError::UnexpectedEof);
}
let s = &self.buf[self.pos..self.pos + len];
self.pos += len + 1;
match s.to_str() {
Ok(s) => Ok(s),
_ => Err(DbusError::InvalidUtf8),
}
}
pub fn read_array<T: DbusType<'a>>(&mut self) -> Result<Cow<'a, [T]>, DbusError> {
let len: u32 = self.read_pod()?;
let len = len as usize;
self.align_to(T::ALIGNMENT)?;
if self.buf.len() - self.pos < len {
return Err(DbusError::UnexpectedEof);
}
if T::IS_POD {
if len % mem::size_of::<T>() != 0 {
return Err(DbusError::PodArrayLength);
}
let slice = unsafe {
std::slice::from_raw_parts(
self.buf[self.pos..].as_ptr() as *const T,
len / mem::size_of::<T>(),
)
};
self.pos += len;
Ok(Cow::Borrowed(slice))
} else {
let mut parser = Parser {
buf: &self.buf[..self.pos + len],
pos: self.pos,
fds: self.fds,
};
self.pos += len;
let mut res = vec![];
while !parser.eof() {
res.push(T::unmarshal(&mut parser)?);
}
Ok(Cow::Owned(res))
}
}
pub fn read_variant(&mut self) -> Result<Variant<'a>, DbusError> {
let sig = self.read_signature()?;
let sig = sig.0.as_bytes();
let (parser, rem) = DynamicType::from_signature(sig)?;
if rem.len() > 0 {
return Err(DbusError::TrailingVariantSignature);
}
parser.parse(self)
}
}

93
src/dbus/socket.rs Normal file
View file

@ -0,0 +1,93 @@
use crate::dbus::types::{ObjectPath, Signature, Variant};
use crate::dbus::{
DbusMessage, DbusSocket, DbusType, Formatter, Message, MethodCall, HDR_DESTINATION,
HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_SIGNATURE, HDR_UNIX_FDS,
};
const MESSAGE_CALL: u8 = 1;
const MESSAGE_RETURN: u8 = 2;
const ERROR: u8 = 3;
const SIGNAL: u8 = 4;
impl DbusSocket {
pub fn new() -> Self {
todo!();
}
pub fn call_noreply<'a, T: MethodCall<'a>>(&self, destination: &str, path: &str, msg: T) {
let (msg, _) = self.format_call(path, Some(destination), &msg);
self.outgoing.push(msg);
}
fn format_call<'a, T: Message<'a>>(
&self,
path: &str,
destination: Option<&str>,
msg: &T,
) -> (DbusMessage, u32) {
let num_fds = msg.num_fds();
let mut fds = Vec::with_capacity(num_fds as _);
let serial = self.next_serial.fetch_add(1);
let mut buf = self.bufs.pop().unwrap_or_default();
buf.clear();
let mut fmt = Formatter::new(&mut fds, &mut buf);
self.format_header(
&mut fmt,
MESSAGE_CALL,
serial,
path,
T::INTERFACE,
T::MEMBER,
destination,
T::SIGNATURE,
num_fds,
);
let body_start = fmt.len();
msg.marshal(&mut fmt);
let body_len = (buf.len() - body_start) as u32;
buf[4..8].copy_from_slice(uapi::as_bytes(&body_len));
(DbusMessage { fds, buf }, serial)
}
fn format_header(
&self,
fmt: &mut Formatter,
ty: u8,
serial: u32,
path: &str,
interface: &str,
member: &str,
destination: Option<&str>,
signature: &str,
fds: u32,
) {
#[cfg(target_endian = "little")]
b'l'.marshal(fmt);
#[cfg(not(target_endian = "little"))]
b'b'.marshal(fmt);
ty.marshal(fmt);
0u8.marshal(fmt);
1u8.marshal(fmt);
0u32.marshal(fmt);
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())));
if let Some(dst) = destination {
headers.push((HDR_DESTINATION, Variant::String(dst.into())));
}
if signature.len() > 0 {
headers.push((
HDR_SIGNATURE,
Variant::Signature(Signature(signature.into())),
));
}
if fds > 0 {
headers.push((HDR_UNIX_FDS, Variant::U32(fds)));
}
fmt.write_array(&headers);
fmt.pad_to(8);
}
}

466
src/dbus/types.rs Normal file
View file

@ -0,0 +1,466 @@
use crate::dbus::{
DbusError, DbusType, DynamicType, Formatter, Parser, TY_ARRAY, TY_BOOLEAN, TY_BYTE, TY_DOUBLE,
TY_INT16, TY_INT32, TY_INT64, TY_OBJECT_PATH, TY_SIGNATURE, TY_STRING, TY_UINT16, TY_UINT32,
TY_UINT64, TY_UNIX_FD, TY_VARIANT,
};
use crate::utils::aligned::{AlignedF64, AlignedI64, AlignedU64};
use std::borrow::Cow;
use std::ops::Deref;
use std::rc::Rc;
use uapi::{OwnedFd, Packed, Pod};
unsafe impl<'a> DbusType<'a> for u8 {
const ALIGNMENT: usize = 1;
const IS_POD: bool = true;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_BYTE);
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_packed(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_pod()
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)]
pub struct Bool(u32);
pub const FALSE: Bool = Bool(0);
pub const TRUE: Bool = Bool(1);
unsafe impl Pod for Bool {}
unsafe impl Packed for Bool {}
unsafe impl<'a> DbusType<'a> for Bool {
const ALIGNMENT: usize = 4;
const IS_POD: bool = true;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_BOOLEAN);
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_packed(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_bool()
}
}
unsafe impl<'a> DbusType<'a> for i16 {
const ALIGNMENT: usize = 2;
const IS_POD: bool = true;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_INT16);
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_packed(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_pod()
}
}
unsafe impl<'a> DbusType<'a> for u16 {
const ALIGNMENT: usize = 2;
const IS_POD: bool = true;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_UINT16)
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_packed(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_pod()
}
}
unsafe impl<'a> DbusType<'a> for i32 {
const ALIGNMENT: usize = 4;
const IS_POD: bool = true;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_INT32)
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_packed(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_pod()
}
}
unsafe impl<'a> DbusType<'a> for u32 {
const ALIGNMENT: usize = 4;
const IS_POD: bool = true;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_UINT32)
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_packed(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_pod()
}
}
unsafe impl<'a> DbusType<'a> for AlignedI64 {
const ALIGNMENT: usize = 8;
const IS_POD: bool = true;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_INT64)
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_packed(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_pod()
}
}
unsafe impl<'a> DbusType<'a> for AlignedU64 {
const ALIGNMENT: usize = 8;
const IS_POD: bool = true;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_UINT64)
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_packed(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_pod()
}
}
unsafe impl<'a> DbusType<'a> for AlignedF64 {
const ALIGNMENT: usize = 8;
const IS_POD: bool = true;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_DOUBLE)
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_packed(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_pod()
}
}
unsafe impl<'a> DbusType<'a> for Cow<'a, str> {
const ALIGNMENT: usize = 4;
const IS_POD: bool = false;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_STRING)
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_str(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_string()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Signature<'a>(pub Cow<'a, str>);
unsafe impl<'a> DbusType<'a> for Signature<'a> {
const ALIGNMENT: usize = 1;
const IS_POD: bool = false;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_SIGNATURE)
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_signature(self.0.as_bytes());
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_signature()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ObjectPath<'a>(pub Cow<'a, str>);
unsafe impl<'a> DbusType<'a> for ObjectPath<'a> {
const ALIGNMENT: usize = 4;
const IS_POD: bool = false;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_OBJECT_PATH)
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_str(&self.0);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_object_path()
}
}
unsafe impl<'a, T: DbusType<'a>> DbusType<'a> for Cow<'a, [T]> {
const ALIGNMENT: usize = 4;
const IS_POD: bool = false;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_ARRAY);
T::write_signature(w);
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_array(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_array()
}
fn num_fds(&self) -> u32 {
let mut res = 0;
for t in self.deref() {
res += t.num_fds();
}
res
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DictEntry<K, V> {
pub key: K,
pub value: V,
}
unsafe impl<'a, K: DbusType<'a>, V: DbusType<'a>> DbusType<'a> for DictEntry<K, V> {
const ALIGNMENT: usize = 8;
const IS_POD: bool = false;
fn write_signature(w: &mut Vec<u8>) {
w.push(b'{');
K::write_signature(w);
V::write_signature(w);
w.push(b'}');
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.pad_to(8);
self.key.marshal(fmt);
self.value.marshal(fmt);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.align_to(8)?;
Ok(Self {
key: K::unmarshal(parser)?,
value: V::unmarshal(parser)?,
})
}
}
macro_rules! tuple {
($($p:ident),*) => {
#[allow(non_snake_case)]
unsafe impl<'a, $($p: DbusType<'a>),*> DbusType<'a> for ($($p,)*) {
const ALIGNMENT: usize = 8;
const IS_POD: bool = false;
fn write_signature(w: &mut Vec<u8>) {
w.push(b'(');
$(
$p::write_signature(w);
)*
w.push(b')');
}
fn marshal(&self, fmt: &mut Formatter) {
let ($($p,)*) = self;
fmt.pad_to(8);
$(
$p.marshal(fmt);
)*
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.align_to(8)?;
Ok(($($p::unmarshal(parser)?,)*))
}
fn num_fds(&self) -> u32 {
let mut res = 0;
let ($($p,)*) = self;
$(
res += $p.num_fds();
)*
res
}
}
}
}
tuple!(A);
tuple!(A, B);
tuple!(A, B, C);
tuple!(A, B, C, D);
tuple!(A, B, C, D, E);
tuple!(A, B, C, D, E, F);
tuple!(A, B, C, D, E, F, G);
tuple!(A, B, C, D, E, F, G, H);
#[derive(Clone, Debug)]
pub enum Variant<'a> {
U8(u8),
Bool(Bool),
I16(i16),
U16(u16),
I32(i32),
U32(u32),
I64(AlignedI64),
U64(AlignedU64),
F64(AlignedF64),
String(Cow<'a, str>),
ObjectPath(ObjectPath<'a>),
Signature(Signature<'a>),
Variant(Box<Variant<'a>>),
Fd(Rc<OwnedFd>),
Array(DynamicType, Vec<Variant<'a>>),
DictEntry(Box<Variant<'a>>, Box<Variant<'a>>),
Struct(Vec<Variant<'a>>),
}
impl<'a> Variant<'a> {
pub fn into_string(self) -> Result<Cow<'a, str>, DbusError> {
match self {
Variant::String(s) => Ok(s),
_ => Err(DbusError::InvalidVariantType),
}
}
pub fn into_object_path(self) -> Result<ObjectPath<'a>, DbusError> {
match self {
Variant::ObjectPath(s) => Ok(s),
_ => Err(DbusError::InvalidVariantType),
}
}
pub fn into_signature(self) -> Result<Signature<'a>, DbusError> {
match self {
Variant::Signature(s) => Ok(s),
_ => Err(DbusError::InvalidVariantType),
}
}
pub fn into_u32(self) -> Result<u32, DbusError> {
match self {
Variant::U32(s) => Ok(s),
_ => Err(DbusError::InvalidVariantType),
}
}
pub fn write_signature(&self, w: &mut Vec<u8>) {
let c = match self {
Variant::U8(..) => TY_BYTE,
Variant::Bool(..) => TY_BOOLEAN,
Variant::I16(..) => TY_INT16,
Variant::U16(..) => TY_UINT16,
Variant::I32(..) => TY_INT32,
Variant::U32(..) => TY_UINT32,
Variant::I64(..) => TY_INT64,
Variant::U64(..) => TY_UINT64,
Variant::F64(..) => TY_DOUBLE,
Variant::String(..) => TY_STRING,
Variant::ObjectPath(..) => TY_OBJECT_PATH,
Variant::Signature(..) => TY_SIGNATURE,
Variant::Variant(..) => TY_VARIANT,
Variant::Fd(..) => TY_UNIX_FD,
Variant::Array(el, _) => {
w.push(TY_ARRAY);
el.write_signature(w);
return;
}
Variant::DictEntry(k, v) => {
w.push(b'{');
k.write_signature(w);
v.write_signature(w);
w.push(b'}');
return;
}
Variant::Struct(f) => {
w.push(b'(');
for f in f {
f.write_signature(w);
}
w.push(b')');
return;
}
};
w.push(c);
}
}
unsafe impl<'a> DbusType<'a> for Variant<'a> {
const ALIGNMENT: usize = 1;
const IS_POD: bool = false;
fn write_signature(w: &mut Vec<u8>) {
w.push(TY_VARIANT);
}
fn marshal(&self, fmt: &mut Formatter) {
fmt.write_variant(self);
}
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
parser.read_variant()
}
fn num_fds(&self) -> u32 {
match self {
Variant::U8(_) => 0,
Variant::Bool(_) => 0,
Variant::I16(_) => 0,
Variant::U16(_) => 0,
Variant::I32(_) => 0,
Variant::U32(_) => 0,
Variant::I64(_) => 0,
Variant::U64(_) => 0,
Variant::F64(_) => 0,
Variant::String(_) => 0,
Variant::ObjectPath(_) => 0,
Variant::Signature(_) => 0,
Variant::Variant(v) => v.num_fds(),
Variant::Array(_, a) => a.iter().map(|e| e.num_fds()).sum(),
Variant::DictEntry(k, v) => k.num_fds() + v.num_fds(),
Variant::Struct(f) => f.iter().map(|f| f.num_fds()).sum(),
Variant::Fd(_) => 1,
}
}
}