autocommit 2022-02-28 00:14:11 CET
This commit is contained in:
parent
db88f2db42
commit
0e9afcbfa5
22 changed files with 1013 additions and 239 deletions
21
Cargo.lock
generated
21
Cargo.lock
generated
|
|
@ -429,6 +429,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pango",
|
"pango",
|
||||||
"pangocairo",
|
"pangocairo",
|
||||||
|
"pin-project",
|
||||||
"rand",
|
"rand",
|
||||||
"renderdoc",
|
"renderdoc",
|
||||||
"repc",
|
"repc",
|
||||||
|
|
@ -620,6 +621,26 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project"
|
||||||
|
version = "1.0.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-internal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-internal"
|
||||||
|
version = "1.0.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ pango = { version = "0.15.2", features = ["v1_44"] }
|
||||||
i4config = { path = "i4config" }
|
i4config = { path = "i4config" }
|
||||||
default-config = { path = "default-config" }
|
default-config = { path = "default-config" }
|
||||||
x11rb = { version = "0.9.0", features = ["composite", "cursor"] }
|
x11rb = { version = "0.9.0", features = ["composite", "cursor"] }
|
||||||
|
pin-project = "1.0.10"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
repc = "0.1.1"
|
repc = "0.1.1"
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ impl<'a> Tokenizer<'a> {
|
||||||
b'{' => self.tokenize_tree(TreeDelim::Brace)?,
|
b'{' => self.tokenize_tree(TreeDelim::Brace)?,
|
||||||
c @ (b')' | b'}') => {
|
c @ (b')' | b'}') => {
|
||||||
if self.delim.map(|d| d.closing()) != Some(c) {
|
if self.delim.map(|d| d.closing()) != Some(c) {
|
||||||
bail!("Unexpected '{}' in line {}", c, self.line);
|
bail!("Unexpected {:?} in line {}", c as char, self.line);
|
||||||
}
|
}
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ use bstr::{BStr, BString, ByteSlice};
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::mem;
|
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -42,18 +41,28 @@ struct Function {
|
||||||
out_fields: Vec<Field>,
|
out_fields: Vec<Field>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Property {
|
||||||
|
name: BString,
|
||||||
|
ty: Type,
|
||||||
|
}
|
||||||
|
|
||||||
struct Parser<'a> {
|
struct Parser<'a> {
|
||||||
pos: usize,
|
pos: usize,
|
||||||
tokens: &'a [Token<'a>],
|
tokens: &'a [Token<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
fn parse(&mut self) -> Result<Vec<Function>> {
|
fn parse(&mut self) -> Result<Component> {
|
||||||
let mut res = vec![];
|
let mut res = Component {
|
||||||
|
functions: vec![],
|
||||||
|
properties: vec![],
|
||||||
|
};
|
||||||
while !self.eof() {
|
while !self.eof() {
|
||||||
let (line, ty) = self.expect_ident()?;
|
let (line, ty) = self.expect_ident()?;
|
||||||
match ty.as_bytes() {
|
match ty.as_bytes() {
|
||||||
b"fn" => res.push(self.parse_fn()?.val),
|
b"fn" => res.functions.push(self.parse_fn()?.val),
|
||||||
|
b"prop" => res.properties.push(self.parse_prop()?.val),
|
||||||
_ => bail!("In line {}: Unexpected entry {:?}", line, ty),
|
_ => bail!("In line {}: Unexpected entry {:?}", line, ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -71,6 +80,22 @@ impl<'a> Parser<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_prop(&mut self) -> Result<Lined<Property>> {
|
||||||
|
let (line, name) = self.expect_ident()?;
|
||||||
|
let res: Result<_> = (|| {
|
||||||
|
self.expect_symbol(Symbol::Equals)?;
|
||||||
|
let ty = self.parse_type()?;
|
||||||
|
Ok(Lined {
|
||||||
|
line,
|
||||||
|
val: Property {
|
||||||
|
name: name.to_owned(),
|
||||||
|
ty,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})();
|
||||||
|
res.with_context(|| format!("While parsing property starting at line {}", line))
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_fn(&mut self) -> Result<Lined<Function>> {
|
fn parse_fn(&mut self) -> Result<Lined<Function>> {
|
||||||
let (line, name) = self.expect_ident()?;
|
let (line, name) = self.expect_ident()?;
|
||||||
let res: Result<_> = (|| {
|
let res: Result<_> = (|| {
|
||||||
|
|
@ -101,7 +126,7 @@ impl<'a> Parser<'a> {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})();
|
})();
|
||||||
res.with_context(|| format!("While parsing message starting at line {}", line))
|
res.with_context(|| format!("While parsing function starting at line {}", line))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_field(&mut self) -> Result<Field> {
|
fn parse_field(&mut self) -> Result<Field> {
|
||||||
|
|
@ -252,7 +277,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_functions(s: &[u8]) -> Result<Vec<Function>> {
|
fn parse_component(s: &[u8]) -> Result<Component> {
|
||||||
let tokens = tokenize(s)?;
|
let tokens = tokenize(s)?;
|
||||||
let mut parser = Parser {
|
let mut parser = Parser {
|
||||||
pos: 0,
|
pos: 0,
|
||||||
|
|
@ -343,6 +368,10 @@ fn write_signature<W: Write>(f: &mut W, ty: &Type) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_type<W: Write>(f: &mut W, ty: &Type) -> Result<()> {
|
fn write_type<W: Write>(f: &mut W, ty: &Type) -> Result<()> {
|
||||||
|
write_type2(f, "'a", ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_type2<W: Write>(f: &mut W, lt: &str, ty: &Type) -> Result<()> {
|
||||||
let ty = match ty {
|
let ty = match ty {
|
||||||
Type::U8 => "u8",
|
Type::U8 => "u8",
|
||||||
Type::Bool => "Bool",
|
Type::Bool => "Bool",
|
||||||
|
|
@ -353,22 +382,34 @@ fn write_type<W: Write>(f: &mut W, ty: &Type) -> Result<()> {
|
||||||
Type::I64 => "AlignedI64",
|
Type::I64 => "AlignedI64",
|
||||||
Type::U64 => "AlignedU64",
|
Type::U64 => "AlignedU64",
|
||||||
Type::F64 => "AlignedF64",
|
Type::F64 => "AlignedF64",
|
||||||
Type::String => "Cow<'a, str>",
|
Type::String => {
|
||||||
Type::ObjectPath => "ObjectPath<'a>",
|
write!(f, "Cow<{}, str>", lt)?;
|
||||||
Type::Signature => "Signature<'a>",
|
return Ok(());
|
||||||
Type::Variant => "Variant<'a>",
|
}
|
||||||
|
Type::ObjectPath => {
|
||||||
|
write!(f, "ObjectPath<{}>", lt)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Type::Signature => {
|
||||||
|
write!(f, "Signature<{}>", lt)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Type::Variant => {
|
||||||
|
write!(f, "Variant<{}>", lt)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
Type::Fd => "Rc<OwnedFd>",
|
Type::Fd => "Rc<OwnedFd>",
|
||||||
Type::Array(e) => {
|
Type::Array(e) => {
|
||||||
write!(f, "Cow<'a, [")?;
|
write!(f, "Cow<{}, [", lt)?;
|
||||||
write_type(f, &e)?;
|
write_type2(f, lt, &e)?;
|
||||||
write!(f, ">")?;
|
write!(f, "]>")?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Type::DictEntry(k, v) => {
|
Type::DictEntry(k, v) => {
|
||||||
write!(f, "DictEntry<")?;
|
write!(f, "DictEntry<")?;
|
||||||
write_type(f, &k)?;
|
write_type2(f, lt, &k)?;
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
write_type(f, &v)?;
|
write_type2(f, lt, &v)?;
|
||||||
write!(f, ">")?;
|
write!(f, ">")?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
@ -378,7 +419,7 @@ fn write_type<W: Write>(f: &mut W, ty: &Type) -> Result<()> {
|
||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
write_type(f, &fs)?;
|
write_type2(f, lt, &fs)?;
|
||||||
}
|
}
|
||||||
write!(f, ")")?;
|
write!(f, ")")?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -400,7 +441,9 @@ fn write_message<W: Write>(
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let needs_lt = fields.iter().any(|f| needs_lifetime(&f.ty));
|
let needs_lt = fields.iter().any(|f| needs_lifetime(&f.ty));
|
||||||
let lt = if needs_lt { "<'a>" } else { "" };
|
let lt = if needs_lt { "<'a>" } else { "" };
|
||||||
|
let ltb = if needs_lt { "<'b>" } else { "" };
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
|
writeln!(f, "{}#[derive(Debug)]", indent)?;
|
||||||
if fields.is_empty() {
|
if fields.is_empty() {
|
||||||
writeln!(f, "{}pub struct {}{};", indent, name, lt)?;
|
writeln!(f, "{}pub struct {}{};", indent, name, lt)?;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -413,7 +456,11 @@ fn write_message<W: Write>(
|
||||||
writeln!(f, "{}}}", indent)?;
|
writeln!(f, "{}}}", indent)?;
|
||||||
}
|
}
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
writeln!(f, "{}impl<'a> Message<'a> for {}{} {{", indent, name, lt)?;
|
writeln!(
|
||||||
|
f,
|
||||||
|
"{}unsafe impl<'a> Message<'a> for {}{} {{",
|
||||||
|
indent, name, lt
|
||||||
|
)?;
|
||||||
write!(f, "{} const SIGNATURE: &'static str = \"", indent)?;
|
write!(f, "{} const SIGNATURE: &'static str = \"", indent)?;
|
||||||
for field in fields {
|
for field in fields {
|
||||||
write_signature(f, &field.ty)?;
|
write_signature(f, &field.ty)?;
|
||||||
|
|
@ -429,6 +476,7 @@ fn write_message<W: Write>(
|
||||||
"{} const MEMBER: &'static str = \"{}\";",
|
"{} const MEMBER: &'static str = \"{}\";",
|
||||||
indent, fun.name
|
indent, fun.name
|
||||||
)?;
|
)?;
|
||||||
|
writeln!(f, "{} type Generic<'b> = {}{};", indent, name, ltb,)?;
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
writeln!(f, "{} fn marshal(&self, fmt: &mut Formatter) {{", indent)?;
|
writeln!(f, "{} fn marshal(&self, fmt: &mut Formatter) {{", indent)?;
|
||||||
if fields.is_empty() {
|
if fields.is_empty() {
|
||||||
|
|
@ -471,41 +519,86 @@ fn write_message<W: Write>(
|
||||||
writeln!(f, "{} }}", indent)?;
|
writeln!(f, "{} }}", indent)?;
|
||||||
writeln!(f, "{}}}", indent)?;
|
writeln!(f, "{}}}", indent)?;
|
||||||
if let Some(rn) = reply_name {
|
if let Some(rn) = reply_name {
|
||||||
let reply_lt = if reply_has_lt { "<'b>" } else { "" };
|
let reply_lt = if reply_has_lt { "<'static>" } else { "" };
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
writeln!(f, "{}impl<'a> MethodCall<'a> for {}{} {{", indent, name, lt)?;
|
writeln!(f, "{}impl<'a> MethodCall<'a> for {}{} {{", indent, name, lt)?;
|
||||||
writeln!(f, "{} type Reply<'b> = {}{};", indent, rn, reply_lt)?;
|
writeln!(f, "{} type Reply = {}{};", indent, rn, reply_lt)?;
|
||||||
writeln!(f, "{}}}", indent)?;
|
writeln!(f, "{}}}", indent)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_interface<W: Write>(f: &mut W, element: &Element, indent: &str) -> Result<()> {
|
fn write_component<W: Write>(
|
||||||
for fun in &element.functions {
|
f: &mut W,
|
||||||
let in_name = format!("{}Call", fun.name);
|
element: &Element,
|
||||||
let out_name = format!("{}Reply", fun.name);
|
component: &Component,
|
||||||
let reply_has_lt = fun.out_fields.iter().any(|f| needs_lifetime(&f.ty));
|
indent: &str,
|
||||||
write_message(
|
) -> Result<()> {
|
||||||
f,
|
for fun in &component.functions {
|
||||||
element,
|
write_function(f, element, fun, indent)?;
|
||||||
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,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
for prop in &component.properties {
|
||||||
|
write_property(f, element, prop, indent)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_property<W: Write>(
|
||||||
|
f: &mut W,
|
||||||
|
el: &Element,
|
||||||
|
property: &Property,
|
||||||
|
indent: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
writeln!(f)?;
|
||||||
|
writeln!(f, "{}pub struct {};", indent, property.name)?;
|
||||||
|
writeln!(f)?;
|
||||||
|
writeln!(f, "{}impl Property for {} {{", indent, property.name)?;
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"{} const INTERFACE: &'static str = \"{}\";",
|
||||||
|
indent, el.interface
|
||||||
|
)?;
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"{} const PROPERTY: &'static str = \"{}\";",
|
||||||
|
indent, property.name,
|
||||||
|
)?;
|
||||||
|
write!(f, "{} type Type = ", indent)?;
|
||||||
|
write_type2(f, "'static", &property.ty)?;
|
||||||
|
writeln!(f, ";")?;
|
||||||
|
writeln!(f, "{}}}", indent)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_function<W: Write>(
|
||||||
|
f: &mut W,
|
||||||
|
element: &Element,
|
||||||
|
fun: &Function,
|
||||||
|
indent: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
let in_name = format!("{}", 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -524,18 +617,27 @@ fn write_element<W: Write>(f: &mut W, element: Element, indent: &str) -> Result<
|
||||||
writeln!(f, "{} use crate::dbus::prelude::*;", indent)?;
|
writeln!(f, "{} use crate::dbus::prelude::*;", indent)?;
|
||||||
{
|
{
|
||||||
let indent = format!("{} ", indent);
|
let indent = format!("{} ", indent);
|
||||||
write_interface(f, &element, &indent)?;
|
for component in &element.components {
|
||||||
|
write_component(f, &element, &component, &indent)?;
|
||||||
|
}
|
||||||
write_module(f, element, &indent)?;
|
write_module(f, element, &indent)?;
|
||||||
}
|
}
|
||||||
writeln!(f, "{}}}", indent)?;
|
writeln!(f, "{}}}", indent)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Component {
|
||||||
|
functions: Vec<Function>,
|
||||||
|
properties: Vec<Property>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct Element {
|
struct Element {
|
||||||
name: BString,
|
name: BString,
|
||||||
interface: BString,
|
interface: BString,
|
||||||
children: HashMap<BString, Element>,
|
children: HashMap<BString, Element>,
|
||||||
functions: Vec<Function>,
|
components: Vec<Component>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_interfaces() -> Result<Element> {
|
fn collect_interfaces() -> Result<Element> {
|
||||||
|
|
@ -543,7 +645,7 @@ fn collect_interfaces() -> Result<Element> {
|
||||||
name: Default::default(),
|
name: Default::default(),
|
||||||
interface: Default::default(),
|
interface: Default::default(),
|
||||||
children: Default::default(),
|
children: Default::default(),
|
||||||
functions: vec![],
|
components: vec![],
|
||||||
};
|
};
|
||||||
let mut files = vec![];
|
let mut files = vec![];
|
||||||
for file in std::fs::read_dir("wire-dbus")? {
|
for file in std::fs::read_dir("wire-dbus")? {
|
||||||
|
|
@ -553,7 +655,7 @@ fn collect_interfaces() -> Result<Element> {
|
||||||
let file_name = file.file_name();
|
let file_name = file.file_name();
|
||||||
let file_name = file_name.as_bytes().as_bstr();
|
let file_name = file_name.as_bytes().as_bstr();
|
||||||
println!("cargo:rerun-if-changed=wire-dbus/{}", file_name);
|
println!("cargo:rerun-if-changed=wire-dbus/{}", file_name);
|
||||||
let mut interface = file_name
|
let interface = file_name
|
||||||
.rsplitn_str(2, ".")
|
.rsplitn_str(2, ".")
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.next()
|
.next()
|
||||||
|
|
@ -562,37 +664,27 @@ fn collect_interfaces() -> Result<Element> {
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let mut components: Vec<_> = file_name.split_str(".").collect();
|
let mut components: Vec<_> = file_name.split_str(".").collect();
|
||||||
components.pop();
|
components.pop();
|
||||||
let functions = (|| {
|
let component = (|| {
|
||||||
let contents = std::fs::read(file.path())?;
|
let contents = std::fs::read(file.path())?;
|
||||||
parse_functions(&contents)
|
parse_component(&contents)
|
||||||
})();
|
})();
|
||||||
let mut functions =
|
let component =
|
||||||
functions.with_context(|| format!("While parsing file {}", file.path().display()))?;
|
component.with_context(|| format!("While parsing file {}", file.path().display()))?;
|
||||||
let mut target = &mut root;
|
let mut target = &mut root;
|
||||||
for (i, comp) in components.iter().enumerate() {
|
for comp in components.iter() {
|
||||||
let comp = comp.as_bstr();
|
let comp = to_snake(comp.as_bstr());
|
||||||
if i + 1 < components.len() {
|
target = match target.children.entry(comp.to_owned()) {
|
||||||
target = match target.children.entry(comp.to_owned()) {
|
Entry::Occupied(o) => o.into_mut(),
|
||||||
Entry::Occupied(o) => o.into_mut(),
|
Entry::Vacant(v) => v.insert(Element {
|
||||||
Entry::Vacant(v) => v.insert(Element {
|
name: comp.to_owned(),
|
||||||
name: comp.to_owned(),
|
interface: Default::default(),
|
||||||
interface: Default::default(),
|
children: HashMap::new(),
|
||||||
children: HashMap::new(),
|
components: vec![],
|
||||||
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),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
target.interface = interface;
|
||||||
|
target.components.push(component);
|
||||||
}
|
}
|
||||||
Ok(root)
|
Ok(root)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
212
src/dbus.rs
212
src/dbus.rs
|
|
@ -1,14 +1,20 @@
|
||||||
use crate::async_engine::{AsyncFd, SpawnedFuture};
|
use crate::async_engine::{AsyncFd, SpawnedFuture};
|
||||||
|
use crate::dbus::property::GetReply;
|
||||||
use crate::dbus::types::{ObjectPath, Signature, Variant};
|
use crate::dbus::types::{ObjectPath, Signature, Variant};
|
||||||
use crate::utils::copyhashmap::CopyHashMap;
|
use crate::utils::copyhashmap::CopyHashMap;
|
||||||
use crate::utils::stack::Stack;
|
use crate::utils::stack::Stack;
|
||||||
use crate::utils::vecstorage::VecStorage;
|
use crate::utils::vecstorage::VecStorage;
|
||||||
use crate::{AsyncEngine, AsyncError, AsyncQueue, CloneCell, NumCell};
|
use crate::{AsyncEngine, AsyncError, AsyncQueue, CloneCell, NumCell, RunToplevel};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
|
use std::fmt::{Debug, Display};
|
||||||
|
use std::future::Future;
|
||||||
|
use std::mem;
|
||||||
|
use std::pin::Pin;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::task::Waker;
|
use std::task::{Context, Poll, Waker};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
pub use types::*;
|
||||||
use uapi::OwnedFd;
|
use uapi::OwnedFd;
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
|
|
@ -18,17 +24,40 @@ mod holder;
|
||||||
mod incoming;
|
mod incoming;
|
||||||
mod outgoing;
|
mod outgoing;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
mod property;
|
||||||
mod socket;
|
mod socket;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CallError {
|
||||||
|
pub name: String,
|
||||||
|
pub msg: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for CallError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if let Some(msg) = &self.msg {
|
||||||
|
write!(f, "{}: {}", self.name, msg)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum DbusError {
|
pub enum DbusError {
|
||||||
#[error("timeout")]
|
|
||||||
Timeout,
|
|
||||||
#[error("Encountered an unknown type in a signature")]
|
#[error("Encountered an unknown type in a signature")]
|
||||||
UnknownType,
|
UnknownType,
|
||||||
#[error("BUS closed the connection")]
|
#[error("BUS closed the connection")]
|
||||||
Closed,
|
Closed,
|
||||||
|
#[error("Function call reply does not contain a reply serial")]
|
||||||
|
NoReplySerial,
|
||||||
|
#[error("Error has no error name")]
|
||||||
|
NoErrorName,
|
||||||
|
#[error("The socket was killed")]
|
||||||
|
Killed,
|
||||||
|
#[error("{0}")]
|
||||||
|
CallError(CallError),
|
||||||
#[error("FD index is out of bounds")]
|
#[error("FD index is out of bounds")]
|
||||||
OobFds,
|
OobFds,
|
||||||
#[error("Variant has an invalid type")]
|
#[error("Variant has an invalid type")]
|
||||||
|
|
@ -71,10 +100,8 @@ pub enum DbusError {
|
||||||
InvalidEndianess,
|
InvalidEndianess,
|
||||||
#[error("Server speaks an unexpected protocol version")]
|
#[error("Server speaks an unexpected protocol version")]
|
||||||
InvalidProtocol,
|
InvalidProtocol,
|
||||||
#[error("Could not read from the socket")]
|
#[error("Signature contains an invalid type")]
|
||||||
ReadFailed(#[source] std::io::Error),
|
InvalidSignatureType,
|
||||||
#[error(transparent)]
|
|
||||||
Rc(Rc<DbusError>),
|
|
||||||
}
|
}
|
||||||
efrom!(DbusError, AsyncError);
|
efrom!(DbusError, AsyncError);
|
||||||
|
|
||||||
|
|
@ -84,32 +111,46 @@ pub struct Dbus {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dbus {
|
impl Dbus {
|
||||||
pub fn new(eng: &Rc<AsyncEngine>) -> Self {
|
pub fn new(eng: &Rc<AsyncEngine>, run_toplevel: &Rc<RunToplevel>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
eng: eng.clone(),
|
eng: eng.clone(),
|
||||||
system: Default::default(),
|
system: Rc::new(DbusHolder::new(run_toplevel)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn system(&self) -> Result<Rc<DbusSocket>, DbusError> {
|
pub fn system(&self) -> Result<Rc<DbusSocket>, DbusError> {
|
||||||
self.system
|
self.system
|
||||||
.get(&self.eng, "/var/run/dbus/system_bus_socket")
|
.get(&self.eng, "/var/run/dbus/system_bus_socket", "System bus")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe trait ReplyHandler {
|
||||||
|
fn signature(&self) -> &str;
|
||||||
|
fn handle_error(self: Box<Self>, socket: &Rc<DbusSocket>, error: DbusError);
|
||||||
|
fn handle(
|
||||||
|
self: Box<Self>,
|
||||||
|
socket: &Rc<DbusSocket>,
|
||||||
|
headers: &Headers,
|
||||||
|
parser: &mut Parser,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
) -> Result<(), DbusError>;
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DbusSocket {
|
pub struct DbusSocket {
|
||||||
|
bus_name: &'static str,
|
||||||
fd: AsyncFd,
|
fd: AsyncFd,
|
||||||
eng: Rc<AsyncEngine>,
|
eng: Rc<AsyncEngine>,
|
||||||
next_serial: NumCell<u32>,
|
next_serial: NumCell<u32>,
|
||||||
bufs: Stack<Vec<u8>>,
|
bufs: Stack<Vec<u8>>,
|
||||||
|
unique_name: CloneCell<Rc<String>>,
|
||||||
outgoing: AsyncQueue<DbusMessage>,
|
outgoing: AsyncQueue<DbusMessage>,
|
||||||
waiters: CopyHashMap<u32, Waker>,
|
reply_handlers: CopyHashMap<u32, Box<dyn ReplyHandler>>,
|
||||||
replies: CopyHashMap<u32, Reply>,
|
|
||||||
incoming: Cell<Option<SpawnedFuture<()>>>,
|
incoming: Cell<Option<SpawnedFuture<()>>>,
|
||||||
outgoing_: Cell<Option<SpawnedFuture<()>>>,
|
outgoing_: Cell<Option<SpawnedFuture<()>>>,
|
||||||
auth: Cell<Option<SpawnedFuture<()>>>,
|
auth: Cell<Option<SpawnedFuture<()>>>,
|
||||||
dead: Cell<bool>,
|
dead: Cell<bool>,
|
||||||
headers: RefCell<VecStorage<(u8, Variant<'static>)>>,
|
headers: RefCell<VecStorage<(u8, Variant<'static>)>>,
|
||||||
|
run_toplevel: Rc<RunToplevel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const TY_BYTE: u8 = b'y';
|
const TY_BYTE: u8 = b'y';
|
||||||
|
|
@ -138,6 +179,15 @@ const HDR_SENDER: u8 = 7;
|
||||||
const HDR_SIGNATURE: u8 = 8;
|
const HDR_SIGNATURE: u8 = 8;
|
||||||
const HDR_UNIX_FDS: u8 = 9;
|
const HDR_UNIX_FDS: u8 = 9;
|
||||||
|
|
||||||
|
const MSG_METHOD_CALL: u8 = 1;
|
||||||
|
const MSG_METHOD_RETURN: u8 = 2;
|
||||||
|
const MSG_ERROR: u8 = 3;
|
||||||
|
const MSG_SIGNAL: u8 = 4;
|
||||||
|
|
||||||
|
const NO_REPLY_EXPECTED: u8 = 0x1;
|
||||||
|
const NO_AUTO_START: u8 = 0x2;
|
||||||
|
const ALLOW_INTERACTIVE_AUTHORIZATION: u8 = 0x4;
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct Headers<'a> {
|
struct Headers<'a> {
|
||||||
path: Option<ObjectPath<'a>>,
|
path: Option<ObjectPath<'a>>,
|
||||||
|
|
@ -153,6 +203,16 @@ struct Headers<'a> {
|
||||||
|
|
||||||
struct DbusHolder {
|
struct DbusHolder {
|
||||||
socket: CloneCell<Option<Rc<DbusSocket>>>,
|
socket: CloneCell<Option<Rc<DbusSocket>>>,
|
||||||
|
run_toplevel: Rc<RunToplevel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DbusHolder {
|
||||||
|
pub fn new(run_toplevel: &Rc<RunToplevel>) -> Self {
|
||||||
|
Self {
|
||||||
|
socket: Default::default(),
|
||||||
|
run_toplevel: run_toplevel.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for DbusHolder {
|
impl Drop for DbusHolder {
|
||||||
|
|
@ -165,23 +225,11 @@ impl Drop for DbusHolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DbusHolder {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
socket: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DbusMessage {
|
struct DbusMessage {
|
||||||
fds: Vec<Rc<OwnedFd>>,
|
fds: Vec<Rc<OwnedFd>>,
|
||||||
buf: Vec<u8>,
|
buf: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Reply {
|
|
||||||
signature: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum DynamicType {
|
pub enum DynamicType {
|
||||||
U8,
|
U8,
|
||||||
|
|
@ -214,24 +262,33 @@ pub struct Formatter<'a> {
|
||||||
buf: &'a mut Vec<u8>,
|
buf: &'a mut Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Message<'a>: Sized {
|
pub unsafe trait Message<'a>: Sized + 'a {
|
||||||
const SIGNATURE: &'static str;
|
const SIGNATURE: &'static str;
|
||||||
const INTERFACE: &'static str;
|
const INTERFACE: &'static str;
|
||||||
const MEMBER: &'static str;
|
const MEMBER: &'static str;
|
||||||
|
type Generic<'b>: Message<'b>;
|
||||||
|
|
||||||
fn marshal(&self, w: &mut Formatter);
|
fn marshal(&self, w: &mut Formatter);
|
||||||
fn unmarshal(p: &mut Parser<'a>) -> Result<Self, DbusError>;
|
fn unmarshal(p: &mut Parser<'a>) -> Result<Self, DbusError>;
|
||||||
fn num_fds(&self) -> u32;
|
fn num_fds(&self) -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MethodCall<'a>: Message<'a> {
|
pub trait Property {
|
||||||
type Reply<'b>: Message<'b>;
|
const INTERFACE: &'static str;
|
||||||
|
const PROPERTY: &'static str;
|
||||||
|
type Type: DbusType<'static>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe trait DbusType<'a>: Clone {
|
pub trait MethodCall<'a>: Message<'a> {
|
||||||
|
type Reply: Message<'static>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe trait DbusType<'a>: Clone + 'a {
|
||||||
const ALIGNMENT: usize;
|
const ALIGNMENT: usize;
|
||||||
const IS_POD: bool;
|
const IS_POD: bool;
|
||||||
|
type Generic<'b>: DbusType<'b> + 'b;
|
||||||
|
|
||||||
|
fn consume_signature(s: &mut &[u8]) -> Result<(), DbusError>;
|
||||||
fn write_signature(w: &mut Vec<u8>);
|
fn write_signature(w: &mut Vec<u8>);
|
||||||
fn marshal(&self, fmt: &mut Formatter);
|
fn marshal(&self, fmt: &mut Formatter);
|
||||||
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError>;
|
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError>;
|
||||||
|
|
@ -241,10 +298,105 @@ pub unsafe trait DbusType<'a>: Clone {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Reply<T: Message<'static>> {
|
||||||
|
socket: Rc<DbusSocket>,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
t: T::Generic<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PropertyValue<T: Property> {
|
||||||
|
reply: Reply<GetReply<'static, T::Type>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Property> Debug for PropertyValue<T>
|
||||||
|
where
|
||||||
|
for<'a> <T::Type as DbusType<'static>>::Generic<'a>: Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.get().fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Property> PropertyValue<T> {
|
||||||
|
pub fn get<'a>(&'a self) -> &'a <T::Type as DbusType<'static>>::Generic<'a> {
|
||||||
|
&self.reply.get().value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Message<'static>> Debug for Reply<T>
|
||||||
|
where
|
||||||
|
for<'a> T::Generic<'a>: Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.get().fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Message<'static>> Reply<T> {
|
||||||
|
pub fn get<'a>(&'a self) -> &'a T::Generic<'a> {
|
||||||
|
unsafe { mem::transmute(&self.t) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Message<'static>> Drop for Reply<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.socket.bufs.push(mem::take(&mut self.buf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AsyncReplySlot<T: Message<'static>> {
|
||||||
|
data: Cell<Option<Result<Reply<T>, DbusError>>>,
|
||||||
|
waker: Cell<Option<Waker>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AsyncReply<T: Message<'static>> {
|
||||||
|
socket: Rc<DbusSocket>,
|
||||||
|
serial: u32,
|
||||||
|
slot: Rc<AsyncReplySlot<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pin_project::pin_project]
|
||||||
|
pub struct AsyncProperty<T: Property> {
|
||||||
|
#[pin]
|
||||||
|
reply: AsyncReply<GetReply<'static, T::Type>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Message<'static>> Drop for AsyncReply<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.socket.reply_handlers.remove(&self.serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Message<'static>> Future for AsyncReply<T> {
|
||||||
|
type Output = Result<Reply<T>, DbusError>;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
if let Some(d) = self.slot.data.take() {
|
||||||
|
Poll::Ready(d)
|
||||||
|
} else {
|
||||||
|
self.slot.waker.set(Some(cx.waker().clone()));
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Property> Future for AsyncProperty<T> {
|
||||||
|
type Output = Result<PropertyValue<T>, DbusError>;
|
||||||
|
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
AsyncProperty::project(self)
|
||||||
|
.reply
|
||||||
|
.poll(cx)
|
||||||
|
.map(|r| r.map(|v| PropertyValue { reply: v }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use super::{
|
pub use super::{
|
||||||
types::{Bool, DictEntry, ObjectPath, Signature, Variant},
|
types::{Bool, DictEntry, ObjectPath, Signature, Variant},
|
||||||
DbusError, DbusType, Formatter, Message, MethodCall, Parser,
|
DbusError, DbusType, Formatter, Message, MethodCall, Parser, Property,
|
||||||
};
|
};
|
||||||
pub use std::borrow::Cow;
|
pub use std::borrow::Cow;
|
||||||
|
pub use std::rc::Rc;
|
||||||
|
pub use uapi::OwnedFd;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,15 @@ struct Auth {
|
||||||
impl Auth {
|
impl Auth {
|
||||||
async fn run(&mut self) {
|
async fn run(&mut self) {
|
||||||
if let Err(e) = self.handle_auth().await {
|
if let Err(e) = self.handle_auth().await {
|
||||||
log::error!("Could not authenticate to dbus socket: {}", ErrorFmt(e));
|
log::error!(
|
||||||
self.socket.dead.set(true);
|
"{}: Could not authenticate to dbus socket: {}",
|
||||||
self.socket.auth.take();
|
self.socket.bus_name,
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
self.socket.kill();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log::info!("Authenticated");
|
log::info!("{}: Authenticated", self.socket.bus_name);
|
||||||
self.socket.incoming.set(Some(
|
self.socket.incoming.set(Some(
|
||||||
self.socket.eng.spawn(handle_incoming(self.socket.clone())),
|
self.socket.eng.spawn(handle_incoming(self.socket.clone())),
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ impl DynamicType {
|
||||||
DynamicType::Fd => Variant::Fd(parser.read_fd()?),
|
DynamicType::Fd => Variant::Fd(parser.read_fd()?),
|
||||||
DynamicType::Array(el) => {
|
DynamicType::Array(el) => {
|
||||||
let len: u32 = parser.read_pod()?;
|
let len: u32 = parser.read_pod()?;
|
||||||
parser.align_to(el.alignment());
|
parser.align_to(el.alignment())?;
|
||||||
let len = len as usize;
|
let len = len as usize;
|
||||||
if parser.buf.len() - parser.pos < len {
|
if parser.buf.len() - parser.pos < len {
|
||||||
return Err(DbusError::UnexpectedEof);
|
return Err(DbusError::UnexpectedEof);
|
||||||
|
|
@ -165,12 +165,12 @@ impl DynamicType {
|
||||||
Variant::Array(el.deref().clone(), vals)
|
Variant::Array(el.deref().clone(), vals)
|
||||||
}
|
}
|
||||||
DynamicType::DictEntry(k, v) => {
|
DynamicType::DictEntry(k, v) => {
|
||||||
parser.align_to(8);
|
parser.align_to(8)?;
|
||||||
Variant::DictEntry(Box::new(k.parse(parser)?), Box::new(v.parse(parser)?))
|
Variant::DictEntry(Box::new(k.parse(parser)?), Box::new(v.parse(parser)?))
|
||||||
}
|
}
|
||||||
DynamicType::Struct(fields) => {
|
DynamicType::Struct(fields) => {
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
parser.align_to(8);
|
parser.align_to(8)?;
|
||||||
for field in fields {
|
for field in fields {
|
||||||
vals.push(field.parse(parser)?);
|
vals.push(field.parse(parser)?);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::dbus::auth::handle_auth;
|
use crate::dbus::auth::handle_auth;
|
||||||
use crate::dbus::{DbusError, DbusHolder, DbusSocket};
|
use crate::dbus::{DbusError, DbusHolder, DbusSocket};
|
||||||
use crate::{AsyncEngine, NumCell};
|
use crate::{org, AsyncEngine, ErrorFmt, NumCell, RunToplevel};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use uapi::c;
|
use uapi::c;
|
||||||
|
|
@ -10,6 +10,7 @@ impl DbusHolder {
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
eng: &Rc<AsyncEngine>,
|
eng: &Rc<AsyncEngine>,
|
||||||
addr: &str,
|
addr: &str,
|
||||||
|
name: &'static str,
|
||||||
) -> Result<Rc<DbusSocket>, DbusError> {
|
) -> Result<Rc<DbusSocket>, DbusError> {
|
||||||
if let Some(c) = self.socket.get() {
|
if let Some(c) = self.socket.get() {
|
||||||
if c.dead.get() {
|
if c.dead.get() {
|
||||||
|
|
@ -18,13 +19,18 @@ impl DbusHolder {
|
||||||
return Ok(c);
|
return Ok(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let socket = connect(eng, addr)?;
|
let socket = connect(eng, addr, name, &self.run_toplevel)?;
|
||||||
self.socket.set(Some(socket.clone()));
|
self.socket.set(Some(socket.clone()));
|
||||||
Ok(socket)
|
Ok(socket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect(eng: &Rc<AsyncEngine>, addr: &str) -> Result<Rc<DbusSocket>, DbusError> {
|
fn connect(
|
||||||
|
eng: &Rc<AsyncEngine>,
|
||||||
|
addr: &str,
|
||||||
|
name: &'static str,
|
||||||
|
run_toplevel: &Rc<RunToplevel>,
|
||||||
|
) -> Result<Rc<DbusSocket>, DbusError> {
|
||||||
let socket = match uapi::socket(
|
let socket = match uapi::socket(
|
||||||
c::AF_UNIX,
|
c::AF_UNIX,
|
||||||
c::SOCK_STREAM | c::SOCK_NONBLOCK | c::SOCK_CLOEXEC,
|
c::SOCK_STREAM | c::SOCK_NONBLOCK | c::SOCK_CLOEXEC,
|
||||||
|
|
@ -41,19 +47,37 @@ fn connect(eng: &Rc<AsyncEngine>, addr: &str) -> Result<Rc<DbusSocket>, DbusErro
|
||||||
return Err(DbusError::Connect(e.into()));
|
return Err(DbusError::Connect(e.into()));
|
||||||
}
|
}
|
||||||
let socket = Rc::new(DbusSocket {
|
let socket = Rc::new(DbusSocket {
|
||||||
|
bus_name: name,
|
||||||
fd: eng.fd(&Rc::new(socket))?,
|
fd: eng.fd(&Rc::new(socket))?,
|
||||||
eng: eng.clone(),
|
eng: eng.clone(),
|
||||||
next_serial: NumCell::new(1),
|
next_serial: NumCell::new(1),
|
||||||
bufs: Default::default(),
|
bufs: Default::default(),
|
||||||
|
unique_name: Default::default(),
|
||||||
outgoing: Default::default(),
|
outgoing: Default::default(),
|
||||||
waiters: Default::default(),
|
reply_handlers: Default::default(),
|
||||||
replies: Default::default(),
|
|
||||||
incoming: Default::default(),
|
incoming: Default::default(),
|
||||||
outgoing_: Default::default(),
|
outgoing_: Default::default(),
|
||||||
auth: Default::default(),
|
auth: Default::default(),
|
||||||
dead: Cell::new(false),
|
dead: Cell::new(false),
|
||||||
headers: Default::default(),
|
headers: Default::default(),
|
||||||
|
run_toplevel: run_toplevel.clone(),
|
||||||
});
|
});
|
||||||
|
let skt = socket.clone();
|
||||||
|
socket.call(
|
||||||
|
"org.freedesktop.DBus",
|
||||||
|
"/org/freedesktop/dbus",
|
||||||
|
org::freedesktop::dbus::Hello,
|
||||||
|
move |res| match res {
|
||||||
|
Ok(name) => {
|
||||||
|
log::info!("{}: Acquired unique name {}", skt.bus_name, name.name);
|
||||||
|
let _ = skt.unique_name.set(Rc::new(name.name.to_string()));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{}: Hello call failed: {}", skt.bus_name, ErrorFmt(e));
|
||||||
|
skt.kill();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
let future = eng.spawn(handle_auth(socket.clone()));
|
let future = eng.spawn(handle_auth(socket.clone()));
|
||||||
socket.auth.set(Some(future));
|
socket.auth.set(Some(future));
|
||||||
Ok(socket)
|
Ok(socket)
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,21 @@ use super::{
|
||||||
HDR_DESTINATION, HDR_ERROR_NAME, HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_REPLY_SERIAL,
|
HDR_DESTINATION, HDR_ERROR_NAME, HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_REPLY_SERIAL,
|
||||||
HDR_SENDER, HDR_SIGNATURE, HDR_UNIX_FDS,
|
HDR_SENDER, HDR_SIGNATURE, HDR_UNIX_FDS,
|
||||||
};
|
};
|
||||||
use crate::dbus::{DbusError, DbusSocket, DynamicType, Headers, Parser};
|
use crate::dbus::{
|
||||||
|
CallError, DbusError, DbusSocket, Headers, Parser, MSG_ERROR, MSG_METHOD_RETURN,
|
||||||
|
};
|
||||||
|
use crate::utils::ptr_ext::{MutPtrExt, PtrExt};
|
||||||
use crate::ErrorFmt;
|
use crate::ErrorFmt;
|
||||||
|
use std::cell::UnsafeCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use uapi::{c, Errno, MaybeUninitSliceExt, MsghdrMut, OwnedFd};
|
use uapi::{c, Errno, MaybeUninitSliceExt, MsghdrMut, OwnedFd};
|
||||||
|
|
||||||
pub async fn handle_incoming(socket: Rc<DbusSocket>) {
|
pub async fn handle_incoming(socket: Rc<DbusSocket>) {
|
||||||
let mut incoming = Incoming {
|
let mut incoming = Incoming {
|
||||||
socket,
|
socket,
|
||||||
msg_buf: vec![],
|
|
||||||
buf: Box::new([MaybeUninit::uninit(); 4096]),
|
buf: Box::new([MaybeUninit::uninit(); 4096]),
|
||||||
buf_start: 0,
|
buf_start: 0,
|
||||||
buf_end: 0,
|
buf_end: 0,
|
||||||
|
|
@ -25,7 +29,6 @@ pub async fn handle_incoming(socket: Rc<DbusSocket>) {
|
||||||
pub struct Incoming {
|
pub struct Incoming {
|
||||||
socket: Rc<DbusSocket>,
|
socket: Rc<DbusSocket>,
|
||||||
|
|
||||||
msg_buf: Vec<u8>,
|
|
||||||
buf: Box<[MaybeUninit<u8>; 4096]>,
|
buf: Box<[MaybeUninit<u8>; 4096]>,
|
||||||
buf_start: usize,
|
buf_start: usize,
|
||||||
buf_end: usize,
|
buf_end: usize,
|
||||||
|
|
@ -36,36 +39,46 @@ pub struct Incoming {
|
||||||
impl Incoming {
|
impl Incoming {
|
||||||
async fn run(&mut self) {
|
async fn run(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
|
if self.socket.dead.get() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if let Err(e) = self.handle_msg().await {
|
if let Err(e) = self.handle_msg().await {
|
||||||
log::error!("Could not process an incoming message: {}", ErrorFmt(e));
|
log::error!(
|
||||||
self.socket.incoming.take();
|
"{}: Could not process an incoming message: {}",
|
||||||
self.socket.outgoing_.take();
|
self.socket.bus_name,
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
self.socket.kill();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_msg(&mut self) -> Result<(), DbusError> {
|
async fn handle_msg(&mut self) -> Result<(), DbusError> {
|
||||||
self.msg_buf.clear();
|
let msg_buf_data = UnsafeCell::new(self.socket.bufs.pop().unwrap_or_default());
|
||||||
|
let msg_buf = unsafe { msg_buf_data.get().deref_mut() };
|
||||||
|
msg_buf.clear();
|
||||||
const FIXED_HEADER_SIZE: usize = 16;
|
const FIXED_HEADER_SIZE: usize = 16;
|
||||||
self.fill_msg_buf(FIXED_HEADER_SIZE).await?;
|
self.fill_msg_buf(FIXED_HEADER_SIZE, msg_buf).await?;
|
||||||
let endianess = self.msg_buf[0];
|
let endianess = msg_buf[0];
|
||||||
if (endianess == b'l') != cfg!(target_endian = "little") {
|
if (endianess == b'l') != cfg!(target_endian = "little") {
|
||||||
return Err(DbusError::InvalidEndianess);
|
return Err(DbusError::InvalidEndianess);
|
||||||
}
|
}
|
||||||
let msg_ty = self.msg_buf[1];
|
let msg_ty = msg_buf[1];
|
||||||
let flags = self.msg_buf[2];
|
let _flags = msg_buf[2];
|
||||||
let protocol = self.msg_buf[3];
|
let protocol = msg_buf[3];
|
||||||
if protocol != 1 {
|
if protocol != 1 {
|
||||||
return Err(DbusError::InvalidEndianess);
|
return Err(DbusError::InvalidProtocol);
|
||||||
}
|
}
|
||||||
let mut fields2 = [0u32; 3];
|
let mut fields2 = [0u32; 3];
|
||||||
uapi::pod_write(&self.msg_buf[4..], &mut fields2[..]).unwrap();
|
uapi::pod_write(&msg_buf[4..], &mut fields2[..]).unwrap();
|
||||||
let [body_len, serial, headers_len] = fields2;
|
let [body_len, _serial, headers_len] = fields2;
|
||||||
let dyn_header_len = headers_len + (headers_len.wrapping_neg() & 7);
|
let dyn_header_len = headers_len + (headers_len.wrapping_neg() & 7);
|
||||||
let remaining = dyn_header_len + body_len;
|
let remaining = dyn_header_len + body_len;
|
||||||
self.fill_msg_buf(remaining as usize).await?;
|
self.fill_msg_buf(remaining as usize, msg_buf).await?;
|
||||||
let headers = &self.msg_buf[FIXED_HEADER_SIZE..FIXED_HEADER_SIZE + headers_len as usize];
|
drop(msg_buf);
|
||||||
|
let msg_buf = unsafe { msg_buf_data.get().deref().deref() };
|
||||||
|
let headers = &msg_buf[FIXED_HEADER_SIZE..FIXED_HEADER_SIZE + headers_len as usize];
|
||||||
let headers = self.parse_headers(headers)?;
|
let headers = self.parse_headers(headers)?;
|
||||||
let unix_fds = headers.unix_fds.unwrap_or(0) as usize;
|
let unix_fds = headers.unix_fds.unwrap_or(0) as usize;
|
||||||
if self.fds.len() < unix_fds {
|
if self.fds.len() < unix_fds {
|
||||||
|
|
@ -73,19 +86,60 @@ impl Incoming {
|
||||||
}
|
}
|
||||||
let fds: Vec<_> = self.fds.drain(..unix_fds).collect();
|
let fds: Vec<_> = self.fds.drain(..unix_fds).collect();
|
||||||
let mut parser = Parser {
|
let mut parser = Parser {
|
||||||
buf: &self.msg_buf,
|
buf: &msg_buf,
|
||||||
pos: FIXED_HEADER_SIZE + dyn_header_len as usize,
|
pos: FIXED_HEADER_SIZE + dyn_header_len as usize,
|
||||||
fds: &fds,
|
fds: &fds,
|
||||||
};
|
};
|
||||||
log::info!("headers = {:?}", headers);
|
match msg_ty {
|
||||||
if let Some(sig) = headers.signature {
|
MSG_METHOD_RETURN | MSG_ERROR => {
|
||||||
let mut sig = sig.0.as_bytes();
|
let serial = match headers.reply_serial {
|
||||||
while sig.len() > 0 {
|
Some(s) => s,
|
||||||
let (dt, rem) = DynamicType::from_signature(sig)?;
|
_ => return Err(DbusError::NoReplySerial),
|
||||||
sig = rem;
|
};
|
||||||
let val = dt.parse(&mut parser)?;
|
if let Some(reply) = self.socket.reply_handlers.remove(&serial) {
|
||||||
log::info!("{:?}", val);
|
if msg_ty == MSG_ERROR {
|
||||||
|
let ename = match headers.error_name {
|
||||||
|
Some(n) => n.into_owned(),
|
||||||
|
_ => return Err(DbusError::NoErrorName),
|
||||||
|
};
|
||||||
|
let mut emsg = None;
|
||||||
|
if let Some(sig) = headers.signature {
|
||||||
|
if sig.0.starts_with("s") {
|
||||||
|
emsg = Some(parser.read_string()?.into_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let error = CallError {
|
||||||
|
name: ename,
|
||||||
|
msg: emsg,
|
||||||
|
};
|
||||||
|
reply.handle_error(&self.socket, DbusError::CallError(error));
|
||||||
|
} else {
|
||||||
|
let sig = headers.signature.as_deref().unwrap_or("");
|
||||||
|
if sig != reply.signature() {
|
||||||
|
log::error!(
|
||||||
|
"{}: Message reply has an invalid signature: expected: {}, actual: {}",
|
||||||
|
self.socket.bus_name,
|
||||||
|
sig,
|
||||||
|
reply.signature()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let buf = unsafe { std::mem::take(msg_buf_data.get().deref_mut()) };
|
||||||
|
if let Err(e) = reply.handle(&self.socket, &headers, &mut parser, buf) {
|
||||||
|
log::error!(
|
||||||
|
"{}: Could not handle reply: {}",
|
||||||
|
self.socket.bus_name,
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let msg_buf = msg_buf_data.into_inner();
|
||||||
|
if msg_buf.capacity() > 0 {
|
||||||
|
self.socket.bufs.push(msg_buf);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +167,7 @@ impl Incoming {
|
||||||
Ok(headers)
|
Ok(headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fill_msg_buf(&mut self, mut n: usize) -> Result<(), DbusError> {
|
async fn fill_msg_buf(&mut self, mut n: usize, buf: &mut Vec<u8>) -> Result<(), DbusError> {
|
||||||
while n > 0 {
|
while n > 0 {
|
||||||
if self.buf_start == self.buf_end {
|
if self.buf_start == self.buf_end {
|
||||||
while let Err(e) = self.recvmsg() {
|
while let Err(e) = self.recvmsg() {
|
||||||
|
|
@ -129,17 +183,9 @@ impl Incoming {
|
||||||
let read = n.min(self.buf_end - self.buf_start);
|
let read = n.min(self.buf_end - self.buf_start);
|
||||||
let buf_start = self.buf_start % self.buf.len();
|
let buf_start = self.buf_start % self.buf.len();
|
||||||
unsafe {
|
unsafe {
|
||||||
if buf_start + read <= self.buf.len() {
|
buf.extend_from_slice(
|
||||||
self.msg_buf.extend_from_slice(
|
self.buf[buf_start..buf_start + read].slice_assume_init_ref(),
|
||||||
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;
|
n -= read;
|
||||||
self.buf_start += read;
|
self.buf_start += read;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
use crate::dbus::{DbusMessage, DbusSocket};
|
use crate::dbus::{DbusMessage, DbusSocket};
|
||||||
use crate::utils::vec_ext::VecExt;
|
use crate::utils::vec_ext::{UninitVecExt, VecExt};
|
||||||
use crate::utils::vecstorage::VecStorage;
|
use crate::utils::vecstorage::VecStorage;
|
||||||
|
use crate::ErrorFmt;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use uapi::{c, Errno, Msghdr};
|
use uapi::{c, Errno, Msghdr};
|
||||||
|
|
@ -27,7 +29,7 @@ struct Outgoing {
|
||||||
socket: Rc<DbusSocket>,
|
socket: Rc<DbusSocket>,
|
||||||
|
|
||||||
msgs: VecDeque<DbusMessageOffset>,
|
msgs: VecDeque<DbusMessageOffset>,
|
||||||
cmsg: Vec<u8>,
|
cmsg: Vec<MaybeUninit<u8>>,
|
||||||
fds: Vec<c::c_int>,
|
fds: Vec<c::c_int>,
|
||||||
iovecs: VecStorage<NonNull<[u8]>>,
|
iovecs: VecStorage<NonNull<[u8]>>,
|
||||||
}
|
}
|
||||||
|
|
@ -37,7 +39,15 @@ impl Outgoing {
|
||||||
loop {
|
loop {
|
||||||
self.socket.outgoing.non_empty().await;
|
self.socket.outgoing.non_empty().await;
|
||||||
while let Err(e) = self.try_flush() {
|
while let Err(e) = self.try_flush() {
|
||||||
if e != Errno(c::EAGAIN) {}
|
if e != Errno(c::EAGAIN) {
|
||||||
|
log::error!(
|
||||||
|
"{}: Could not send a message to the bus: {}",
|
||||||
|
self.socket.bus_name,
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
self.socket.kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
let _ = self.socket.fd.writable().await;
|
let _ = self.socket.fd.writable().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -68,16 +78,14 @@ impl Outgoing {
|
||||||
self.fds.extend(fds.iter().map(|f| f.raw()));
|
self.fds.extend(fds.iter().map(|f| f.raw()));
|
||||||
let cmsg_space = uapi::cmsg_space(fds.len() * mem::size_of::<c::c_int>());
|
let cmsg_space = uapi::cmsg_space(fds.len() * mem::size_of::<c::c_int>());
|
||||||
self.cmsg.reserve(cmsg_space);
|
self.cmsg.reserve(cmsg_space);
|
||||||
let (_, mut spare) = self.cmsg.split_at_spare_mut_ext();
|
let (_, mut spare) = self.cmsg.split_at_spare_mut_bytes_ext();
|
||||||
let hdr = c::cmsghdr {
|
let hdr = c::cmsghdr {
|
||||||
cmsg_len: 0,
|
cmsg_len: 0,
|
||||||
cmsg_level: c::SOL_SOCKET,
|
cmsg_level: c::SOL_SOCKET,
|
||||||
cmsg_type: c::SCM_RIGHTS,
|
cmsg_type: c::SCM_RIGHTS,
|
||||||
};
|
};
|
||||||
let len = uapi::cmsg_write(&mut spare, hdr, &self.fds).unwrap();
|
let len = uapi::cmsg_write(&mut spare, hdr, &self.fds).unwrap();
|
||||||
unsafe {
|
self.cmsg.set_len_safe(len);
|
||||||
self.cmsg.set_len(len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let msg = Msghdr {
|
let msg = Msghdr {
|
||||||
iov: &iovecs[..],
|
iov: &iovecs[..],
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_pod<'b, T: DbusType<'b> + Pod>(&mut self) -> Result<T, DbusError> {
|
pub fn read_pod<'b, T: DbusType<'b> + Pod>(&mut self) -> Result<T, DbusError> {
|
||||||
self.align_to(T::ALIGNMENT);
|
self.align_to(T::ALIGNMENT)?;
|
||||||
match uapi::pod_read_init(&self.buf[self.pos..]) {
|
match uapi::pod_read_init(&self.buf[self.pos..]) {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
self.pos += mem::size_of::<T>();
|
self.pos += mem::size_of::<T>();
|
||||||
|
|
@ -74,7 +74,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_string_(&mut self, len: usize) -> Result<&'a str, DbusError> {
|
fn read_string_(&mut self, len: usize) -> Result<&'a str, DbusError> {
|
||||||
if self.buf.len() - self.pos < len + 1 {
|
if len == usize::MAX || self.buf.len() - self.pos < len + 1 {
|
||||||
return Err(DbusError::UnexpectedEof);
|
return Err(DbusError::UnexpectedEof);
|
||||||
}
|
}
|
||||||
let s = &self.buf[self.pos..self.pos + len];
|
let s = &self.buf[self.pos..self.pos + len];
|
||||||
|
|
@ -128,4 +128,14 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
parser.parse(self)
|
parser.parse(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_variant_as<T: DbusType<'a>>(&mut self) -> Result<T, DbusError> {
|
||||||
|
let sig = self.read_signature()?;
|
||||||
|
let mut sig = sig.0.as_bytes();
|
||||||
|
T::consume_signature(&mut sig)?;
|
||||||
|
if sig.len() > 0 {
|
||||||
|
return Err(DbusError::TrailingVariantSignature);
|
||||||
|
}
|
||||||
|
T::unmarshal(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
66
src/dbus/property.rs
Normal file
66
src/dbus/property.rs
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
use crate::dbus::{DbusError, DbusType, Formatter, Message, MethodCall, Parser};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Get<'a, T: DbusType<'static>> {
|
||||||
|
pub interface_name: Cow<'a, str>,
|
||||||
|
pub property_name: Cow<'a, str>,
|
||||||
|
pub _phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a, T: DbusType<'static>> Message<'a> for Get<'a, T> {
|
||||||
|
const SIGNATURE: &'static str = "ss";
|
||||||
|
const INTERFACE: &'static str = "org.freedesktop.DBus.Properties";
|
||||||
|
const MEMBER: &'static str = "Get";
|
||||||
|
type Generic<'b> = Get<'b, T>;
|
||||||
|
|
||||||
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
|
fmt.marshal(&self.interface_name);
|
||||||
|
fmt.marshal(&self.property_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
|
||||||
|
Ok(Self {
|
||||||
|
interface_name: parser.unmarshal()?,
|
||||||
|
property_name: parser.unmarshal()?,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_fds(&self) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: DbusType<'static>> MethodCall<'a> for Get<'a, T> {
|
||||||
|
type Reply = GetReply<'static, T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetReply<'a, T: DbusType<'a>> {
|
||||||
|
pub value: T,
|
||||||
|
pub _phantom: PhantomData<&'a ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a, T: DbusType<'a>> Message<'a> for GetReply<'a, T> {
|
||||||
|
const SIGNATURE: &'static str = "v";
|
||||||
|
const INTERFACE: &'static str = "org.freedesktop.DBus.Properties";
|
||||||
|
const MEMBER: &'static str = "Get";
|
||||||
|
type Generic<'b> = GetReply<'b, T::Generic<'b>>;
|
||||||
|
|
||||||
|
fn marshal(&self, _fmt: &mut Formatter) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
|
||||||
|
Ok(Self {
|
||||||
|
value: parser.read_variant_as()?,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_fds(&self) -> u32 {
|
||||||
|
self.value.num_fds()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,39 +1,150 @@
|
||||||
|
use crate::dbus::property::Get;
|
||||||
use crate::dbus::types::{ObjectPath, Signature, Variant};
|
use crate::dbus::types::{ObjectPath, Signature, Variant};
|
||||||
use crate::dbus::{
|
use crate::dbus::{
|
||||||
DbusMessage, DbusSocket, DbusType, Formatter, Message, MethodCall, HDR_DESTINATION,
|
AsyncProperty, AsyncReply, AsyncReplySlot, DbusError, DbusMessage, DbusSocket, DbusType,
|
||||||
HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_SIGNATURE, HDR_UNIX_FDS,
|
Formatter, Headers, Message, MethodCall, Parser, Property, Reply, ReplyHandler,
|
||||||
|
HDR_DESTINATION, HDR_INTERFACE, HDR_MEMBER, HDR_PATH, HDR_SIGNATURE, HDR_UNIX_FDS,
|
||||||
|
MSG_METHOD_CALL, NO_REPLY_EXPECTED,
|
||||||
};
|
};
|
||||||
|
use std::cell::Cell;
|
||||||
const MESSAGE_CALL: u8 = 1;
|
use std::marker::PhantomData;
|
||||||
const MESSAGE_RETURN: u8 = 2;
|
use std::mem;
|
||||||
const ERROR: u8 = 3;
|
use std::ops::DerefMut;
|
||||||
const SIGNAL: u8 = 4;
|
use std::rc::Rc;
|
||||||
|
use uapi::c;
|
||||||
|
|
||||||
impl DbusSocket {
|
impl DbusSocket {
|
||||||
pub fn new() -> Self {
|
pub(super) fn kill(self: &Rc<Self>) {
|
||||||
todo!();
|
self.dead.set(true);
|
||||||
|
self.auth.take();
|
||||||
|
self.incoming.take();
|
||||||
|
self.outgoing_.take();
|
||||||
|
let _ = uapi::shutdown(self.fd.raw(), c::SHUT_RDWR);
|
||||||
|
let replies = mem::take(self.reply_handlers.lock().deref_mut());
|
||||||
|
for (_, handler) in replies {
|
||||||
|
handler.handle_error(self, DbusError::Killed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_noreply<'a, T: MethodCall<'a>>(&self, destination: &str, path: &str, msg: T) {
|
pub fn call_noreply<'a, T: MethodCall<'a>>(&self, destination: &str, path: &str, msg: T) {
|
||||||
let (msg, _) = self.format_call(path, Some(destination), &msg);
|
if !self.dead.get() {
|
||||||
|
self.send_call(path, destination, NO_REPLY_EXPECTED, &msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serial(&self) -> u32 {
|
||||||
|
self.next_serial.fetch_add(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call<'a, T, F>(&self, destination: &str, path: &str, msg: T, f: F)
|
||||||
|
where
|
||||||
|
T: MethodCall<'a>,
|
||||||
|
F: for<'b> FnOnce(Result<&<T::Reply as Message<'static>>::Generic<'b>, DbusError>)
|
||||||
|
+ 'static,
|
||||||
|
{
|
||||||
|
if self.dead.get() {
|
||||||
|
self.run_toplevel
|
||||||
|
.schedule(move || f(Err(DbusError::Killed)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let serial = self.send_call(path, destination, 0, &msg);
|
||||||
|
self.reply_handlers
|
||||||
|
.set(serial, Box::new(SyncReplyHandler(f, PhantomData)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_async<'a, T>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
destination: &str,
|
||||||
|
path: &str,
|
||||||
|
msg: T,
|
||||||
|
) -> AsyncReply<T::Reply>
|
||||||
|
where
|
||||||
|
T: MethodCall<'a>,
|
||||||
|
{
|
||||||
|
if self.dead.get() {
|
||||||
|
return AsyncReply {
|
||||||
|
socket: self.clone(),
|
||||||
|
serial: self.serial(),
|
||||||
|
slot: Rc::new(AsyncReplySlot {
|
||||||
|
data: Cell::new(Some(Err(DbusError::Killed))),
|
||||||
|
waker: Cell::new(None),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let serial = self.send_call(path, destination, 0, &msg);
|
||||||
|
let slot = Rc::new(AsyncReplySlot {
|
||||||
|
data: Cell::new(None),
|
||||||
|
waker: Cell::new(None),
|
||||||
|
});
|
||||||
|
self.reply_handlers
|
||||||
|
.set(serial, Box::new(AsyncReplyHandler(slot.clone())));
|
||||||
|
AsyncReply {
|
||||||
|
socket: self.clone(),
|
||||||
|
serial,
|
||||||
|
slot,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<T, F>(&self, destination: &str, path: &str, f: F)
|
||||||
|
where
|
||||||
|
T: Property,
|
||||||
|
F: for<'b> FnOnce(Result<&<T::Type as DbusType<'static>>::Generic<'b>, DbusError>)
|
||||||
|
+ 'static,
|
||||||
|
{
|
||||||
|
let msg: Get<T::Type> = Get {
|
||||||
|
interface_name: T::INTERFACE.into(),
|
||||||
|
property_name: T::PROPERTY.into(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
};
|
||||||
|
self.call(destination, path, msg, move |res| {
|
||||||
|
f(res.map(|v| &v.value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_async<T: Property>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
destination: &str,
|
||||||
|
path: &str,
|
||||||
|
) -> AsyncProperty<T> {
|
||||||
|
let msg: Get<T::Type> = Get {
|
||||||
|
interface_name: T::INTERFACE.into(),
|
||||||
|
property_name: T::PROPERTY.into(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
};
|
||||||
|
AsyncProperty {
|
||||||
|
reply: self.call_async(destination, path, msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_call<'a, T: Message<'a>>(
|
||||||
|
&self,
|
||||||
|
path: &str,
|
||||||
|
destination: &str,
|
||||||
|
flags: u8,
|
||||||
|
msg: &T,
|
||||||
|
) -> u32 {
|
||||||
|
let (msg, serial) = self.format_call(path, destination, flags, msg);
|
||||||
self.outgoing.push(msg);
|
self.outgoing.push(msg);
|
||||||
|
serial
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_call<'a, T: Message<'a>>(
|
fn format_call<'a, T: Message<'a>>(
|
||||||
&self,
|
&self,
|
||||||
path: &str,
|
path: &str,
|
||||||
destination: Option<&str>,
|
destination: &str,
|
||||||
|
flags: u8,
|
||||||
msg: &T,
|
msg: &T,
|
||||||
) -> (DbusMessage, u32) {
|
) -> (DbusMessage, u32) {
|
||||||
let num_fds = msg.num_fds();
|
let num_fds = msg.num_fds();
|
||||||
let mut fds = Vec::with_capacity(num_fds as _);
|
let mut fds = Vec::with_capacity(num_fds as _);
|
||||||
let serial = self.next_serial.fetch_add(1);
|
let serial = self.serial();
|
||||||
let mut buf = self.bufs.pop().unwrap_or_default();
|
let mut buf = self.bufs.pop().unwrap_or_default();
|
||||||
buf.clear();
|
buf.clear();
|
||||||
let mut fmt = Formatter::new(&mut fds, &mut buf);
|
let mut fmt = Formatter::new(&mut fds, &mut buf);
|
||||||
self.format_header(
|
self.format_header(
|
||||||
&mut fmt,
|
&mut fmt,
|
||||||
MESSAGE_CALL,
|
MSG_METHOD_CALL,
|
||||||
|
flags,
|
||||||
serial,
|
serial,
|
||||||
path,
|
path,
|
||||||
T::INTERFACE,
|
T::INTERFACE,
|
||||||
|
|
@ -53,11 +164,12 @@ impl DbusSocket {
|
||||||
&self,
|
&self,
|
||||||
fmt: &mut Formatter,
|
fmt: &mut Formatter,
|
||||||
ty: u8,
|
ty: u8,
|
||||||
|
flags: u8,
|
||||||
serial: u32,
|
serial: u32,
|
||||||
path: &str,
|
path: &str,
|
||||||
interface: &str,
|
interface: &str,
|
||||||
member: &str,
|
member: &str,
|
||||||
destination: Option<&str>,
|
destination: &str,
|
||||||
signature: &str,
|
signature: &str,
|
||||||
fds: u32,
|
fds: u32,
|
||||||
) {
|
) {
|
||||||
|
|
@ -66,7 +178,7 @@ impl DbusSocket {
|
||||||
#[cfg(not(target_endian = "little"))]
|
#[cfg(not(target_endian = "little"))]
|
||||||
b'b'.marshal(fmt);
|
b'b'.marshal(fmt);
|
||||||
ty.marshal(fmt);
|
ty.marshal(fmt);
|
||||||
0u8.marshal(fmt);
|
flags.marshal(fmt);
|
||||||
1u8.marshal(fmt);
|
1u8.marshal(fmt);
|
||||||
0u32.marshal(fmt);
|
0u32.marshal(fmt);
|
||||||
serial.marshal(fmt);
|
serial.marshal(fmt);
|
||||||
|
|
@ -75,9 +187,7 @@ impl DbusSocket {
|
||||||
headers.push((HDR_PATH, Variant::ObjectPath(ObjectPath(path.into()))));
|
headers.push((HDR_PATH, Variant::ObjectPath(ObjectPath(path.into()))));
|
||||||
headers.push((HDR_INTERFACE, Variant::String(interface.into())));
|
headers.push((HDR_INTERFACE, Variant::String(interface.into())));
|
||||||
headers.push((HDR_MEMBER, Variant::String(member.into())));
|
headers.push((HDR_MEMBER, Variant::String(member.into())));
|
||||||
if let Some(dst) = destination {
|
headers.push((HDR_DESTINATION, Variant::String(destination.into())));
|
||||||
headers.push((HDR_DESTINATION, Variant::String(dst.into())));
|
|
||||||
}
|
|
||||||
if signature.len() > 0 {
|
if signature.len() > 0 {
|
||||||
headers.push((
|
headers.push((
|
||||||
HDR_SIGNATURE,
|
HDR_SIGNATURE,
|
||||||
|
|
@ -91,3 +201,72 @@ impl DbusSocket {
|
||||||
fmt.pad_to(8);
|
fmt.pad_to(8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SyncReplyHandler<T, F>(F, PhantomData<T>);
|
||||||
|
|
||||||
|
unsafe impl<T, F> ReplyHandler for SyncReplyHandler<T, F>
|
||||||
|
where
|
||||||
|
T: Message<'static>,
|
||||||
|
F: for<'b> FnOnce(Result<&T::Generic<'b>, DbusError>),
|
||||||
|
{
|
||||||
|
fn signature(&self) -> &str {
|
||||||
|
T::SIGNATURE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_error(self: Box<Self>, _socket: &Rc<DbusSocket>, error: DbusError) {
|
||||||
|
(self.0)(Err(error))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle<'a>(
|
||||||
|
self: Box<Self>,
|
||||||
|
socket: &Rc<DbusSocket>,
|
||||||
|
_headers: &Headers,
|
||||||
|
parser: &mut Parser<'a>,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
) -> Result<(), DbusError> {
|
||||||
|
let msg = <T::Generic<'a> as Message>::unmarshal(parser)?;
|
||||||
|
(self.0)(Ok(&msg));
|
||||||
|
socket.bufs.push(buf);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AsyncReplyHandler<T: Message<'static>>(Rc<AsyncReplySlot<T>>);
|
||||||
|
|
||||||
|
unsafe impl<T> ReplyHandler for AsyncReplyHandler<T>
|
||||||
|
where
|
||||||
|
T: Message<'static>,
|
||||||
|
{
|
||||||
|
fn signature(&self) -> &str {
|
||||||
|
T::SIGNATURE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_error(self: Box<Self>, _socket: &Rc<DbusSocket>, error: DbusError) {
|
||||||
|
self.0.data.set(Some(Err(error)));
|
||||||
|
if let Some(waker) = self.0.waker.take() {
|
||||||
|
waker.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle<'a>(
|
||||||
|
self: Box<Self>,
|
||||||
|
socket: &Rc<DbusSocket>,
|
||||||
|
_headers: &Headers,
|
||||||
|
parser: &mut Parser<'a>,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
) -> Result<(), DbusError> {
|
||||||
|
let msg = <T::Generic<'static> as Message<'static>>::unmarshal(unsafe {
|
||||||
|
mem::transmute::<&mut Parser<'a>, &mut Parser<'static>>(parser)
|
||||||
|
})?;
|
||||||
|
let reply = Reply {
|
||||||
|
socket: socket.clone(),
|
||||||
|
buf,
|
||||||
|
t: msg,
|
||||||
|
};
|
||||||
|
self.0.data.set(Some(Ok(reply)));
|
||||||
|
if let Some(waker) = self.0.waker.take() {
|
||||||
|
waker.wake();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,37 @@ use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use uapi::{OwnedFd, Packed, Pod};
|
use uapi::{OwnedFd, Packed, Pod};
|
||||||
|
|
||||||
|
macro_rules! consume_signature_body {
|
||||||
|
($s:expr, $ty:expr) => {{
|
||||||
|
if $s.is_empty() {
|
||||||
|
return Err(DbusError::EmptySignature);
|
||||||
|
}
|
||||||
|
if $s[0] != $ty {
|
||||||
|
return Err(DbusError::InvalidSignatureType);
|
||||||
|
}
|
||||||
|
*$s = &(*$s)[1..];
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! signature {
|
||||||
|
($ty:expr) => {
|
||||||
|
fn consume_signature(s: &mut &[u8]) -> Result<(), DbusError> {
|
||||||
|
consume_signature_body!(s, $ty);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_signature(w: &mut Vec<u8>) {
|
||||||
|
w.push(TY_BYTE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl<'a> DbusType<'a> for u8 {
|
unsafe impl<'a> DbusType<'a> for u8 {
|
||||||
const ALIGNMENT: usize = 1;
|
const ALIGNMENT: usize = 1;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
|
type Generic<'b> = Self;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_BYTE);
|
||||||
w.push(TY_BYTE);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_packed(self);
|
fmt.write_packed(self);
|
||||||
|
|
@ -38,10 +62,9 @@ unsafe impl Packed for Bool {}
|
||||||
unsafe impl<'a> DbusType<'a> for Bool {
|
unsafe impl<'a> DbusType<'a> for Bool {
|
||||||
const ALIGNMENT: usize = 4;
|
const ALIGNMENT: usize = 4;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
|
type Generic<'b> = Self;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_BOOLEAN);
|
||||||
w.push(TY_BOOLEAN);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_packed(self);
|
fmt.write_packed(self);
|
||||||
|
|
@ -55,10 +78,9 @@ unsafe impl<'a> DbusType<'a> for Bool {
|
||||||
unsafe impl<'a> DbusType<'a> for i16 {
|
unsafe impl<'a> DbusType<'a> for i16 {
|
||||||
const ALIGNMENT: usize = 2;
|
const ALIGNMENT: usize = 2;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
|
type Generic<'b> = Self;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_INT16);
|
||||||
w.push(TY_INT16);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_packed(self);
|
fmt.write_packed(self);
|
||||||
|
|
@ -72,10 +94,9 @@ unsafe impl<'a> DbusType<'a> for i16 {
|
||||||
unsafe impl<'a> DbusType<'a> for u16 {
|
unsafe impl<'a> DbusType<'a> for u16 {
|
||||||
const ALIGNMENT: usize = 2;
|
const ALIGNMENT: usize = 2;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
|
type Generic<'b> = Self;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_UINT16);
|
||||||
w.push(TY_UINT16)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_packed(self);
|
fmt.write_packed(self);
|
||||||
|
|
@ -89,10 +110,9 @@ unsafe impl<'a> DbusType<'a> for u16 {
|
||||||
unsafe impl<'a> DbusType<'a> for i32 {
|
unsafe impl<'a> DbusType<'a> for i32 {
|
||||||
const ALIGNMENT: usize = 4;
|
const ALIGNMENT: usize = 4;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
|
type Generic<'b> = Self;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_INT32);
|
||||||
w.push(TY_INT32)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_packed(self);
|
fmt.write_packed(self);
|
||||||
|
|
@ -106,10 +126,9 @@ unsafe impl<'a> DbusType<'a> for i32 {
|
||||||
unsafe impl<'a> DbusType<'a> for u32 {
|
unsafe impl<'a> DbusType<'a> for u32 {
|
||||||
const ALIGNMENT: usize = 4;
|
const ALIGNMENT: usize = 4;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
|
type Generic<'b> = Self;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_UINT32);
|
||||||
w.push(TY_UINT32)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_packed(self);
|
fmt.write_packed(self);
|
||||||
|
|
@ -123,10 +142,9 @@ unsafe impl<'a> DbusType<'a> for u32 {
|
||||||
unsafe impl<'a> DbusType<'a> for AlignedI64 {
|
unsafe impl<'a> DbusType<'a> for AlignedI64 {
|
||||||
const ALIGNMENT: usize = 8;
|
const ALIGNMENT: usize = 8;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
|
type Generic<'b> = Self;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_INT64);
|
||||||
w.push(TY_INT64)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_packed(self);
|
fmt.write_packed(self);
|
||||||
|
|
@ -140,10 +158,9 @@ unsafe impl<'a> DbusType<'a> for AlignedI64 {
|
||||||
unsafe impl<'a> DbusType<'a> for AlignedU64 {
|
unsafe impl<'a> DbusType<'a> for AlignedU64 {
|
||||||
const ALIGNMENT: usize = 8;
|
const ALIGNMENT: usize = 8;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
|
type Generic<'b> = Self;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_UINT64);
|
||||||
w.push(TY_UINT64)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_packed(self);
|
fmt.write_packed(self);
|
||||||
|
|
@ -157,10 +174,9 @@ unsafe impl<'a> DbusType<'a> for AlignedU64 {
|
||||||
unsafe impl<'a> DbusType<'a> for AlignedF64 {
|
unsafe impl<'a> DbusType<'a> for AlignedF64 {
|
||||||
const ALIGNMENT: usize = 8;
|
const ALIGNMENT: usize = 8;
|
||||||
const IS_POD: bool = true;
|
const IS_POD: bool = true;
|
||||||
|
type Generic<'b> = Self;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_DOUBLE);
|
||||||
w.push(TY_DOUBLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_packed(self);
|
fmt.write_packed(self);
|
||||||
|
|
@ -174,10 +190,9 @@ unsafe impl<'a> DbusType<'a> for AlignedF64 {
|
||||||
unsafe impl<'a> DbusType<'a> for Cow<'a, str> {
|
unsafe impl<'a> DbusType<'a> for Cow<'a, str> {
|
||||||
const ALIGNMENT: usize = 4;
|
const ALIGNMENT: usize = 4;
|
||||||
const IS_POD: bool = false;
|
const IS_POD: bool = false;
|
||||||
|
type Generic<'b> = Cow<'b, str>;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_STRING);
|
||||||
w.push(TY_STRING)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_str(self);
|
fmt.write_str(self);
|
||||||
|
|
@ -191,13 +206,20 @@ unsafe impl<'a> DbusType<'a> for Cow<'a, str> {
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Signature<'a>(pub Cow<'a, str>);
|
pub struct Signature<'a>(pub Cow<'a, str>);
|
||||||
|
|
||||||
|
impl<'a> Deref for Signature<'a> {
|
||||||
|
type Target = str;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl<'a> DbusType<'a> for Signature<'a> {
|
unsafe impl<'a> DbusType<'a> for Signature<'a> {
|
||||||
const ALIGNMENT: usize = 1;
|
const ALIGNMENT: usize = 1;
|
||||||
const IS_POD: bool = false;
|
const IS_POD: bool = false;
|
||||||
|
type Generic<'b> = Signature<'b>;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_SIGNATURE);
|
||||||
w.push(TY_SIGNATURE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_signature(self.0.as_bytes());
|
fmt.write_signature(self.0.as_bytes());
|
||||||
|
|
@ -211,13 +233,20 @@ unsafe impl<'a> DbusType<'a> for Signature<'a> {
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct ObjectPath<'a>(pub Cow<'a, str>);
|
pub struct ObjectPath<'a>(pub Cow<'a, str>);
|
||||||
|
|
||||||
|
impl<'a> Deref for ObjectPath<'a> {
|
||||||
|
type Target = str;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl<'a> DbusType<'a> for ObjectPath<'a> {
|
unsafe impl<'a> DbusType<'a> for ObjectPath<'a> {
|
||||||
const ALIGNMENT: usize = 4;
|
const ALIGNMENT: usize = 4;
|
||||||
const IS_POD: bool = false;
|
const IS_POD: bool = false;
|
||||||
|
type Generic<'b> = ObjectPath<'b>;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_OBJECT_PATH);
|
||||||
w.push(TY_OBJECT_PATH)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_str(&self.0);
|
fmt.write_str(&self.0);
|
||||||
|
|
@ -228,9 +257,35 @@ unsafe impl<'a> DbusType<'a> for ObjectPath<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a> DbusType<'a> for Rc<OwnedFd> {
|
||||||
|
const ALIGNMENT: usize = 4;
|
||||||
|
const IS_POD: bool = false;
|
||||||
|
type Generic<'b> = Self;
|
||||||
|
|
||||||
|
signature!(TY_UNIX_FD);
|
||||||
|
|
||||||
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
|
fmt.write_fd(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError> {
|
||||||
|
parser.read_fd()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_fds(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl<'a, T: DbusType<'a>> DbusType<'a> for Cow<'a, [T]> {
|
unsafe impl<'a, T: DbusType<'a>> DbusType<'a> for Cow<'a, [T]> {
|
||||||
const ALIGNMENT: usize = 4;
|
const ALIGNMENT: usize = 4;
|
||||||
const IS_POD: bool = false;
|
const IS_POD: bool = false;
|
||||||
|
type Generic<'b> = Cow<'b, [T::Generic<'b>]>;
|
||||||
|
|
||||||
|
fn consume_signature(s: &mut &[u8]) -> Result<(), DbusError> {
|
||||||
|
consume_signature_body!(s, TY_ARRAY);
|
||||||
|
T::consume_signature(s)
|
||||||
|
}
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
fn write_signature(w: &mut Vec<u8>) {
|
||||||
w.push(TY_ARRAY);
|
w.push(TY_ARRAY);
|
||||||
|
|
@ -263,6 +318,15 @@ pub struct DictEntry<K, V> {
|
||||||
unsafe impl<'a, K: DbusType<'a>, V: DbusType<'a>> DbusType<'a> for DictEntry<K, V> {
|
unsafe impl<'a, K: DbusType<'a>, V: DbusType<'a>> DbusType<'a> for DictEntry<K, V> {
|
||||||
const ALIGNMENT: usize = 8;
|
const ALIGNMENT: usize = 8;
|
||||||
const IS_POD: bool = false;
|
const IS_POD: bool = false;
|
||||||
|
type Generic<'b> = DictEntry<K::Generic<'b>, V::Generic<'b>>;
|
||||||
|
|
||||||
|
fn consume_signature(s: &mut &[u8]) -> Result<(), DbusError> {
|
||||||
|
consume_signature_body!(s, b'{');
|
||||||
|
K::consume_signature(s)?;
|
||||||
|
V::consume_signature(s)?;
|
||||||
|
consume_signature_body!(s, b'}');
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
fn write_signature(w: &mut Vec<u8>) {
|
||||||
w.push(b'{');
|
w.push(b'{');
|
||||||
|
|
@ -292,6 +356,16 @@ macro_rules! tuple {
|
||||||
unsafe impl<'a, $($p: DbusType<'a>),*> DbusType<'a> for ($($p,)*) {
|
unsafe impl<'a, $($p: DbusType<'a>),*> DbusType<'a> for ($($p,)*) {
|
||||||
const ALIGNMENT: usize = 8;
|
const ALIGNMENT: usize = 8;
|
||||||
const IS_POD: bool = false;
|
const IS_POD: bool = false;
|
||||||
|
type Generic<'b> = ($($p::Generic<'b>,)*);
|
||||||
|
|
||||||
|
fn consume_signature(s: &mut &[u8]) -> Result<(), DbusError> {
|
||||||
|
consume_signature_body!(s, b'(');
|
||||||
|
$(
|
||||||
|
$p::consume_signature(s)?;
|
||||||
|
)*
|
||||||
|
consume_signature_body!(s, b')');
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
fn write_signature(w: &mut Vec<u8>) {
|
||||||
w.push(b'(');
|
w.push(b'(');
|
||||||
|
|
@ -429,10 +503,9 @@ impl<'a> Variant<'a> {
|
||||||
unsafe impl<'a> DbusType<'a> for Variant<'a> {
|
unsafe impl<'a> DbusType<'a> for Variant<'a> {
|
||||||
const ALIGNMENT: usize = 1;
|
const ALIGNMENT: usize = 1;
|
||||||
const IS_POD: bool = false;
|
const IS_POD: bool = false;
|
||||||
|
type Generic<'b> = Variant<'b>;
|
||||||
|
|
||||||
fn write_signature(w: &mut Vec<u8>) {
|
signature!(TY_VARIANT);
|
||||||
w.push(TY_VARIANT);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn marshal(&self, fmt: &mut Formatter) {
|
fn marshal(&self, fmt: &mut Formatter) {
|
||||||
fmt.write_variant(self);
|
fmt.write_variant(self);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ impl IoIn {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.scratch.set_len(len);
|
self.scratch.set_len(len);
|
||||||
}
|
}
|
||||||
let res = bincode::decode_from_slice::<T, _>(&&self.scratch, bincode_ops());
|
let res = bincode::decode_from_slice::<T, _>(&self.scratch, bincode_ops());
|
||||||
match res {
|
match res {
|
||||||
Ok((msg, _)) => Ok(msg),
|
Ok((msg, _)) => Ok(msg),
|
||||||
Err(e) => Err(ForkerError::DecodeFailed(e)),
|
Err(e) => Err(ForkerError::DecodeFailed(e)),
|
||||||
|
|
|
||||||
51
src/main.rs
51
src/main.rs
|
|
@ -19,7 +19,7 @@ use crate::backends::dummy::DummyBackend;
|
||||||
use crate::backends::xorg::{XorgBackend, XorgBackendError};
|
use crate::backends::xorg::{XorgBackend, XorgBackendError};
|
||||||
use crate::client::Clients;
|
use crate::client::Clients;
|
||||||
use crate::clientmem::ClientMemError;
|
use crate::clientmem::ClientMemError;
|
||||||
use crate::dbus::Dbus;
|
use crate::dbus::{Dbus, FALSE};
|
||||||
use crate::event_loop::EventLoopError;
|
use crate::event_loop::EventLoopError;
|
||||||
use crate::forker::ForkerError;
|
use crate::forker::ForkerError;
|
||||||
use crate::globals::Globals;
|
use crate::globals::Globals;
|
||||||
|
|
@ -40,6 +40,7 @@ use crate::utils::clonecell::CloneCell;
|
||||||
use crate::utils::errorfmt::ErrorFmt;
|
use crate::utils::errorfmt::ErrorFmt;
|
||||||
use crate::utils::numcell::NumCell;
|
use crate::utils::numcell::NumCell;
|
||||||
use crate::utils::queue::AsyncQueue;
|
use crate::utils::queue::AsyncQueue;
|
||||||
|
use crate::utils::run_toplevel::RunToplevel;
|
||||||
use crate::wheel::WheelError;
|
use crate::wheel::WheelError;
|
||||||
use crate::wire_dbus::org;
|
use crate::wire_dbus::org;
|
||||||
use crate::xkbcommon::XkbContext;
|
use crate::xkbcommon::XkbContext;
|
||||||
|
|
@ -47,7 +48,6 @@ use acceptor::Acceptor;
|
||||||
use async_engine::AsyncEngine;
|
use async_engine::AsyncEngine;
|
||||||
use event_loop::EventLoop;
|
use event_loop::EventLoop;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
@ -140,6 +140,7 @@ fn main_() -> Result<(), MainError> {
|
||||||
let xkb_keymap = xkb_ctx.keymap_from_str(include_str!("keymap.xkb")).unwrap();
|
let xkb_keymap = xkb_ctx.keymap_from_str(include_str!("keymap.xkb")).unwrap();
|
||||||
let wheel = Wheel::install(&el)?;
|
let wheel = Wheel::install(&el)?;
|
||||||
let engine = AsyncEngine::install(&el, &wheel)?;
|
let engine = AsyncEngine::install(&el, &wheel)?;
|
||||||
|
let (_run_toplevel_future, run_toplevel) = RunToplevel::install(&engine);
|
||||||
let node_ids = NodeIds::default();
|
let node_ids = NodeIds::default();
|
||||||
let state = Rc::new(State {
|
let state = Rc::new(State {
|
||||||
xkb_ctx,
|
xkb_ctx,
|
||||||
|
|
@ -175,21 +176,39 @@ fn main_() -> Result<(), MainError> {
|
||||||
pending_container_titles: Default::default(),
|
pending_container_titles: Default::default(),
|
||||||
pending_float_layout: Default::default(),
|
pending_float_layout: Default::default(),
|
||||||
pending_float_titles: Default::default(),
|
pending_float_titles: Default::default(),
|
||||||
dbus: Dbus::new(&engine),
|
dbus: Dbus::new(&engine, &run_toplevel),
|
||||||
|
});
|
||||||
|
let _future = state.eng.spawn({
|
||||||
|
let dbus = state.dbus.system().unwrap();
|
||||||
|
async move {
|
||||||
|
const LOGIND: &str = "org.freedesktop.login1";
|
||||||
|
let reply = dbus
|
||||||
|
.call_async(
|
||||||
|
LOGIND,
|
||||||
|
"/org/freedesktop/login1",
|
||||||
|
org::freedesktop::login1::manager::GetSession {
|
||||||
|
session_id: std::env::var("XDG_SESSION_ID").unwrap().into(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let reply = dbus
|
||||||
|
.call_async(
|
||||||
|
LOGIND,
|
||||||
|
&reply.get().object_path,
|
||||||
|
org::freedesktop::login1::session::TakeControl { force: FALSE },
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
log::info!("{:?}", reply);
|
||||||
|
let reply = dbus
|
||||||
|
.get_async::<org::freedesktop::login1::manager::BootLoaderEntries>(
|
||||||
|
LOGIND,
|
||||||
|
"/org/freedesktop/login1",
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
log::info!("{:?}", reply);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
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);
|
forker.install(&state);
|
||||||
let backend = XorgBackend::new(&state)?;
|
let backend = XorgBackend::new(&state)?;
|
||||||
state.backend.set(backend);
|
state.backend.set(backend);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ pub mod linkedlist;
|
||||||
pub mod numcell;
|
pub mod numcell;
|
||||||
pub mod ptr_ext;
|
pub mod ptr_ext;
|
||||||
pub mod queue;
|
pub mod queue;
|
||||||
|
pub mod run_toplevel;
|
||||||
pub mod smallmap;
|
pub mod smallmap;
|
||||||
pub mod stack;
|
pub mod stack;
|
||||||
pub mod tri;
|
pub mod tri;
|
||||||
|
|
|
||||||
38
src/utils/run_toplevel.rs
Normal file
38
src/utils/run_toplevel.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
use crate::async_engine::SpawnedFuture;
|
||||||
|
use crate::{AsyncEngine, AsyncQueue};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct RunToplevelFuture {
|
||||||
|
_future: SpawnedFuture<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RunToplevel {
|
||||||
|
queue: AsyncQueue<Box<dyn FnOnce()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunToplevel {
|
||||||
|
pub fn install(eng: &Rc<AsyncEngine>) -> (RunToplevelFuture, Rc<RunToplevel>) {
|
||||||
|
let slf = Rc::new(RunToplevel {
|
||||||
|
queue: Default::default(),
|
||||||
|
});
|
||||||
|
let future = eng.spawn({
|
||||||
|
let slf = slf.clone();
|
||||||
|
async move {
|
||||||
|
loop {
|
||||||
|
let f = slf.queue.pop().await;
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let future = RunToplevelFuture { _future: future };
|
||||||
|
(future, slf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn schedule<F: FnOnce() + 'static>(&self, f: F) {
|
||||||
|
self.schedule_dyn(Box::new(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule_dyn(&self, f: Box<dyn FnOnce()>) {
|
||||||
|
self.queue.push(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ use std::slice;
|
||||||
|
|
||||||
pub trait VecExt<T> {
|
pub trait VecExt<T> {
|
||||||
fn split_at_spare_mut_ext(&mut self) -> (&mut [T], &mut [MaybeUninit<T>]);
|
fn split_at_spare_mut_ext(&mut self) -> (&mut [T], &mut [MaybeUninit<T>]);
|
||||||
|
fn split_at_spare_mut_bytes_ext(&mut self) -> (&mut [T], &mut [MaybeUninit<u8>]);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> VecExt<T> for Vec<T> {
|
impl<T> VecExt<T> for Vec<T> {
|
||||||
|
|
@ -20,4 +21,22 @@ impl<T> VecExt<T> for Vec<T> {
|
||||||
(initialized, spare)
|
(initialized, spare)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn split_at_spare_mut_bytes_ext(&mut self) -> (&mut [T], &mut [MaybeUninit<u8>]) {
|
||||||
|
let (l, r) = self.split_at_spare_mut_ext();
|
||||||
|
unsafe { (l, uapi::as_maybe_uninit_bytes_mut2(r)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UninitVecExt<T> {
|
||||||
|
fn set_len_safe(&mut self, n: usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> UninitVecExt<T> for Vec<MaybeUninit<T>> {
|
||||||
|
fn set_len_safe(&mut self, n: usize) {
|
||||||
|
assert!(n <= self.capacity());
|
||||||
|
unsafe {
|
||||||
|
self.set_len(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
wire-dbus/org.freedesktop.DBus.Properties.txt
Normal file
10
wire-dbus/org.freedesktop.DBus.Properties.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
fn Get(interface_name: string, property_name: string) {
|
||||||
|
value: variant,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Set(interface_name: string, property_name: string, value: variant) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn GetAll(interface_name: string) {
|
||||||
|
props: array(dict(string, variant)),
|
||||||
|
}
|
||||||
|
|
@ -3,3 +3,5 @@ fn GetSession(
|
||||||
) {
|
) {
|
||||||
object_path: object_path,
|
object_path: object_path,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prop BootLoaderEntries = array(string)
|
||||||
|
|
|
||||||
10
wire-dbus/org.freedesktop.login1.Session.txt
Normal file
10
wire-dbus/org.freedesktop.login1.Session.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
fn TakeControl(force: bool) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn TakeDevice(major: u32, minor: u32) {
|
||||||
|
fd: fd,
|
||||||
|
inactive: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn PauseDeviceComplete(major: u32, minor: u32) { }
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue