autocommit 2022-03-22 23:24:17 CET
This commit is contained in:
parent
18806a38fb
commit
2ff60ff817
36 changed files with 4934 additions and 237 deletions
103
src/xcon/consts.rs
Normal file
103
src/xcon/consts.rs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
pub const XGE_EVENT: u8 = 35;
|
||||
|
||||
pub const INPUT_DEVICE_ALL: u16 = 0;
|
||||
pub const INPUT_DEVICE_ALL_MASTER: u16 = 1;
|
||||
|
||||
pub const WINDOW_CLASS_INPUT_OUTPUT: u16 = 1;
|
||||
|
||||
pub const PROP_MODE_REPLACE: u8 = 0;
|
||||
|
||||
pub const ATOM_WM_CLASS: u32 = 67;
|
||||
pub const ATOM_STRING: u32 = 31;
|
||||
|
||||
pub const EVENT_MASK_NO_EVENT: u32 = 0;
|
||||
pub const EVENT_MASK_KEY_PRESS: u32 = 1;
|
||||
pub const EVENT_MASK_KEY_RELEASE: u32 = 2;
|
||||
pub const EVENT_MASK_BUTTON_PRESS: u32 = 4;
|
||||
pub const EVENT_MASK_BUTTON_RELEASE: u32 = 8;
|
||||
pub const EVENT_MASK_ENTER_WINDOW: u32 = 16;
|
||||
pub const EVENT_MASK_LEAVE_WINDOW: u32 = 32;
|
||||
pub const EVENT_MASK_POINTER_MOTION: u32 = 64;
|
||||
pub const EVENT_MASK_POINTER_MOTION_HINT: u32 = 128;
|
||||
pub const EVENT_MASK_BUTTON_1_MOTION: u32 = 256;
|
||||
pub const EVENT_MASK_BUTTON_2_MOTION: u32 = 512;
|
||||
pub const EVENT_MASK_BUTTON_3_MOTION: u32 = 1024;
|
||||
pub const EVENT_MASK_BUTTON_4_MOTION: u32 = 2048;
|
||||
pub const EVENT_MASK_BUTTON_5_MOTION: u32 = 4096;
|
||||
pub const EVENT_MASK_BUTTON_MOTION: u32 = 8192;
|
||||
pub const EVENT_MASK_KEYMAP_STATE: u32 = 16384;
|
||||
pub const EVENT_MASK_EXPOSURE: u32 = 32768;
|
||||
pub const EVENT_MASK_VISIBILITY_CHANGE: u32 = 65536;
|
||||
pub const EVENT_MASK_STRUCTURE_NOTIFY: u32 = 131072;
|
||||
pub const EVENT_MASK_RESIZE_REDIRECT: u32 = 262144;
|
||||
pub const EVENT_MASK_SUBSTRUCTURE_NOTIFY: u32 = 524288;
|
||||
pub const EVENT_MASK_SUBSTRUCTURE_REDIRECT: u32 = 1048576;
|
||||
pub const EVENT_MASK_FOCUS_CHANGE: u32 = 2097152;
|
||||
pub const EVENT_MASK_PROPERTY_CHANGE: u32 = 4194304;
|
||||
pub const EVENT_MASK_COLOR_MAP_CHANGE: u32 = 8388608;
|
||||
pub const EVENT_MASK_OWNER_GRAB_BUTTON: u32 = 16777216;
|
||||
|
||||
pub const XI_EVENT_MASK_DEVICE_CHANGED: u32 = 2;
|
||||
pub const XI_EVENT_MASK_KEY_PRESS: u32 = 4;
|
||||
pub const XI_EVENT_MASK_KEY_RELEASE: u32 = 8;
|
||||
pub const XI_EVENT_MASK_BUTTON_PRESS: u32 = 16;
|
||||
pub const XI_EVENT_MASK_BUTTON_RELEASE: u32 = 32;
|
||||
pub const XI_EVENT_MASK_MOTION: u32 = 64;
|
||||
pub const XI_EVENT_MASK_ENTER: u32 = 128;
|
||||
pub const XI_EVENT_MASK_LEAVE: u32 = 256;
|
||||
pub const XI_EVENT_MASK_FOCUS_IN: u32 = 512;
|
||||
pub const XI_EVENT_MASK_FOCUS_OUT: u32 = 1024;
|
||||
pub const XI_EVENT_MASK_HIERARCHY: u32 = 2048;
|
||||
pub const XI_EVENT_MASK_PROPERTY: u32 = 4096;
|
||||
pub const XI_EVENT_MASK_RAW_KEY_PRESS: u32 = 8192;
|
||||
pub const XI_EVENT_MASK_RAW_KEY_RELEASE: u32 = 16384;
|
||||
pub const XI_EVENT_MASK_RAW_BUTTON_PRESS: u32 = 32768;
|
||||
pub const XI_EVENT_MASK_RAW_BUTTON_RELEASE: u32 = 65536;
|
||||
pub const XI_EVENT_MASK_RAW_MOTION: u32 = 131072;
|
||||
pub const XI_EVENT_MASK_TOUCH_BEGIN: u32 = 262144;
|
||||
pub const XI_EVENT_MASK_TOUCH_UPDATE: u32 = 524288;
|
||||
pub const XI_EVENT_MASK_TOUCH_END: u32 = 1048576;
|
||||
pub const XI_EVENT_MASK_TOUCH_OWNERSHIP: u32 = 2097152;
|
||||
pub const XI_EVENT_MASK_RAW_TOUCH_BEGIN: u32 = 4194304;
|
||||
pub const XI_EVENT_MASK_RAW_TOUCH_UPDATE: u32 = 8388608;
|
||||
pub const XI_EVENT_MASK_RAW_TOUCH_END: u32 = 16777216;
|
||||
pub const XI_EVENT_MASK_BARRIER_HIT: u32 = 33554432;
|
||||
pub const XI_EVENT_MASK_BARRIER_LEAVE: u32 = 67108864;
|
||||
|
||||
pub const PRESENT_EVENT_MASK_NO_EVENT: u32 = 0;
|
||||
pub const PRESENT_EVENT_MASK_CONFIGURE_NOTIFY: u32 = 1;
|
||||
pub const PRESENT_EVENT_MASK_COMPLETE_NOTIFY: u32 = 2;
|
||||
pub const PRESENT_EVENT_MASK_IDLE_NOTIFY: u32 = 4;
|
||||
pub const PRESENT_EVENT_MASK_REDIRECT_NOTIFY: u32 = 8;
|
||||
|
||||
pub const INPUT_DEVICE_TYPE_MASTER_POINTER: u16 = 1;
|
||||
pub const INPUT_DEVICE_TYPE_MASTER_KEYBOARD: u16 = 2;
|
||||
pub const INPUT_DEVICE_TYPE_SLAVE_POINTER: u16 = 3;
|
||||
pub const INPUT_DEVICE_TYPE_SLAVE_KEYBOARD: u16 = 4;
|
||||
pub const INPUT_DEVICE_TYPE_FLOATING_SLAVE: u16 = 5;
|
||||
|
||||
pub const XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT: u32 = 1;
|
||||
pub const XKB_PER_CLIENT_FLAG_GRABS_USE_XKB_STATE: u32 = 2;
|
||||
pub const XKB_PER_CLIENT_FLAG_AUTO_RESET_CONTROLS: u32 = 4;
|
||||
pub const XKB_PER_CLIENT_FLAG_LOOKUP_STATE_WHEN_GRABBED: u32 = 8;
|
||||
pub const XKB_PER_CLIENT_FLAG_SEND_EVENT_USES_XKB_STATE: u32 = 16;
|
||||
|
||||
pub const INPUT_HIERARCHY_MASK_MASTER_ADDED: u32 = 1;
|
||||
pub const INPUT_HIERARCHY_MASK_MASTER_REMOVED: u32 = 2;
|
||||
pub const INPUT_HIERARCHY_MASK_SLAVE_ADDED: u32 = 4;
|
||||
pub const INPUT_HIERARCHY_MASK_SLAVE_REMOVED: u32 = 8;
|
||||
pub const INPUT_HIERARCHY_MASK_SLAVE_ATTACHED: u32 = 16;
|
||||
pub const INPUT_HIERARCHY_MASK_SLAVE_DETACHED: u32 = 32;
|
||||
pub const INPUT_HIERARCHY_MASK_DEVICE_ENABLED: u32 = 64;
|
||||
pub const INPUT_HIERARCHY_MASK_DEVICE_DISABLED: u32 = 128;
|
||||
|
||||
pub const GRAB_MODE_SYNC: u8 = 0;
|
||||
pub const GRAB_MODE_ASYNC: u8 = 1;
|
||||
|
||||
pub const GRAB_STATUS_SUCCESS: u8 = 0;
|
||||
pub const GRAB_STATUS_ALREADY_GRABBED: u8 = 1;
|
||||
pub const GRAB_STATUS_INVALID_TIME: u8 = 2;
|
||||
pub const GRAB_STATUS_NOT_VIEWABLE: u8 = 3;
|
||||
pub const GRAB_STATUS_FROZEN: u8 = 4;
|
||||
62
src/xcon/formatter.rs
Normal file
62
src/xcon/formatter.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
use crate::xcon::Message;
|
||||
use std::rc::Rc;
|
||||
use uapi::{AssertPacked, OwnedFd, Packed};
|
||||
|
||||
pub struct Formatter<'a> {
|
||||
fds: &'a mut Vec<Rc<OwnedFd>>,
|
||||
buf: &'a mut Vec<u8>,
|
||||
ext_opcode: u8,
|
||||
}
|
||||
|
||||
impl<'a> Formatter<'a> {
|
||||
pub fn new(fds: &'a mut Vec<Rc<OwnedFd>>, buf: &'a mut Vec<u8>, ext_opcode: u8) -> Self {
|
||||
Self {
|
||||
fds,
|
||||
buf,
|
||||
ext_opcode,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ext_opcode(&self) -> u8 {
|
||||
self.ext_opcode
|
||||
}
|
||||
|
||||
pub fn pad(&mut self, pad: usize) {
|
||||
static BUF: [u8; 8] = [0; 8];
|
||||
self.buf.extend_from_slice(&BUF[..pad]);
|
||||
}
|
||||
|
||||
pub fn align(&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 write_packed<T: Packed + ?Sized>(&mut self, t: &T) {
|
||||
self.buf.extend_from_slice(uapi::as_bytes(t));
|
||||
}
|
||||
|
||||
pub fn write_list<'b, T: Message<'b>>(&mut self, t: &[T]) {
|
||||
if T::IS_POD {
|
||||
self.buf
|
||||
.extend_from_slice(uapi::as_bytes(unsafe { AssertPacked::new(t) }));
|
||||
} else {
|
||||
for t in t {
|
||||
t.serialize(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_bytes(&mut self, b: &[u8]) {
|
||||
self.buf.extend_from_slice(b);
|
||||
}
|
||||
|
||||
pub fn write_request_length(&mut self) {
|
||||
let len: u16 = (self.buf.len() / 4) as u16;
|
||||
self.buf[2..4].copy_from_slice(&len.to_ne_bytes());
|
||||
}
|
||||
|
||||
pub fn add_fd(&mut self, fd: &Rc<OwnedFd>) {
|
||||
self.fds.push(fd.clone());
|
||||
}
|
||||
}
|
||||
222
src/xcon/incoming.rs
Normal file
222
src/xcon/incoming.rs
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
use crate::utils::bufio::BufIoIncoming;
|
||||
use crate::xcon::consts::XGE_EVENT;
|
||||
use crate::xcon::{Event, ExtensionData, ExtensionIdRange, Parser, XconData, XconError};
|
||||
use crate::ErrorFmt;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(super) async fn handle_incoming(xorg: Rc<XconData>, incoming: BufIoIncoming) {
|
||||
let mut incoming = Incoming {
|
||||
incoming,
|
||||
socket: xorg,
|
||||
ed: None,
|
||||
};
|
||||
incoming.run().await;
|
||||
}
|
||||
|
||||
pub struct Incoming {
|
||||
socket: Rc<XconData>,
|
||||
incoming: BufIoIncoming,
|
||||
ed: Option<Rc<ExtensionData>>,
|
||||
}
|
||||
|
||||
impl Incoming {
|
||||
async fn run(&mut self) {
|
||||
loop {
|
||||
if self.socket.dead.get() {
|
||||
return;
|
||||
}
|
||||
if let Err(e) = self.handle_msg().await {
|
||||
log::error!("Could not process an incoming message: {}", ErrorFmt(e));
|
||||
self.socket.kill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_msg(&mut self) -> Result<(), XconError> {
|
||||
const MAX_LENGTH_UNITS: usize = 0x4000 / 4;
|
||||
const MIN_MSG_SIZE: usize = 32;
|
||||
|
||||
let mut msg_buf = self.socket.bufio.buf();
|
||||
self.incoming
|
||||
.fill_msg_buf(MIN_MSG_SIZE, &mut msg_buf)
|
||||
.await?;
|
||||
let mut serial = 0;
|
||||
const KEYMAP_NOTIFY: u8 = 11;
|
||||
let mut reply_handlers = self.socket.reply_handlers.borrow_mut();
|
||||
if msg_buf[0] & 0x7f != KEYMAP_NOTIFY {
|
||||
let serial_16 = u16::from_ne_bytes([msg_buf[2], msg_buf[3]]);
|
||||
serial = (self.socket.last_recv_serial.get() & !0xffff) | (serial_16 as u64);
|
||||
if serial < self.socket.last_recv_serial.get() {
|
||||
serial += 0x10000;
|
||||
}
|
||||
self.socket.last_recv_serial.set(serial);
|
||||
while let Some(first) = reply_handlers.front() {
|
||||
if first.serial() < serial {
|
||||
let handler = reply_handlers.pop_front().unwrap();
|
||||
drop(reply_handlers);
|
||||
handler.handle_noreply(&self.socket.bufio)?;
|
||||
reply_handlers = self.socket.reply_handlers.borrow_mut();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.ed.is_none() {
|
||||
self.ed = self.socket.extensions.get();
|
||||
}
|
||||
match msg_buf[0] & 0x7f {
|
||||
0 => 'handle_error: {
|
||||
let code = msg_buf[1];
|
||||
let (ext, code) = if code < 128 {
|
||||
(None, code)
|
||||
} else if let Some(ed) = &self.ed {
|
||||
let r = match find_range(&ed.errors, code) {
|
||||
Some(r) => r,
|
||||
_ => {
|
||||
log::error!("Received an out of bounds error code {}", code);
|
||||
break 'handle_error;
|
||||
}
|
||||
};
|
||||
match r.extension {
|
||||
Some(e) => (Some(e), code - r.first),
|
||||
None => {
|
||||
log::warn!(
|
||||
"Received an error from an unconfigured extension: `{}`",
|
||||
r.name
|
||||
);
|
||||
break 'handle_error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::error!("Received an extension error before extension have been fetched");
|
||||
break 'handle_error;
|
||||
};
|
||||
let e = match ext {
|
||||
Some(e) => XconError::ExtensionError(e, code),
|
||||
_ => XconError::CoreError(code),
|
||||
};
|
||||
if let Some(first) = reply_handlers.front() {
|
||||
if first.serial() == serial {
|
||||
let handler = reply_handlers.pop_front().unwrap();
|
||||
drop(reply_handlers);
|
||||
handler.handle_error(e);
|
||||
break 'handle_error;
|
||||
}
|
||||
}
|
||||
log::error!(
|
||||
"Received an error with no corresponding handler: {}",
|
||||
ErrorFmt(e)
|
||||
);
|
||||
}
|
||||
1 => {
|
||||
if let Some(first) = reply_handlers.front() {
|
||||
if first.serial() == serial {
|
||||
let handler = reply_handlers.pop_front().unwrap();
|
||||
drop(reply_handlers);
|
||||
let mut fds = vec![];
|
||||
if handler.has_fds() {
|
||||
let num_fds = msg_buf[1] as usize;
|
||||
if self.incoming.fds.len() < num_fds {
|
||||
return Err(XconError::MissingFds);
|
||||
}
|
||||
fds.extend(self.incoming.fds.drain(..num_fds));
|
||||
}
|
||||
let length =
|
||||
u32::from_ne_bytes([msg_buf[4], msg_buf[5], msg_buf[6], msg_buf[7]])
|
||||
as usize;
|
||||
if length > MAX_LENGTH_UNITS {
|
||||
return Err(XconError::ExcessiveMessageSize);
|
||||
}
|
||||
let length = length * 4;
|
||||
self.incoming.fill_msg_buf(length, &mut msg_buf).await?;
|
||||
let mut parser = unsafe {
|
||||
let msg_buf = mem::transmute::<&[u8], &'static [u8]>(&msg_buf[..]);
|
||||
Parser::new(msg_buf, fds)
|
||||
};
|
||||
handler.handle_result(
|
||||
&self.socket.bufio,
|
||||
&mut parser,
|
||||
mem::take(&mut msg_buf),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ev => 'handle_event: {
|
||||
let (ext, code) = if ev == XGE_EVENT {
|
||||
let length =
|
||||
u32::from_ne_bytes([msg_buf[4], msg_buf[5], msg_buf[6], msg_buf[7]])
|
||||
as usize;
|
||||
if length > MAX_LENGTH_UNITS {
|
||||
return Err(XconError::ExcessiveMessageSize);
|
||||
}
|
||||
let length = length * 4;
|
||||
self.incoming.fill_msg_buf(length, &mut msg_buf).await?;
|
||||
let opcode = msg_buf[1];
|
||||
let ext = match &self.ed {
|
||||
Some(ed) => ed.ext_by_opcode.get(&opcode),
|
||||
_ => {
|
||||
log::error!("Received an XGE event before extension have been fetched");
|
||||
break 'handle_event;
|
||||
}
|
||||
};
|
||||
let ext = match ext {
|
||||
Some(ext) => *ext,
|
||||
_ => {
|
||||
log::warn!(
|
||||
"Received an event from an unconfigured extension: `{}`",
|
||||
opcode
|
||||
);
|
||||
break 'handle_event;
|
||||
}
|
||||
};
|
||||
let code = u16::from_ne_bytes([msg_buf[8], msg_buf[9]]);
|
||||
(Some(ext), code)
|
||||
} else if ev < 64 {
|
||||
(None, ev as u16)
|
||||
} else if let Some(ed) = &self.ed {
|
||||
let r = match find_range(&ed.events, ev) {
|
||||
Some(r) => r,
|
||||
_ => {
|
||||
log::error!("Received an out of bounds event {}", ev);
|
||||
break 'handle_event;
|
||||
}
|
||||
};
|
||||
match r.extension {
|
||||
Some(e) => (Some(e), (ev - r.first) as u16),
|
||||
None => {
|
||||
log::warn!(
|
||||
"Received an event from an unconfigured extension: `{}`",
|
||||
r.name
|
||||
);
|
||||
break 'handle_event;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::error!("Received an extension event before extension have been fetched");
|
||||
break 'handle_event;
|
||||
};
|
||||
self.socket.events.push(Event {
|
||||
bufio: self.socket.bufio.clone(),
|
||||
ext,
|
||||
code,
|
||||
buf: mem::take(&mut msg_buf),
|
||||
});
|
||||
}
|
||||
}
|
||||
if msg_buf.capacity() > 0 {
|
||||
self.socket.bufio.add_buf(msg_buf);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn find_range(codes: &[ExtensionIdRange], code: u8) -> Option<&ExtensionIdRange> {
|
||||
let idx = match codes.binary_search_by_key(&code, |v| v.first) {
|
||||
Ok(v) => v,
|
||||
Err(v) if v > 0 => v - 1,
|
||||
_ => return None,
|
||||
};
|
||||
Some(&codes[idx])
|
||||
}
|
||||
10
src/xcon/outgoing.rs
Normal file
10
src/xcon/outgoing.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
use crate::xcon::XconData;
|
||||
use crate::ErrorFmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(super) async fn handle_outgoing(socket: Rc<XconData>) {
|
||||
if let Err(e) = socket.bufio.clone().outgoing().await {
|
||||
log::error!("{}", ErrorFmt(e));
|
||||
}
|
||||
socket.kill();
|
||||
}
|
||||
138
src/xcon/parser.rs
Normal file
138
src/xcon/parser.rs
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
use crate::utils::ptr_ext::PtrExt;
|
||||
use crate::xcon::wire_type::Message;
|
||||
use crate::xcon::XconError;
|
||||
use bstr::{BStr, ByteSlice};
|
||||
use std::borrow::Cow;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use uapi::{OwnedFd, Pod};
|
||||
|
||||
pub struct Parser<'a> {
|
||||
pos: usize,
|
||||
buf: &'a [u8],
|
||||
fds_pos: usize,
|
||||
fds: Vec<Rc<OwnedFd>>,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn new(buf: &'a [u8], fds: Vec<Rc<OwnedFd>>) -> Self {
|
||||
Self {
|
||||
buf,
|
||||
pos: 0,
|
||||
fds,
|
||||
fds_pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eof(&self) -> bool {
|
||||
self.pos == self.buf.len()
|
||||
}
|
||||
|
||||
fn rem(&self) -> usize {
|
||||
self.buf.len() - self.pos
|
||||
}
|
||||
|
||||
pub fn unmarshal<T: Message<'a>>(&mut self) -> Result<T, XconError> {
|
||||
T::deserialize(self)
|
||||
}
|
||||
|
||||
pub fn pad(&mut self, new: usize) -> Result<(), XconError> {
|
||||
if new > self.buf.len() - self.pos {
|
||||
return Err(XconError::UnexpectedEof);
|
||||
}
|
||||
self.pos += new;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn align(&mut self, n: usize) -> Result<(), XconError> {
|
||||
let new = self.pos + (self.pos.wrapping_neg() & (n - 1));
|
||||
if new > self.buf.len() {
|
||||
return Err(XconError::UnexpectedEof);
|
||||
}
|
||||
self.pos = new;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_fd(&mut self) -> Result<Rc<OwnedFd>, XconError> {
|
||||
if self.fds_pos >= self.fds.len() {
|
||||
return Err(XconError::NotEnoughFds);
|
||||
}
|
||||
self.fds_pos += 1;
|
||||
Ok(self.fds[self.fds_pos - 1].clone())
|
||||
}
|
||||
|
||||
pub fn read_pod<'b, T: Pod>(&mut self) -> Result<T, XconError> {
|
||||
match uapi::pod_read_init(&self.buf[self.pos..]) {
|
||||
Ok(v) => {
|
||||
self.pos += mem::size_of::<T>();
|
||||
Ok(v)
|
||||
}
|
||||
_ => Err(XconError::UnexpectedEof),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_list_slice<T: Message<'a> + Pod>(
|
||||
&mut self,
|
||||
n: Option<usize>,
|
||||
) -> Result<&'a [T], XconError> {
|
||||
let n = match n {
|
||||
Some(n) => n,
|
||||
_ => self.rem() / mem::size_of::<T>(),
|
||||
};
|
||||
let len = mem::size_of::<T>() * n;
|
||||
if len > self.rem() {
|
||||
return Err(XconError::UnexpectedEof);
|
||||
}
|
||||
if self.buf[self.pos..].as_ptr() as usize & (mem::align_of::<T>() - 1) != 0 {
|
||||
return Err(XconError::UnalignedSlice);
|
||||
}
|
||||
let res =
|
||||
unsafe { std::slice::from_raw_parts(self.buf.as_ptr().add(self.pos) as *const T, n) };
|
||||
self.pos += len;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn read_list<T: Message<'a> + Clone>(
|
||||
&mut self,
|
||||
n: Option<usize>,
|
||||
) -> Result<Cow<'a, [T]>, XconError> {
|
||||
let mut res = vec![];
|
||||
if let Some(n) = n {
|
||||
for _ in 0..n {
|
||||
res.push(T::deserialize(self)?);
|
||||
}
|
||||
} else {
|
||||
while !self.eof() {
|
||||
res.push(T::deserialize(self)?);
|
||||
}
|
||||
}
|
||||
Ok(res.into())
|
||||
}
|
||||
|
||||
pub fn read_bytes<const N: usize>(&mut self) -> Result<&'a [u8; N], XconError> {
|
||||
if N > self.rem() {
|
||||
return Err(XconError::UnexpectedEof);
|
||||
}
|
||||
let res = unsafe { self.buf.as_ptr().add(self.pos).cast::<[u8; N]>().deref() };
|
||||
self.pos += N;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn read_slice(&mut self, n: usize) -> Result<&'a [u8], XconError> {
|
||||
if n > self.rem() {
|
||||
return Err(XconError::UnexpectedEof);
|
||||
}
|
||||
let res = &self.buf[self.pos..self.pos + n];
|
||||
self.pos += n;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn read_string(&mut self, n: usize) -> Result<&'a BStr, XconError> {
|
||||
if n > self.rem() {
|
||||
return Err(XconError::UnexpectedEof);
|
||||
}
|
||||
let res = &self.buf[self.pos..self.pos + n];
|
||||
self.pos += n;
|
||||
Ok(res.as_bstr())
|
||||
}
|
||||
}
|
||||
118
src/xcon/wire_type.rs
Normal file
118
src/xcon/wire_type.rs
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
use crate::xcon::formatter::Formatter;
|
||||
use crate::xcon::parser::Parser;
|
||||
use crate::xcon::XconError;
|
||||
use bstr::{BStr, ByteSlice};
|
||||
use std::borrow::Cow;
|
||||
use std::rc::Rc;
|
||||
use uapi::OwnedFd;
|
||||
|
||||
#[cold]
|
||||
fn unimplemented() -> ! {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
pub unsafe trait Message<'a>: Clone + 'a {
|
||||
type Generic<'b>: Message<'b>;
|
||||
const IS_POD: bool;
|
||||
const HAS_FDS: bool;
|
||||
|
||||
fn serialize(&self, formatter: &mut Formatter) {
|
||||
let _ = formatter;
|
||||
unimplemented()
|
||||
}
|
||||
|
||||
fn deserialize(parser: &mut Parser<'a>) -> Result<Self, XconError> {
|
||||
let _ = parser;
|
||||
unimplemented()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Request<'a>: Message<'a> {
|
||||
type Reply: Message<'static>;
|
||||
const EXTENSION: Option<usize>;
|
||||
const IS_VOID: bool;
|
||||
}
|
||||
|
||||
pub trait XEvent<'a>: Message<'a> {
|
||||
const OPCODE: u16;
|
||||
}
|
||||
|
||||
macro_rules! simple {
|
||||
($ty:ty) => {
|
||||
unsafe impl Message<'_> for $ty {
|
||||
type Generic<'b> = $ty;
|
||||
const IS_POD: bool = true;
|
||||
const HAS_FDS: bool = false;
|
||||
|
||||
fn serialize(&self, formatter: &mut Formatter) {
|
||||
formatter.write_packed(self);
|
||||
}
|
||||
|
||||
fn deserialize(parser: &mut Parser<'_>) -> Result<Self, XconError> {
|
||||
parser.read_pod()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
simple!(u8);
|
||||
simple!(i8);
|
||||
simple!(u16);
|
||||
simple!(i16);
|
||||
simple!(u32);
|
||||
simple!(i32);
|
||||
simple!(u64);
|
||||
simple!(i64);
|
||||
|
||||
unsafe impl<'a> Message<'a> for () {
|
||||
type Generic<'b> = ();
|
||||
const IS_POD: bool = false;
|
||||
const HAS_FDS: bool = false;
|
||||
}
|
||||
|
||||
unsafe impl<'a> Message<'a> for &'a BStr {
|
||||
type Generic<'b> = &'b BStr;
|
||||
const IS_POD: bool = true;
|
||||
const HAS_FDS: bool = false;
|
||||
|
||||
fn serialize(&self, formatter: &mut Formatter) {
|
||||
formatter.write_packed(self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: Message<'a>> Message<'a> for &'a [T] {
|
||||
type Generic<'b> = &'b [T::Generic<'b>];
|
||||
const IS_POD: bool = false;
|
||||
const HAS_FDS: bool = false;
|
||||
|
||||
fn serialize(&self, formatter: &mut Formatter) {
|
||||
formatter.write_list(self);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a, T> Message<'a> for Cow<'a, [T]>
|
||||
where
|
||||
T: Message<'a>,
|
||||
{
|
||||
type Generic<'b> = Cow<'b, [T::Generic<'b>]>;
|
||||
const IS_POD: bool = false;
|
||||
const HAS_FDS: bool = false;
|
||||
|
||||
fn serialize(&self, formatter: &mut Formatter) {
|
||||
formatter.write_list(self);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a> Message<'a> for Rc<OwnedFd> {
|
||||
type Generic<'b> = Rc<OwnedFd>;
|
||||
const IS_POD: bool = false;
|
||||
const HAS_FDS: bool = true;
|
||||
|
||||
fn serialize(&self, formatter: &mut Formatter) {
|
||||
formatter.add_fd(self);
|
||||
}
|
||||
|
||||
fn deserialize(parser: &mut Parser<'a>) -> Result<Self, XconError> {
|
||||
parser.read_fd()
|
||||
}
|
||||
}
|
||||
96
src/xcon/xauthority.rs
Normal file
96
src/xcon/xauthority.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
use crate::xcon::XconError;
|
||||
use bstr::{BString, ByteSlice};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
pub const LOCAL: u16 = 256;
|
||||
|
||||
pub const MIT_MAGIC_COOKIE: &[u8] = b"MIT-MAGIC-COOKIE-1";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XAuthority {
|
||||
pub family: u16,
|
||||
pub host: BString,
|
||||
pub display: u32,
|
||||
pub method: BString,
|
||||
pub value: BString,
|
||||
}
|
||||
|
||||
impl XAuthority {
|
||||
pub fn load() -> Result<Vec<XAuthority>, XconError> {
|
||||
let path = 'path: {
|
||||
if let Ok(p) = std::env::var("XAUTHORITY") {
|
||||
break 'path p;
|
||||
}
|
||||
if let Ok(home) = std::env::var("HOME") {
|
||||
break 'path format!("{home}/.Xauthority");
|
||||
}
|
||||
return Err(XconError::HomeNotSet);
|
||||
};
|
||||
let mut buf = vec![];
|
||||
if let Err(e) = File::open(&path).and_then(|mut f| f.read_to_end(&mut buf)) {
|
||||
return Err(XconError::ReadXAuthority(e));
|
||||
}
|
||||
Parser::parse(&buf)
|
||||
}
|
||||
}
|
||||
|
||||
struct Parser<'a> {
|
||||
pos: usize,
|
||||
buf: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn parse(buf: &[u8]) -> Result<Vec<XAuthority>, XconError> {
|
||||
let mut slf = Parser { pos: 0, buf };
|
||||
let mut res = vec![];
|
||||
while slf.rem() > 0 {
|
||||
res.push(slf.parse_one()?);
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn rem(&self) -> usize {
|
||||
self.buf.len() - self.pos
|
||||
}
|
||||
|
||||
fn parse_one(&mut self) -> Result<XAuthority, XconError> {
|
||||
Ok(XAuthority {
|
||||
family: self.read_u16()?,
|
||||
host: self.read_string()?,
|
||||
display: {
|
||||
let s = self.read_string()?;
|
||||
match s.to_str() {
|
||||
Ok(s) => match s.parse() {
|
||||
Ok(v) => v,
|
||||
_ => return Err(XconError::InvalidAuthorityDisplay),
|
||||
},
|
||||
_ => return Err(XconError::InvalidAuthorityDisplay),
|
||||
}
|
||||
},
|
||||
method: self.read_string()?,
|
||||
value: self.read_string()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_u16(&mut self) -> Result<u16, XconError> {
|
||||
if self.rem() < 2 {
|
||||
return Err(XconError::UnexpectedEof);
|
||||
}
|
||||
let bytes = [self.buf[self.pos], self.buf[self.pos + 1]];
|
||||
self.pos += 2;
|
||||
Ok(u16::from_be_bytes(bytes))
|
||||
}
|
||||
|
||||
fn read_string(&mut self) -> Result<BString, XconError> {
|
||||
let len = self.read_u16()? as usize;
|
||||
if self.rem() < len {
|
||||
log::info!("rem = {}; len = {}", self.rem(), len);
|
||||
return Err(XconError::UnexpectedEof);
|
||||
}
|
||||
let res = self.buf[self.pos..self.pos + len].to_vec();
|
||||
self.pos += len;
|
||||
let res = res.into();
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue