autocommit 2022-02-27 01:35:49 CET
This commit is contained in:
parent
6e466360a8
commit
db88f2db42
26 changed files with 2696 additions and 6 deletions
|
|
@ -4,7 +4,9 @@ use std::path::PathBuf;
|
|||
use std::{env, io};
|
||||
|
||||
mod enums;
|
||||
mod tokens;
|
||||
mod wire;
|
||||
mod wire_dbus;
|
||||
|
||||
fn open(s: &str) -> io::Result<BufWriter<File>> {
|
||||
let mut path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
|
|
@ -20,7 +22,7 @@ fn open(s: &str) -> io::Result<BufWriter<File>> {
|
|||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
wire::main()?;
|
||||
|
||||
wire_dbus::main()?;
|
||||
enums::main()?;
|
||||
|
||||
println!("cargo:rerun-if-changed=build/build.rs");
|
||||
|
|
|
|||
206
build/tokens.rs
Normal file
206
build/tokens.rs
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
use anyhow::{bail, Context, Result};
|
||||
use bstr::{BStr, ByteSlice};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum TreeDelim {
|
||||
Paren,
|
||||
Brace,
|
||||
}
|
||||
|
||||
impl TreeDelim {
|
||||
pub fn opening(self) -> u8 {
|
||||
match self {
|
||||
TreeDelim::Paren => b'(',
|
||||
TreeDelim::Brace => b'{',
|
||||
}
|
||||
}
|
||||
|
||||
pub fn closing(self) -> u8 {
|
||||
match self {
|
||||
TreeDelim::Paren => b')',
|
||||
TreeDelim::Brace => b'}',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Symbol {
|
||||
Comma,
|
||||
Colon,
|
||||
Equals,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
Symbol::Comma => "','",
|
||||
Symbol::Colon => "':'",
|
||||
Symbol::Equals => "'='",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Token<'a> {
|
||||
pub line: u32,
|
||||
pub kind: TokenKind<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TokenKind<'a> {
|
||||
Ident(&'a BStr),
|
||||
Num(u32),
|
||||
Tree {
|
||||
delim: TreeDelim,
|
||||
body: Vec<Token<'a>>,
|
||||
},
|
||||
Symbol(Symbol),
|
||||
}
|
||||
|
||||
impl TokenKind<'_> {
|
||||
pub fn name(&self) -> &str {
|
||||
match self {
|
||||
TokenKind::Ident(_) => "identifier",
|
||||
TokenKind::Num(_) => "number",
|
||||
TokenKind::Tree { delim, .. } => match delim {
|
||||
TreeDelim::Paren => "'('-tree",
|
||||
TreeDelim::Brace => "'{'-tree",
|
||||
},
|
||||
TokenKind::Symbol(s) => s.name(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Cursor<'a> {
|
||||
pos: usize,
|
||||
s: &'a [u8],
|
||||
}
|
||||
|
||||
impl Cursor<'_> {
|
||||
fn eof(&self) -> bool {
|
||||
self.pos >= self.s.len()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tokenize<'a>(s: &'a [u8]) -> Result<Vec<Token<'a>>> {
|
||||
let mut tnz = Tokenizer {
|
||||
line: 1,
|
||||
cursor: Cursor { pos: 0, s },
|
||||
delim: None,
|
||||
res: vec![],
|
||||
};
|
||||
tnz.tokenize()?;
|
||||
Ok(tnz.res)
|
||||
}
|
||||
|
||||
struct Tokenizer<'a> {
|
||||
line: u32,
|
||||
cursor: Cursor<'a>,
|
||||
delim: Option<TreeDelim>,
|
||||
res: Vec<Token<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Tokenizer<'a> {
|
||||
fn tokenize_one(&mut self) -> Result<bool> {
|
||||
let c = &mut self.cursor;
|
||||
while !c.eof() {
|
||||
let b = c.s[c.pos];
|
||||
if matches!(b, b' ' | b'\n' | b'#') {
|
||||
c.pos += 1;
|
||||
if b == b'\n' {
|
||||
self.line += 1;
|
||||
} else if b == b'#' {
|
||||
while !c.eof() {
|
||||
c.pos += 1;
|
||||
if c.s[c.pos - 1] == b'\n' {
|
||||
self.line += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if c.eof() {
|
||||
if self.delim.is_some() {
|
||||
bail!("Unexpected eof");
|
||||
}
|
||||
return Ok(false);
|
||||
}
|
||||
let line = self.line;
|
||||
let b = c.s[c.pos];
|
||||
let b_pos = c.pos;
|
||||
c.pos += 1;
|
||||
let kind = match b {
|
||||
b'a'..=b'z' | b'A'..=b'Z' => {
|
||||
while !c.eof()
|
||||
&& matches!(c.s[c.pos], b'a'..=b'z' | b'A'..=b'Z' | b'_' | b'0'..=b'9')
|
||||
{
|
||||
c.pos += 1;
|
||||
}
|
||||
TokenKind::Ident(c.s[b_pos..c.pos].as_bstr())
|
||||
}
|
||||
b'0'..=b'9' => {
|
||||
c.pos -= 1;
|
||||
let mut num = 0;
|
||||
while !c.eof() && matches!(c.s[c.pos], b'0'..=b'9') {
|
||||
num = num * 10 + (c.s[c.pos] - b'0') as u32;
|
||||
c.pos += 1;
|
||||
}
|
||||
TokenKind::Num(num)
|
||||
}
|
||||
b',' => TokenKind::Symbol(Symbol::Comma),
|
||||
b'=' => TokenKind::Symbol(Symbol::Equals),
|
||||
b':' => TokenKind::Symbol(Symbol::Colon),
|
||||
b'(' => self.tokenize_tree(TreeDelim::Paren)?,
|
||||
b'{' => self.tokenize_tree(TreeDelim::Brace)?,
|
||||
c @ (b')' | b'}') => {
|
||||
if self.delim.map(|d| d.closing()) != Some(c) {
|
||||
bail!("Unexpected '{}' in line {}", c, self.line);
|
||||
}
|
||||
return Ok(false);
|
||||
}
|
||||
_ => bail!("Unexpected byte {:?} in line {}", b as char, self.line),
|
||||
};
|
||||
self.res.push(Token { line, kind });
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn tokenize(&mut self) -> Result<()> {
|
||||
while self.tokenize_one()? {
|
||||
// nothing
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tokenize_tree(&mut self, delim: TreeDelim) -> Result<TokenKind<'a>> {
|
||||
let mut tnz = Tokenizer {
|
||||
line: self.line,
|
||||
cursor: self.cursor,
|
||||
delim: Some(delim),
|
||||
res: vec![],
|
||||
};
|
||||
tnz.tokenize().with_context(|| {
|
||||
format!(
|
||||
"While tokenizing {:?} block starting in line {}",
|
||||
delim.opening() as char,
|
||||
self.line
|
||||
)
|
||||
})?;
|
||||
self.cursor.pos = tnz.cursor.pos;
|
||||
self.line = tnz.line;
|
||||
Ok(TokenKind::Tree {
|
||||
delim,
|
||||
body: tnz.res,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Lined<T> {
|
||||
#[allow(dead_code)]
|
||||
pub line: u32,
|
||||
pub val: T,
|
||||
}
|
||||
608
build/wire_dbus.rs
Normal file
608
build/wire_dbus.rs
Normal file
|
|
@ -0,0 +1,608 @@
|
|||
use crate::open;
|
||||
use crate::tokens::{tokenize, Lined, Symbol, Token, TokenKind, TreeDelim};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use bstr::{BStr, BString, ByteSlice};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::mem;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Type {
|
||||
U8,
|
||||
Bool,
|
||||
I16,
|
||||
U16,
|
||||
I32,
|
||||
U32,
|
||||
I64,
|
||||
U64,
|
||||
F64,
|
||||
String,
|
||||
ObjectPath,
|
||||
Signature,
|
||||
Variant,
|
||||
Fd,
|
||||
Array(Box<Type>),
|
||||
DictEntry(Box<Type>, Box<Type>),
|
||||
Struct(Vec<Type>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Field {
|
||||
name: BString,
|
||||
ty: Type,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Function {
|
||||
name: BString,
|
||||
in_fields: Vec<Field>,
|
||||
out_fields: Vec<Field>,
|
||||
}
|
||||
|
||||
struct Parser<'a> {
|
||||
pos: usize,
|
||||
tokens: &'a [Token<'a>],
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn parse(&mut self) -> Result<Vec<Function>> {
|
||||
let mut res = vec![];
|
||||
while !self.eof() {
|
||||
let (line, ty) = self.expect_ident()?;
|
||||
match ty.as_bytes() {
|
||||
b"fn" => res.push(self.parse_fn()?.val),
|
||||
_ => bail!("In line {}: Unexpected entry {:?}", line, ty),
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn eof(&self) -> bool {
|
||||
self.pos == self.tokens.len()
|
||||
}
|
||||
|
||||
fn not_eof(&self) -> Result<()> {
|
||||
if self.eof() {
|
||||
bail!("Unexpected eof");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_fn(&mut self) -> Result<Lined<Function>> {
|
||||
let (line, name) = self.expect_ident()?;
|
||||
let res: Result<_> = (|| {
|
||||
let (_, body) = self.expect_tree(TreeDelim::Paren)?;
|
||||
let mut parser = Parser {
|
||||
pos: 0,
|
||||
tokens: body,
|
||||
};
|
||||
let mut in_fields = vec![];
|
||||
while !parser.eof() {
|
||||
in_fields.push(parser.parse_field()?);
|
||||
}
|
||||
let (_, body) = self.expect_tree(TreeDelim::Brace)?;
|
||||
let mut parser = Parser {
|
||||
pos: 0,
|
||||
tokens: body,
|
||||
};
|
||||
let mut out_fields = vec![];
|
||||
while !parser.eof() {
|
||||
out_fields.push(parser.parse_field()?);
|
||||
}
|
||||
Ok(Lined {
|
||||
line,
|
||||
val: Function {
|
||||
name: name.to_owned(),
|
||||
in_fields,
|
||||
out_fields,
|
||||
},
|
||||
})
|
||||
})();
|
||||
res.with_context(|| format!("While parsing message starting at line {}", line))
|
||||
}
|
||||
|
||||
fn parse_field(&mut self) -> Result<Field> {
|
||||
let (line, name) = self.expect_ident()?;
|
||||
let res: Result<_> = (|| {
|
||||
self.expect_symbol(Symbol::Colon)?;
|
||||
let ty = self.parse_type()?;
|
||||
if !self.eof() {
|
||||
self.expect_symbol(Symbol::Comma)?;
|
||||
}
|
||||
Ok(Field {
|
||||
name: name.to_owned(),
|
||||
ty,
|
||||
})
|
||||
})();
|
||||
res.with_context(|| format!("While parsing field starting at line {}", line))
|
||||
}
|
||||
|
||||
fn expect_ident(&mut self) -> Result<(u32, &'a BStr)> {
|
||||
self.not_eof()?;
|
||||
let token = &self.tokens[self.pos];
|
||||
self.pos += 1;
|
||||
match &token.kind {
|
||||
TokenKind::Ident(id) => Ok((token.line, *id)),
|
||||
k => bail!(
|
||||
"In line {}: Expected identifier, found {}",
|
||||
token.line,
|
||||
k.name()
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_symbol(&mut self, symbol: Symbol) -> Result<()> {
|
||||
self.not_eof()?;
|
||||
let token = &self.tokens[self.pos];
|
||||
self.pos += 1;
|
||||
match &token.kind {
|
||||
TokenKind::Symbol(s) if *s == symbol => Ok(()),
|
||||
k => bail!(
|
||||
"In line {}: Expected {}, found {}",
|
||||
token.line,
|
||||
symbol.name(),
|
||||
k.name()
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_tree_(&mut self) -> Result<(u32, TreeDelim, &'a [Token<'a>])> {
|
||||
self.not_eof()?;
|
||||
let token = &self.tokens[self.pos];
|
||||
self.pos += 1;
|
||||
match &token.kind {
|
||||
TokenKind::Tree { delim, body } => Ok((token.line, *delim, body)),
|
||||
k => bail!("In line {}: Expected tree, found {}", token.line, k.name()),
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_tree(&mut self, exp_delim: TreeDelim) -> Result<(u32, &'a [Token<'a>])> {
|
||||
let (line, delim, tokens) = self.expect_tree_()?;
|
||||
if delim == exp_delim {
|
||||
Ok((line, tokens))
|
||||
} else {
|
||||
bail!(
|
||||
"In line {}: Expected {:?}-delimited tree, found {:?}-delimited tree",
|
||||
line,
|
||||
exp_delim,
|
||||
delim.opening()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_type(&mut self) -> Result<Type> {
|
||||
self.not_eof()?;
|
||||
let (_, ty) = self.expect_ident()?;
|
||||
let ty = match ty.as_bytes() {
|
||||
b"u8" => Type::U8,
|
||||
b"bool" => Type::Bool,
|
||||
b"i16" => Type::I16,
|
||||
b"u16" => Type::U16,
|
||||
b"i32" => Type::I32,
|
||||
b"u32" => Type::U32,
|
||||
b"i64" => Type::I64,
|
||||
b"u64" => Type::U64,
|
||||
b"f64" => Type::F64,
|
||||
b"string" => Type::String,
|
||||
b"object_path" => Type::ObjectPath,
|
||||
b"signature" => Type::Signature,
|
||||
b"variant" => Type::Variant,
|
||||
b"fd" => Type::Fd,
|
||||
b"array" => {
|
||||
let (line, body) = self.expect_tree(TreeDelim::Paren)?;
|
||||
let mut parser = Parser {
|
||||
pos: 0,
|
||||
tokens: body,
|
||||
};
|
||||
let ty: Result<_> = (|| {
|
||||
let ty = parser.parse_type()?;
|
||||
if !parser.eof() {
|
||||
bail!("Trailing tokens in element type");
|
||||
}
|
||||
Ok(ty)
|
||||
})();
|
||||
let ty =
|
||||
ty.with_context(|| format!("While parsing array starting in line {}", line))?;
|
||||
Type::Array(Box::new(ty))
|
||||
}
|
||||
b"dict" => {
|
||||
let (line, body) = self.expect_tree(TreeDelim::Paren)?;
|
||||
let mut parser = Parser {
|
||||
pos: 0,
|
||||
tokens: body,
|
||||
};
|
||||
let ty: Result<_> = (|| {
|
||||
let key = parser.parse_type()?;
|
||||
parser.expect_symbol(Symbol::Comma)?;
|
||||
let val = parser.parse_type()?;
|
||||
Ok((key, val))
|
||||
})();
|
||||
let ty =
|
||||
ty.with_context(|| format!("While parsing dict starting in line {}", line))?;
|
||||
Type::DictEntry(Box::new(ty.0), Box::new(ty.1))
|
||||
}
|
||||
b"struct" => {
|
||||
let (line, body) = self.expect_tree(TreeDelim::Paren)?;
|
||||
let mut parser = Parser {
|
||||
pos: 0,
|
||||
tokens: body,
|
||||
};
|
||||
let mut fields = vec![];
|
||||
while !parser.eof() {
|
||||
let ty: Result<_> = (|| {
|
||||
let ty = parser.parse_type()?;
|
||||
if !parser.eof() {
|
||||
parser.expect_symbol(Symbol::Comma)?;
|
||||
}
|
||||
Ok(ty)
|
||||
})();
|
||||
let ty = ty.with_context(|| {
|
||||
format!("While parsing struct starting in line {}", line)
|
||||
})?;
|
||||
fields.push(ty);
|
||||
}
|
||||
Type::Struct(fields)
|
||||
}
|
||||
_ => bail!("Unknown type {}", ty),
|
||||
};
|
||||
Ok(ty)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_functions(s: &[u8]) -> Result<Vec<Function>> {
|
||||
let tokens = tokenize(s)?;
|
||||
let mut parser = Parser {
|
||||
pos: 0,
|
||||
tokens: &tokens,
|
||||
};
|
||||
parser.parse()
|
||||
}
|
||||
|
||||
fn to_snake(s: &BStr) -> BString {
|
||||
let mut last_was_lowercase = false;
|
||||
let mut res = vec![];
|
||||
for mut b in s.as_bytes().iter().copied() {
|
||||
if b.is_ascii_uppercase() {
|
||||
if last_was_lowercase {
|
||||
res.push(b'_');
|
||||
last_was_lowercase = false;
|
||||
}
|
||||
b = b.to_ascii_lowercase();
|
||||
} else {
|
||||
last_was_lowercase = true;
|
||||
}
|
||||
res.push(b);
|
||||
}
|
||||
res.into()
|
||||
}
|
||||
|
||||
fn needs_lifetime(ty: &Type) -> bool {
|
||||
match ty {
|
||||
Type::U8 => false,
|
||||
Type::Bool => false,
|
||||
Type::I16 => false,
|
||||
Type::U16 => false,
|
||||
Type::I32 => false,
|
||||
Type::U32 => false,
|
||||
Type::I64 => false,
|
||||
Type::U64 => false,
|
||||
Type::F64 => false,
|
||||
Type::String => true,
|
||||
Type::ObjectPath => true,
|
||||
Type::Signature => true,
|
||||
Type::Variant => true,
|
||||
Type::Fd => false,
|
||||
Type::Array(_) => true,
|
||||
Type::DictEntry(k, v) => needs_lifetime(k) || needs_lifetime(v),
|
||||
Type::Struct(fs) => fs.iter().any(needs_lifetime),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_signature<W: Write>(f: &mut W, ty: &Type) -> Result<()> {
|
||||
let c = match ty {
|
||||
Type::U8 => 'y',
|
||||
Type::Bool => 'b',
|
||||
Type::I16 => 'n',
|
||||
Type::U16 => 'q',
|
||||
Type::I32 => 'i',
|
||||
Type::U32 => 'u',
|
||||
Type::I64 => 'x',
|
||||
Type::U64 => 't',
|
||||
Type::F64 => 'd',
|
||||
Type::String => 's',
|
||||
Type::ObjectPath => 'o',
|
||||
Type::Signature => 'g',
|
||||
Type::Variant => 'v',
|
||||
Type::Fd => 'h',
|
||||
Type::Array(e) => {
|
||||
write!(f, "a")?;
|
||||
write_signature(f, e)?;
|
||||
return Ok(());
|
||||
}
|
||||
Type::DictEntry(k, v) => {
|
||||
write!(f, "{{")?;
|
||||
write_signature(f, k)?;
|
||||
write_signature(f, v)?;
|
||||
write!(f, "}}")?;
|
||||
return Ok(());
|
||||
}
|
||||
Type::Struct(fs) => {
|
||||
write!(f, "(")?;
|
||||
for fs in fs {
|
||||
write_signature(f, fs)?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
write!(f, "{}", c)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_type<W: Write>(f: &mut W, ty: &Type) -> Result<()> {
|
||||
let ty = match ty {
|
||||
Type::U8 => "u8",
|
||||
Type::Bool => "Bool",
|
||||
Type::I16 => "i16",
|
||||
Type::U16 => "u16",
|
||||
Type::I32 => "i32",
|
||||
Type::U32 => "u32",
|
||||
Type::I64 => "AlignedI64",
|
||||
Type::U64 => "AlignedU64",
|
||||
Type::F64 => "AlignedF64",
|
||||
Type::String => "Cow<'a, str>",
|
||||
Type::ObjectPath => "ObjectPath<'a>",
|
||||
Type::Signature => "Signature<'a>",
|
||||
Type::Variant => "Variant<'a>",
|
||||
Type::Fd => "Rc<OwnedFd>",
|
||||
Type::Array(e) => {
|
||||
write!(f, "Cow<'a, [")?;
|
||||
write_type(f, &e)?;
|
||||
write!(f, ">")?;
|
||||
return Ok(());
|
||||
}
|
||||
Type::DictEntry(k, v) => {
|
||||
write!(f, "DictEntry<")?;
|
||||
write_type(f, &k)?;
|
||||
write!(f, ", ")?;
|
||||
write_type(f, &v)?;
|
||||
write!(f, ">")?;
|
||||
return Ok(());
|
||||
}
|
||||
Type::Struct(fs) => {
|
||||
write!(f, "(")?;
|
||||
for (idx, fs) in fs.iter().enumerate() {
|
||||
if idx > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write_type(f, &fs)?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
write!(f, "{}", ty)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_message<W: Write>(
|
||||
f: &mut W,
|
||||
el: &Element,
|
||||
fun: &Function,
|
||||
name: &str,
|
||||
indent: &str,
|
||||
fields: &[Field],
|
||||
reply_name: Option<&str>,
|
||||
reply_has_lt: bool,
|
||||
) -> Result<()> {
|
||||
let needs_lt = fields.iter().any(|f| needs_lifetime(&f.ty));
|
||||
let lt = if needs_lt { "<'a>" } else { "" };
|
||||
writeln!(f)?;
|
||||
if fields.is_empty() {
|
||||
writeln!(f, "{}pub struct {}{};", indent, name, lt)?;
|
||||
} else {
|
||||
writeln!(f, "{}pub struct {}{} {{", indent, name, lt)?;
|
||||
for field in fields {
|
||||
write!(f, "{} pub {}: ", indent, field.name)?;
|
||||
write_type(f, &field.ty)?;
|
||||
writeln!(f, ",")?;
|
||||
}
|
||||
writeln!(f, "{}}}", indent)?;
|
||||
}
|
||||
writeln!(f)?;
|
||||
writeln!(f, "{}impl<'a> Message<'a> for {}{} {{", indent, name, lt)?;
|
||||
write!(f, "{} const SIGNATURE: &'static str = \"", indent)?;
|
||||
for field in fields {
|
||||
write_signature(f, &field.ty)?;
|
||||
}
|
||||
writeln!(f, "\";")?;
|
||||
writeln!(
|
||||
f,
|
||||
"{} const INTERFACE: &'static str = \"{}\";",
|
||||
indent, el.interface
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"{} const MEMBER: &'static str = \"{}\";",
|
||||
indent, fun.name
|
||||
)?;
|
||||
writeln!(f)?;
|
||||
writeln!(f, "{} fn marshal(&self, fmt: &mut Formatter) {{", indent)?;
|
||||
if fields.is_empty() {
|
||||
writeln!(f, "{} let _ = fmt;", indent)?;
|
||||
}
|
||||
for field in fields {
|
||||
writeln!(f, "{} fmt.marshal(&self.{});", indent, field.name)?;
|
||||
}
|
||||
writeln!(f, "{} }}", indent)?;
|
||||
writeln!(f)?;
|
||||
writeln!(
|
||||
f,
|
||||
"{} fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {{",
|
||||
indent
|
||||
)?;
|
||||
if fields.is_empty() {
|
||||
writeln!(f, "{} let _ = parser;", indent)?;
|
||||
}
|
||||
writeln!(f, "{} Ok(Self {{", indent)?;
|
||||
for field in fields {
|
||||
writeln!(
|
||||
f,
|
||||
"{} {}: parser.unmarshal()?,",
|
||||
indent, field.name
|
||||
)?;
|
||||
}
|
||||
writeln!(f, "{} }})", indent)?;
|
||||
writeln!(f, "{} }}", indent)?;
|
||||
writeln!(f)?;
|
||||
writeln!(f, "{} fn num_fds(&self) -> u32 {{", indent)?;
|
||||
if fields.is_empty() {
|
||||
writeln!(f, "{} 0", indent)?;
|
||||
} else {
|
||||
writeln!(f, "{} let mut res = 0;", indent)?;
|
||||
for field in fields {
|
||||
writeln!(f, "{} res += self.{}.num_fds();", indent, field.name)?;
|
||||
}
|
||||
writeln!(f, "{} res", indent)?;
|
||||
}
|
||||
writeln!(f, "{} }}", indent)?;
|
||||
writeln!(f, "{}}}", indent)?;
|
||||
if let Some(rn) = reply_name {
|
||||
let reply_lt = if reply_has_lt { "<'b>" } else { "" };
|
||||
writeln!(f)?;
|
||||
writeln!(f, "{}impl<'a> MethodCall<'a> for {}{} {{", indent, name, lt)?;
|
||||
writeln!(f, "{} type Reply<'b> = {}{};", indent, rn, reply_lt)?;
|
||||
writeln!(f, "{}}}", indent)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_interface<W: Write>(f: &mut W, element: &Element, indent: &str) -> Result<()> {
|
||||
for fun in &element.functions {
|
||||
let in_name = format!("{}Call", fun.name);
|
||||
let out_name = format!("{}Reply", fun.name);
|
||||
let reply_has_lt = fun.out_fields.iter().any(|f| needs_lifetime(&f.ty));
|
||||
write_message(
|
||||
f,
|
||||
element,
|
||||
fun,
|
||||
&in_name,
|
||||
indent,
|
||||
&fun.in_fields,
|
||||
Some(&out_name),
|
||||
reply_has_lt,
|
||||
)?;
|
||||
write_message(
|
||||
f,
|
||||
element,
|
||||
fun,
|
||||
&out_name,
|
||||
indent,
|
||||
&fun.out_fields,
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_module<W: Write>(f: &mut W, element: Element, indent: &str) -> Result<()> {
|
||||
let mut children: Vec<_> = element.children.into_iter().map(|v| v.1).collect();
|
||||
children.sort_by(|c1, c2| c1.name.cmp(&c2.name));
|
||||
for child in children {
|
||||
write_element(f, child, indent)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_element<W: Write>(f: &mut W, element: Element, indent: &str) -> Result<()> {
|
||||
writeln!(f)?;
|
||||
writeln!(f, "{}pub mod {} {{", indent, element.name)?;
|
||||
writeln!(f, "{} use crate::dbus::prelude::*;", indent)?;
|
||||
{
|
||||
let indent = format!("{} ", indent);
|
||||
write_interface(f, &element, &indent)?;
|
||||
write_module(f, element, &indent)?;
|
||||
}
|
||||
writeln!(f, "{}}}", indent)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct Element {
|
||||
name: BString,
|
||||
interface: BString,
|
||||
children: HashMap<BString, Element>,
|
||||
functions: Vec<Function>,
|
||||
}
|
||||
|
||||
fn collect_interfaces() -> Result<Element> {
|
||||
let mut root = Element {
|
||||
name: Default::default(),
|
||||
interface: Default::default(),
|
||||
children: Default::default(),
|
||||
functions: vec![],
|
||||
};
|
||||
let mut files = vec![];
|
||||
for file in std::fs::read_dir("wire-dbus")? {
|
||||
files.push(file?);
|
||||
}
|
||||
for file in files {
|
||||
let file_name = file.file_name();
|
||||
let file_name = file_name.as_bytes().as_bstr();
|
||||
println!("cargo:rerun-if-changed=wire-dbus/{}", file_name);
|
||||
let mut interface = file_name
|
||||
.rsplitn_str(2, ".")
|
||||
.skip(1)
|
||||
.next()
|
||||
.unwrap()
|
||||
.as_bstr()
|
||||
.to_owned();
|
||||
let mut components: Vec<_> = file_name.split_str(".").collect();
|
||||
components.pop();
|
||||
let functions = (|| {
|
||||
let contents = std::fs::read(file.path())?;
|
||||
parse_functions(&contents)
|
||||
})();
|
||||
let mut functions =
|
||||
functions.with_context(|| format!("While parsing file {}", file.path().display()))?;
|
||||
let mut target = &mut root;
|
||||
for (i, comp) in components.iter().enumerate() {
|
||||
let comp = comp.as_bstr();
|
||||
if i + 1 < components.len() {
|
||||
target = match target.children.entry(comp.to_owned()) {
|
||||
Entry::Occupied(o) => o.into_mut(),
|
||||
Entry::Vacant(v) => v.insert(Element {
|
||||
name: comp.to_owned(),
|
||||
interface: Default::default(),
|
||||
children: HashMap::new(),
|
||||
functions: Vec::new(),
|
||||
}),
|
||||
};
|
||||
} else {
|
||||
target.children.insert(
|
||||
comp.to_owned(),
|
||||
Element {
|
||||
name: to_snake(comp),
|
||||
interface: mem::take(&mut interface),
|
||||
children: Default::default(),
|
||||
functions: mem::take(&mut functions),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(root)
|
||||
}
|
||||
|
||||
pub fn main() -> Result<()> {
|
||||
println!("cargo:rerun-if-changed=wire-dbus");
|
||||
|
||||
let mut f = open("wire_dbus.rs")?;
|
||||
for (_, child) in collect_interfaces()?.children {
|
||||
write_element(&mut f, child, "")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
250
src/dbus.rs
Normal file
250
src/dbus.rs
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
use crate::async_engine::{AsyncFd, SpawnedFuture};
|
||||
use crate::dbus::types::{ObjectPath, Signature, Variant};
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
use crate::utils::stack::Stack;
|
||||
use crate::utils::vecstorage::VecStorage;
|
||||
use crate::{AsyncEngine, AsyncError, AsyncQueue, CloneCell, NumCell};
|
||||
use std::borrow::Cow;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use std::task::Waker;
|
||||
use thiserror::Error;
|
||||
use uapi::OwnedFd;
|
||||
|
||||
mod auth;
|
||||
mod dynamic_type;
|
||||
mod formatter;
|
||||
mod holder;
|
||||
mod incoming;
|
||||
mod outgoing;
|
||||
mod parser;
|
||||
mod socket;
|
||||
mod types;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DbusError {
|
||||
#[error("timeout")]
|
||||
Timeout,
|
||||
#[error("Encountered an unknown type in a signature")]
|
||||
UnknownType,
|
||||
#[error("BUS closed the connection")]
|
||||
Closed,
|
||||
#[error("FD index is out of bounds")]
|
||||
OobFds,
|
||||
#[error("Variant has an invalid type")]
|
||||
InvalidVariantType,
|
||||
#[error("Could not create a socket")]
|
||||
Socket(#[source] std::io::Error),
|
||||
#[error("Could not connect")]
|
||||
Connect(#[source] std::io::Error),
|
||||
#[error("Could not write to the dbus socket")]
|
||||
WriteError(#[source] std::io::Error),
|
||||
#[error("Could not read from the dbus socket")]
|
||||
ReadError(#[source] std::io::Error),
|
||||
#[error("timeout")]
|
||||
AsyncError(#[source] Box<AsyncError>),
|
||||
#[error("Server did not accept our authentication")]
|
||||
Auth,
|
||||
#[error("Array length is not a multiple of the element size")]
|
||||
PodArrayLength,
|
||||
#[error("Peer did not send enough fds")]
|
||||
TooFewFds,
|
||||
#[error("Variant signature is not a single type")]
|
||||
TrailingVariantSignature,
|
||||
#[error("Dict signature does not contain a terminating '}}'")]
|
||||
UnterminatedDict,
|
||||
#[error("Struct signature does not contain a terminating '}}'")]
|
||||
UnterminatedStruct,
|
||||
#[error("Dict signature contains trailing types")]
|
||||
DictTrailing,
|
||||
#[error("String does not contain valid UTF-8")]
|
||||
InvalidUtf8,
|
||||
#[error("Unexpected end of message")]
|
||||
UnexpectedEof,
|
||||
#[error("Boolean value was not 0 or 1")]
|
||||
InvalidBoolValue,
|
||||
#[error("Signature is empty")]
|
||||
EmptySignature,
|
||||
#[error("Server does not support FD passing")]
|
||||
UnixFd,
|
||||
#[error("Server message has a different endianess than ourselves")]
|
||||
InvalidEndianess,
|
||||
#[error("Server speaks an unexpected protocol version")]
|
||||
InvalidProtocol,
|
||||
#[error("Could not read from the socket")]
|
||||
ReadFailed(#[source] std::io::Error),
|
||||
#[error(transparent)]
|
||||
Rc(Rc<DbusError>),
|
||||
}
|
||||
efrom!(DbusError, AsyncError);
|
||||
|
||||
pub struct Dbus {
|
||||
eng: Rc<AsyncEngine>,
|
||||
system: Rc<DbusHolder>,
|
||||
}
|
||||
|
||||
impl Dbus {
|
||||
pub fn new(eng: &Rc<AsyncEngine>) -> Self {
|
||||
Self {
|
||||
eng: eng.clone(),
|
||||
system: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn system(&self) -> Result<Rc<DbusSocket>, DbusError> {
|
||||
self.system
|
||||
.get(&self.eng, "/var/run/dbus/system_bus_socket")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DbusSocket {
|
||||
fd: AsyncFd,
|
||||
eng: Rc<AsyncEngine>,
|
||||
next_serial: NumCell<u32>,
|
||||
bufs: Stack<Vec<u8>>,
|
||||
outgoing: AsyncQueue<DbusMessage>,
|
||||
waiters: CopyHashMap<u32, Waker>,
|
||||
replies: CopyHashMap<u32, Reply>,
|
||||
incoming: Cell<Option<SpawnedFuture<()>>>,
|
||||
outgoing_: Cell<Option<SpawnedFuture<()>>>,
|
||||
auth: Cell<Option<SpawnedFuture<()>>>,
|
||||
dead: Cell<bool>,
|
||||
headers: RefCell<VecStorage<(u8, Variant<'static>)>>,
|
||||
}
|
||||
|
||||
const TY_BYTE: u8 = b'y';
|
||||
const TY_BOOLEAN: u8 = b'b';
|
||||
const TY_INT16: u8 = b'n';
|
||||
const TY_UINT16: u8 = b'q';
|
||||
const TY_INT32: u8 = b'i';
|
||||
const TY_UINT32: u8 = b'u';
|
||||
const TY_INT64: u8 = b'x';
|
||||
const TY_UINT64: u8 = b't';
|
||||
const TY_DOUBLE: u8 = b'd';
|
||||
const TY_STRING: u8 = b's';
|
||||
const TY_OBJECT_PATH: u8 = b'o';
|
||||
const TY_SIGNATURE: u8 = b'g';
|
||||
const TY_ARRAY: u8 = b'a';
|
||||
const TY_VARIANT: u8 = b'v';
|
||||
const TY_UNIX_FD: u8 = b'h';
|
||||
|
||||
const HDR_PATH: u8 = 1;
|
||||
const HDR_INTERFACE: u8 = 2;
|
||||
const HDR_MEMBER: u8 = 3;
|
||||
const HDR_ERROR_NAME: u8 = 4;
|
||||
const HDR_REPLY_SERIAL: u8 = 5;
|
||||
const HDR_DESTINATION: u8 = 6;
|
||||
const HDR_SENDER: u8 = 7;
|
||||
const HDR_SIGNATURE: u8 = 8;
|
||||
const HDR_UNIX_FDS: u8 = 9;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct Headers<'a> {
|
||||
path: Option<ObjectPath<'a>>,
|
||||
interface: Option<Cow<'a, str>>,
|
||||
member: Option<Cow<'a, str>>,
|
||||
error_name: Option<Cow<'a, str>>,
|
||||
reply_serial: Option<u32>,
|
||||
destination: Option<Cow<'a, str>>,
|
||||
sender: Option<Cow<'a, str>>,
|
||||
signature: Option<Signature<'a>>,
|
||||
unix_fds: Option<u32>,
|
||||
}
|
||||
|
||||
struct DbusHolder {
|
||||
socket: CloneCell<Option<Rc<DbusSocket>>>,
|
||||
}
|
||||
|
||||
impl Drop for DbusHolder {
|
||||
fn drop(&mut self) {
|
||||
if let Some(socket) = self.socket.take() {
|
||||
socket.auth.take();
|
||||
socket.outgoing_.take();
|
||||
socket.incoming.take();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DbusHolder {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
socket: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DbusMessage {
|
||||
fds: Vec<Rc<OwnedFd>>,
|
||||
buf: Vec<u8>,
|
||||
}
|
||||
|
||||
struct Reply {
|
||||
signature: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum DynamicType {
|
||||
U8,
|
||||
Bool,
|
||||
I16,
|
||||
U16,
|
||||
I32,
|
||||
U32,
|
||||
I64,
|
||||
U64,
|
||||
F64,
|
||||
String,
|
||||
ObjectPath,
|
||||
Signature,
|
||||
Variant,
|
||||
Fd,
|
||||
Array(Box<DynamicType>),
|
||||
DictEntry(Box<DynamicType>, Box<DynamicType>),
|
||||
Struct(Vec<DynamicType>),
|
||||
}
|
||||
|
||||
pub struct Parser<'a> {
|
||||
buf: &'a [u8],
|
||||
pos: usize,
|
||||
fds: &'a [Rc<OwnedFd>],
|
||||
}
|
||||
|
||||
pub struct Formatter<'a> {
|
||||
fds: &'a mut Vec<Rc<OwnedFd>>,
|
||||
buf: &'a mut Vec<u8>,
|
||||
}
|
||||
|
||||
pub trait Message<'a>: Sized {
|
||||
const SIGNATURE: &'static str;
|
||||
const INTERFACE: &'static str;
|
||||
const MEMBER: &'static str;
|
||||
|
||||
fn marshal(&self, w: &mut Formatter);
|
||||
fn unmarshal(p: &mut Parser<'a>) -> Result<Self, DbusError>;
|
||||
fn num_fds(&self) -> u32;
|
||||
}
|
||||
|
||||
pub trait MethodCall<'a>: Message<'a> {
|
||||
type Reply<'b>: Message<'b>;
|
||||
}
|
||||
|
||||
pub unsafe trait DbusType<'a>: Clone {
|
||||
const ALIGNMENT: usize;
|
||||
const IS_POD: bool;
|
||||
|
||||
fn write_signature(w: &mut Vec<u8>);
|
||||
fn marshal(&self, fmt: &mut Formatter);
|
||||
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError>;
|
||||
|
||||
fn num_fds(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub mod prelude {
|
||||
pub use super::{
|
||||
types::{Bool, DictEntry, ObjectPath, Signature, Variant},
|
||||
DbusError, DbusType, Formatter, Message, MethodCall, Parser,
|
||||
};
|
||||
pub use std::borrow::Cow;
|
||||
}
|
||||
112
src/dbus/auth.rs
Normal file
112
src/dbus/auth.rs
Normal 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
182
src/dbus/dynamic_type.rs
Normal 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
110
src/dbus/formatter.rs
Normal 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
60
src/dbus/holder.rs
Normal 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
173
src/dbus/incoming.rs
Normal 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
102
src/dbus/outgoing.rs
Normal 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
131
src/dbus/parser.rs
Normal 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
93
src/dbus/socket.rs
Normal 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
466
src/dbus/types.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,13 @@ pub struct Xwindow {
|
|||
|
||||
impl XwindowData {
|
||||
pub fn new(state: &Rc<State>, event: &CreateNotifyEvent, client: &Rc<Client>) -> Self {
|
||||
let extents = Rect::new_sized(event.x as _, event.y as _, event.width as _, event.height as _).unwrap();
|
||||
let extents = Rect::new_sized(
|
||||
event.x as _,
|
||||
event.y as _,
|
||||
event.width as _,
|
||||
event.height as _,
|
||||
)
|
||||
.unwrap();
|
||||
log::info!("extents = {:?}", extents);
|
||||
Self {
|
||||
state: state.clone(),
|
||||
|
|
|
|||
1
src/logind.rs
Normal file
1
src/logind.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
|
|
@ -314,3 +314,33 @@ macro_rules! dedicated_add_global {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! assert_size_eq {
|
||||
($t:ty, $u:ty) => {{
|
||||
struct AssertEqSize<T, U>(std::marker::PhantomData<T>, std::marker::PhantomData<U>);
|
||||
impl<T, U> AssertEqSize<T, U> {
|
||||
const VAL: usize = {
|
||||
if std::mem::size_of::<T>() != std::mem::size_of::<U>() {
|
||||
panic!("Types have different size");
|
||||
}
|
||||
1
|
||||
};
|
||||
}
|
||||
let _ = AssertEqSize::<$t, $u>::VAL;
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! assert_align_eq {
|
||||
($t:ty, $u:ty) => {{
|
||||
struct AssertEqAlign<T, U>(std::marker::PhantomData<T>, std::marker::PhantomData<U>);
|
||||
impl<T, U> AssertEqAlign<T, U> {
|
||||
const VAL: usize = {
|
||||
if std::mem::align_of::<T>() != std::mem::align_of::<U>() {
|
||||
panic!("Types have different alignment");
|
||||
}
|
||||
1
|
||||
};
|
||||
}
|
||||
let _ = AssertEqAlign::<$t, $u>::VAL;
|
||||
}};
|
||||
}
|
||||
|
|
|
|||
28
src/main.rs
28
src/main.rs
|
|
@ -1,4 +1,10 @@
|
|||
#![feature(c_variadic, thread_local, label_break_value, try_blocks)]
|
||||
#![feature(
|
||||
c_variadic,
|
||||
thread_local,
|
||||
label_break_value,
|
||||
try_blocks,
|
||||
generic_associated_types
|
||||
)]
|
||||
#![allow(
|
||||
clippy::len_zero,
|
||||
clippy::needless_lifetimes,
|
||||
|
|
@ -13,6 +19,7 @@ use crate::backends::dummy::DummyBackend;
|
|||
use crate::backends::xorg::{XorgBackend, XorgBackendError};
|
||||
use crate::client::Clients;
|
||||
use crate::clientmem::ClientMemError;
|
||||
use crate::dbus::Dbus;
|
||||
use crate::event_loop::EventLoopError;
|
||||
use crate::forker::ForkerError;
|
||||
use crate::globals::Globals;
|
||||
|
|
@ -34,11 +41,13 @@ use crate::utils::errorfmt::ErrorFmt;
|
|||
use crate::utils::numcell::NumCell;
|
||||
use crate::utils::queue::AsyncQueue;
|
||||
use crate::wheel::WheelError;
|
||||
use crate::wire_dbus::org;
|
||||
use crate::xkbcommon::XkbContext;
|
||||
use acceptor::Acceptor;
|
||||
use async_engine::AsyncEngine;
|
||||
use event_loop::EventLoop;
|
||||
use log::LevelFilter;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -58,6 +67,7 @@ mod client;
|
|||
mod clientmem;
|
||||
mod config;
|
||||
mod cursor;
|
||||
mod dbus;
|
||||
mod drm;
|
||||
mod event_loop;
|
||||
mod fixed;
|
||||
|
|
@ -65,6 +75,7 @@ mod forker;
|
|||
mod format;
|
||||
mod globals;
|
||||
mod ifs;
|
||||
mod logind;
|
||||
mod object;
|
||||
mod pixman;
|
||||
mod rect;
|
||||
|
|
@ -80,6 +91,7 @@ mod tree;
|
|||
mod utils;
|
||||
mod wheel;
|
||||
mod wire;
|
||||
mod wire_dbus;
|
||||
mod xkbcommon;
|
||||
mod xwayland;
|
||||
|
||||
|
|
@ -163,7 +175,21 @@ fn main_() -> Result<(), MainError> {
|
|||
pending_container_titles: Default::default(),
|
||||
pending_float_layout: Default::default(),
|
||||
pending_float_titles: Default::default(),
|
||||
dbus: Dbus::new(&engine),
|
||||
});
|
||||
state.dbus.system().unwrap().call_noreply(
|
||||
"org.freedesktop.DBus",
|
||||
"/org/freedesktop/dbus",
|
||||
org::freedesktop::dbus::HelloCall,
|
||||
);
|
||||
state.dbus.system().unwrap().call_noreply(
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
org::freedesktop::login1::manager::GetSessionCall {
|
||||
// session_id: Cow::Owned(std::env::var("XDG_SESSION_ID").unwrap()),
|
||||
session_id: Cow::Borrowed("hurr durr"),
|
||||
},
|
||||
);
|
||||
forker.install(&state);
|
||||
let backend = XorgBackend::new(&state)?;
|
||||
state.backend.set(backend);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use crate::backend::{
|
|||
use crate::client::{Client, Clients};
|
||||
use crate::config::ConfigProxy;
|
||||
use crate::cursor::ServerCursors;
|
||||
use crate::dbus::Dbus;
|
||||
use crate::event_loop::EventLoop;
|
||||
use crate::forker::ForkerProxy;
|
||||
use crate::globals::{Globals, GlobalsError, WaylandGlobal};
|
||||
|
|
@ -63,6 +64,7 @@ pub struct State {
|
|||
pub pending_container_titles: AsyncQueue<Rc<ContainerNode>>,
|
||||
pub pending_float_layout: AsyncQueue<Rc<FloatNode>>,
|
||||
pub pending_float_titles: AsyncQueue<Rc<FloatNode>>,
|
||||
pub dbus: Dbus,
|
||||
}
|
||||
|
||||
pub struct MouseData {
|
||||
|
|
|
|||
22
src/utils/aligned.rs
Normal file
22
src/utils/aligned.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
use uapi::{Packed, Pod};
|
||||
|
||||
#[repr(C, align(8))]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct AlignedI64(pub i64);
|
||||
|
||||
unsafe impl Pod for AlignedI64 {}
|
||||
unsafe impl Packed for AlignedI64 {}
|
||||
|
||||
#[repr(C, align(8))]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct AlignedU64(pub u64);
|
||||
|
||||
unsafe impl Pod for AlignedU64 {}
|
||||
unsafe impl Packed for AlignedU64 {}
|
||||
|
||||
#[repr(C, align(8))]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct AlignedF64(pub f64);
|
||||
|
||||
unsafe impl Pod for AlignedF64 {}
|
||||
unsafe impl Packed for AlignedF64 {}
|
||||
15
src/utils/hex.rs
Normal file
15
src/utils/hex.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
pub fn to_hex(b: &str) -> String {
|
||||
let mut s = String::with_capacity(b.len() * 2);
|
||||
for &b in b.as_bytes() {
|
||||
s.push(nibble_to_hex(b >> 4) as char);
|
||||
s.push(nibble_to_hex(b & 7) as char);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
fn nibble_to_hex(n: u8) -> u8 {
|
||||
match n {
|
||||
n @ 0..=9 => b'0' + n,
|
||||
n => b'a' + n,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
pub mod aligned;
|
||||
pub mod array;
|
||||
pub mod asyncevent;
|
||||
pub mod bitflags;
|
||||
|
|
@ -6,6 +7,7 @@ pub mod clonecell;
|
|||
pub mod copyhashmap;
|
||||
pub mod debug_fn;
|
||||
pub mod errorfmt;
|
||||
pub mod hex;
|
||||
pub mod linkedlist;
|
||||
pub mod numcell;
|
||||
pub mod ptr_ext;
|
||||
|
|
@ -14,3 +16,4 @@ pub mod smallmap;
|
|||
pub mod stack;
|
||||
pub mod tri;
|
||||
pub mod vec_ext;
|
||||
pub mod vecstorage;
|
||||
|
|
|
|||
74
src/utils/vecstorage.rs
Normal file
74
src/utils/vecstorage.rs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
use std::mem::ManuallyDrop;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
pub struct VecStorage<T> {
|
||||
ptr: *mut T,
|
||||
cap: usize,
|
||||
}
|
||||
|
||||
impl<T> Default for VecStorage<T> {
|
||||
fn default() -> Self {
|
||||
let mut v = ManuallyDrop::new(vec![]);
|
||||
Self {
|
||||
ptr: v.as_mut_ptr(),
|
||||
cap: v.capacity(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> VecStorage<T> {
|
||||
#[allow(dead_code)]
|
||||
pub fn take<'a>(&'a mut self) -> RealizedVec<'a, T, T> {
|
||||
self.take_as()
|
||||
}
|
||||
|
||||
pub fn take_as<'a, U>(&'a mut self) -> RealizedVec<'a, T, U> {
|
||||
assert_size_eq!(T, U);
|
||||
assert_align_eq!(T, U);
|
||||
unsafe {
|
||||
RealizedVec {
|
||||
vec: ManuallyDrop::new(self.to_vector()),
|
||||
storage: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn to_vector<U>(&mut self) -> Vec<U> {
|
||||
Vec::from_raw_parts(self.ptr as _, 0, self.cap)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for VecStorage<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
drop(self.to_vector::<T>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RealizedVec<'a, T, U> {
|
||||
vec: ManuallyDrop<Vec<U>>,
|
||||
storage: &'a mut VecStorage<T>,
|
||||
}
|
||||
|
||||
impl<'a, T, U> Drop for RealizedVec<'a, T, U> {
|
||||
fn drop(&mut self) {
|
||||
self.vec.clear();
|
||||
self.storage.ptr = self.vec.as_mut_ptr() as _;
|
||||
self.storage.cap = self.vec.capacity();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, U> Deref for RealizedVec<'a, T, U> {
|
||||
type Target = Vec<U>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.vec.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, U> DerefMut for RealizedVec<'a, T, U> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.vec.deref_mut()
|
||||
}
|
||||
}
|
||||
3
src/wire_dbus.rs
Normal file
3
src/wire_dbus.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#![allow(unused_imports)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/wire_dbus.rs"));
|
||||
|
|
@ -2,6 +2,7 @@ use crate::async_engine::AsyncFd;
|
|||
use crate::client::Client;
|
||||
use crate::ifs::wl_surface::xwindow::{Xwindow, XwindowData};
|
||||
use crate::ifs::wl_surface::WlSurface;
|
||||
use crate::rect::Rect;
|
||||
use crate::wire::WlSurfaceId;
|
||||
use crate::xwayland::{XWaylandError, XWaylandEvent};
|
||||
use crate::{AsyncQueue, ErrorFmt, State};
|
||||
|
|
@ -17,11 +18,14 @@ use x11rb::connection::Connection;
|
|||
use x11rb::cursor::Handle;
|
||||
use x11rb::errors::ConnectionError;
|
||||
use x11rb::protocol::composite::{ConnectionExt as _, Redirect};
|
||||
use x11rb::protocol::xproto::{ChangeWindowAttributesAux, ClientMessageEvent, ConfigureNotifyEvent, ConfigureRequestEvent, ConfigureWindowAux, ConnectionExt as _, CreateNotifyEvent, CreateWindowAux, DestroyNotifyEvent, EventMask, MapRequestEvent, Window, WindowClass};
|
||||
use x11rb::protocol::xproto::{
|
||||
ChangeWindowAttributesAux, ClientMessageEvent, ConfigureNotifyEvent, ConfigureRequestEvent,
|
||||
ConfigureWindowAux, ConnectionExt as _, CreateNotifyEvent, CreateWindowAux, DestroyNotifyEvent,
|
||||
EventMask, MapRequestEvent, Window, WindowClass,
|
||||
};
|
||||
use x11rb::protocol::Event;
|
||||
use x11rb::resource_manager::Database;
|
||||
use x11rb::rust_connection::{DefaultStream, RustConnection};
|
||||
use crate::rect::Rect;
|
||||
|
||||
atom_manager! {
|
||||
pub Atoms: AtomsCookie {
|
||||
|
|
@ -372,7 +376,8 @@ impl Wm {
|
|||
event.y as _,
|
||||
event.width as _,
|
||||
event.height as _,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
let changed = data.extents.replace(extents) != extents;
|
||||
if changed {
|
||||
self.state.tree_changed();
|
||||
|
|
|
|||
3
wire-dbus/org.freedesktop.DBus.txt
Normal file
3
wire-dbus/org.freedesktop.DBus.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fn Hello() {
|
||||
name: string,
|
||||
}
|
||||
5
wire-dbus/org.freedesktop.login1.Manager.txt
Normal file
5
wire-dbus/org.freedesktop.login1.Manager.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
fn GetSession(
|
||||
session_id: string,
|
||||
) {
|
||||
object_path: object_path,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue