1
0
Fork 0
forked from wry/wry

autocommit 2022-01-02 16:30:30 CET

This commit is contained in:
Julian Orth 2022-01-02 16:30:30 +01:00
parent d6172b273f
commit c21f231ce7
34 changed files with 874 additions and 844 deletions

View file

@ -1,6 +1,6 @@
use crate::client::ClientError;
use crate::event_loop::{EventLoopDispatcher, EventLoopError, EventLoopId};
use crate::state::State;
use crate::wl_client::WlClientError;
use std::rc::Rc;
use thiserror::Error;
use uapi::{c, Errno, OwnedFd};
@ -20,7 +20,7 @@ pub enum AcceptorError {
#[error("Could not accept new connections")]
AcceptFailed(#[source] std::io::Error),
#[error("Could not spawn an event handler for a new connection")]
SpawnFailed(#[source] WlClientError),
SpawnFailed(#[source] ClientError),
#[error("Could not bind the socket to an address")]
BindFailed(#[source] std::io::Error),
#[error("All wayland addresses in the range 0..1000 are already in use")]

395
src/client/mod.rs Normal file
View file

@ -0,0 +1,395 @@
use crate::async_engine::{AsyncError, AsyncFd, SpawnedFuture};
use crate::client::objects::Objects;
use crate::ifs::wl_callback::WlCallback;
use crate::ifs::wl_compositor::{WlCompositorError, WlCompositorObj};
use crate::ifs::wl_display::{WlDisplay, WlDisplayError};
use crate::ifs::wl_region::{WlRegion, WlRegionError};
use crate::ifs::wl_registry::{WlRegistry, WlRegistryError};
use crate::ifs::wl_shm::{WlShmError, WlShmObj};
use crate::ifs::wl_shm_pool::{WlShmPool, WlShmPoolError};
use crate::ifs::wl_subcompositor::WlSubcompositorObj;
use crate::ifs::wl_surface::{WlSurface, WlSurfaceError};
use crate::ifs::xdg_wm_base::XdgWmBaseObj;
use crate::object::{Object, ObjectId, WL_DISPLAY_ID};
use crate::state::State;
use crate::utils::buffd::{BufFdError, WlFormatter, WlParser, WlParserError};
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::numcell::NumCell;
use crate::utils::oneshot::{oneshot, OneshotTx};
use crate::utils::queue::AsyncQueue;
use ahash::AHashMap;
use anyhow::anyhow;
use std::cell::{Cell, RefMut};
use std::fmt::{Debug, Display, Formatter};
use std::future::Future;
use std::rc::Rc;
use thiserror::Error;
use uapi::OwnedFd;
mod objects;
mod tasks;
#[derive(Debug, Error)]
pub enum ClientError {
#[error("An error occurred in the async engine")]
Async(#[from] AsyncError),
#[error("An error occurred reading from/writing to the client")]
Io(#[from] BufFdError),
#[error("An error occurred while processing a request")]
RequestError(#[source] Box<ClientError>),
#[error("Client tried to invoke a non-existent method")]
InvalidMethod,
#[error("Client tried to access non-existent object {0}")]
InvalidObject(ObjectId),
#[error("The message size is < 8")]
MessageSizeTooSmall,
#[error("The size of the message is not a multiple of 4")]
UnalignedMessage,
#[error("The outgoing buffer overflowed")]
OutBufferOverflow,
#[error("The requested client {0} does not exist")]
ClientDoesNotExist(ClientId),
#[error("There is no region with id {0}")]
RegionDoesNotExist(ObjectId),
#[error("Cannot parse the message")]
ParserError(#[source] Box<WlParserError>),
#[error("Server tried to allocate more than 0x1_00_00_00 ids")]
TooManyIds,
#[error("The server object id is out of bounds")]
ServerIdOutOfBounds,
#[error("The object id is unknown")]
UnknownId,
#[error("The id is already in use")]
IdAlreadyInUse,
#[error("The client object id is out of bounds")]
ClientIdOutOfBounds,
#[error("An error occurred in a `wl_display`")]
WlDisplayError(#[source] Box<WlDisplayError>),
#[error("An error occurred in a `wl_registry`")]
WlRegistryError(#[source] Box<WlRegistryError>),
#[error("Could not add object {0} to the client")]
AddObjectError(ObjectId, #[source] Box<ClientError>),
#[error("An error occurred in a `wl_surface`")]
WlSurfaceError(#[source] Box<WlSurfaceError>),
#[error("An error occurred in a `wl_compositor`")]
WlCompositorError(#[source] Box<WlCompositorError>),
#[error("An error occurred in a `wl_shm`")]
WlShmError(#[source] Box<WlShmError>),
#[error("An error occurred in a `wl_shm_pool`")]
WlShmPoolError(#[source] Box<WlShmPoolError>),
#[error("An error occurred in a `wl_region`")]
WlRegionError(#[source] Box<WlRegionError>),
#[error("Object {0} is not a display")]
NotADisplay(ObjectId),
}
efrom!(ClientError, ParserError, WlParserError);
efrom!(ClientError, WlDisplayError, WlDisplayError);
efrom!(ClientError, WlRegistryError, WlRegistryError);
efrom!(ClientError, WlSurfaceError, WlSurfaceError);
efrom!(ClientError, WlCompositorError, WlCompositorError);
efrom!(ClientError, WlShmError, WlShmError);
efrom!(ClientError, WlShmPoolError, WlShmPoolError);
efrom!(ClientError, WlRegionError, WlRegionError);
impl ClientError {
fn peer_closed(&self) -> bool {
match self {
ClientError::Io(BufFdError::Closed) => true,
_ => false,
}
}
}
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct ClientId(u64);
impl Display for ClientId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}
pub struct Clients {
next_client_id: NumCell<u64>,
clients: CopyHashMap<ClientId, Rc<ClientHolder>>,
shutdown_clients: CopyHashMap<ClientId, Rc<ClientHolder>>,
}
impl Clients {
pub fn new() -> Self {
Self {
next_client_id: NumCell::new(1),
clients: CopyHashMap::new(),
shutdown_clients: CopyHashMap::new(),
}
}
pub fn id(&self) -> ClientId {
ClientId(self.next_client_id.fetch_add(1))
}
pub fn get(&self, id: ClientId) -> Result<Rc<Client>, ClientError> {
match self.clients.get(&id) {
Some(c) => Ok(c.data.clone()),
_ => Err(ClientError::ClientDoesNotExist(id)),
}
}
pub fn spawn(
&self,
id: ClientId,
global: &Rc<State>,
socket: OwnedFd,
) -> Result<(), ClientError> {
let (send, recv) = oneshot();
let data = Rc::new(Client {
id,
state: global.clone(),
socket: global.eng.fd(&Rc::new(socket))?,
objects: Objects::new(),
events: AsyncQueue::new(),
shutdown: Cell::new(Some(send)),
shutdown_sent: Cell::new(false),
});
data.objects
.add_client_object(Rc::new(WlDisplay::new(&data)))
.expect("");
let client = Rc::new(ClientHolder {
_handler: global.eng.spawn(tasks::client(data.clone(), recv)),
data,
});
self.clients.set(client.data.id, client.clone());
log::info!("Client {} connected", id);
Ok(())
}
pub fn kill(&self, client: ClientId) {
log::info!("Removing client {}", client.0);
if self.clients.remove(&client).is_none() {
self.shutdown_clients.remove(&client);
}
}
pub fn shutdown(&self, client_id: ClientId) {
if let Some(client) = self.clients.remove(&client_id) {
log::info!("Shutting down client {}", client.data.id.0);
client.data.shutdown.replace(None).unwrap().send(());
client.data.events.push(WlEvent::Shutdown);
client.data.shutdown_sent.set(true);
self.shutdown_clients.set(client_id, client);
}
}
pub fn broadcast<B>(&self, mut f: B)
where
B: FnMut(&Rc<Client>),
{
let clients = self.clients.lock();
for client in clients.values() {
f(&client.data);
}
}
}
struct ClientHolder {
data: Rc<Client>,
_handler: SpawnedFuture<()>,
}
impl Drop for ClientHolder {
fn drop(&mut self) {
self.data.objects.destroy();
}
}
pub trait EventFormatter: Debug {
fn format(self: Box<Self>, fmt: &mut WlFormatter<'_>);
fn obj(&self) -> &dyn Object;
}
pub type DynEventFormatter = Box<dyn EventFormatter>;
pub trait RequestParser<'a>: Debug + Sized {
fn parse(parser: &mut WlParser<'_, 'a>) -> Result<Self, WlParserError>;
}
enum WlEvent {
Flush,
Shutdown,
Event(Box<dyn EventFormatter>),
}
pub struct Client {
pub id: ClientId,
pub state: Rc<State>,
socket: AsyncFd,
objects: Objects,
events: AsyncQueue<WlEvent>,
shutdown: Cell<Option<OneshotTx<()>>>,
shutdown_sent: Cell<bool>,
}
const MAX_PENDING_EVENTS: usize = 100;
impl Client {
pub fn invalid_request(&self, obj: &dyn Object, request: u32) {
log::error!(
"Client {} sent an invalid request {} on object {} of type {}",
self.id.0,
request,
obj.id(),
obj.interface().name(),
);
match self.display() {
Ok(d) => self.fatal_event(d.invalid_request(obj, request)),
Err(e) => {
log::error!(
"Could not retrieve display of client {}: {:#}",
self.id,
anyhow!(e)
);
self.state.clients.kill(self.id);
}
}
}
pub fn display(&self) -> Result<Rc<WlDisplay>, ClientError> {
Ok(self.objects.get_obj(WL_DISPLAY_ID)?.into_display()?)
}
pub fn parse<'a, R: RequestParser<'a>>(
&self,
obj: &impl Object,
mut parser: WlParser<'_, 'a>,
) -> Result<R, WlParserError> {
let res = R::parse(&mut parser)?;
parser.eof()?;
log::trace!(
"Client {} -> {}@{}.{:?}",
self.id,
obj.interface().name(),
obj.id(),
res
);
Ok(res)
}
pub fn fatal_event(&self, event: Box<dyn EventFormatter>) {
self.events.push(WlEvent::Event(event));
self.state.clients.shutdown(self.id);
}
pub fn event_locked(&self, event: Box<dyn EventFormatter>) -> bool {
self.events.push(WlEvent::Event(event));
self.events.size() > MAX_PENDING_EVENTS
}
pub async fn event(&self, event: Box<dyn EventFormatter>) -> Result<(), ClientError> {
self.event2(WlEvent::Event(event)).await
}
async fn event2(&self, event: WlEvent) -> Result<(), ClientError> {
self.events.push(event);
self.check_queue_size().await
}
pub async fn check_queue_size(&self) -> Result<(), ClientError> {
if self.events.size() > MAX_PENDING_EVENTS {
self.state.eng.yield_now().await;
if self.events.size() > MAX_PENDING_EVENTS {
log::error!("Client {} is too slow at fetching events", self.id.0);
self.state.clients.kill(self.id);
return Err(ClientError::OutBufferOverflow);
}
}
Ok(())
}
pub fn get_region(&self, id: ObjectId) -> Result<Rc<WlRegion>, ClientError> {
match self.objects.regions.get(&id) {
Some(r) => Ok(r),
_ => Err(ClientError::RegionDoesNotExist(id)),
}
}
fn simple_add_obj<T: Object>(&self, obj: &Rc<T>, client: bool) -> Result<(), ClientError> {
if client {
self.objects.add_client_object(obj.clone())
} else {
self.objects.add_server_object(obj.clone());
Ok(())
}
}
fn simple_remove_obj<'a>(
&'a self,
id: ObjectId,
) -> impl Future<Output = Result<(), ClientError>> + 'a {
self.objects.remove_obj(self, id)
}
pub fn lock_registries(&self) -> RefMut<AHashMap<ObjectId, Rc<WlRegistry>>> {
self.objects.registries()
}
}
pub trait AddObj<T> {
type RemoveObj<'a>: Future<Output = Result<(), ClientError>> + 'a;
fn add_client_obj(&self, obj: &Rc<T>) -> Result<(), ClientError> {
self.add_obj(obj, true)
}
fn add_server_obj(&self, obj: &Rc<T>) {
self.add_obj(obj, false).expect("add_server_obj failed")
}
fn add_obj(&self, obj: &Rc<T>, client: bool) -> Result<(), ClientError>;
fn remove_obj<'a>(&'a self, obj: &'a T) -> Self::RemoveObj<'a>;
}
macro_rules! simple_add_obj {
($ty:ty) => {
impl AddObj<$ty> for Client {
type RemoveObj<'a> = impl Future<Output = Result<(), ClientError>> + 'a;
fn add_obj(&self, obj: &Rc<$ty>, client: bool) -> Result<(), ClientError> {
self.simple_add_obj(obj, client)
}
fn remove_obj<'a>(&'a self, obj: &'a $ty) -> Self::RemoveObj<'a> {
self.simple_remove_obj(obj.id())
}
}
};
}
simple_add_obj!(WlCompositorObj);
simple_add_obj!(WlCallback);
simple_add_obj!(WlRegistry);
simple_add_obj!(WlShmObj);
simple_add_obj!(WlShmPool);
simple_add_obj!(WlSubcompositorObj);
simple_add_obj!(XdgWmBaseObj);
macro_rules! dedicated_add_obj {
($ty:ty, $field:ident) => {
impl AddObj<$ty> for Client {
type RemoveObj<'a> = impl Future<Output = Result<(), ClientError>> + 'a;
fn add_obj(&self, obj: &Rc<$ty>, client: bool) -> Result<(), ClientError> {
self.simple_add_obj(obj, client)?;
self.objects.$field.set(obj.id(), obj.clone());
Ok(())
}
fn remove_obj<'a>(&'a self, obj: &'a $ty) -> Self::RemoveObj<'a> {
self.objects.$field.remove(&obj.id());
self.simple_remove_obj(obj.id())
}
}
};
}
dedicated_add_obj!(WlRegion, regions);
dedicated_add_obj!(WlSurface, surfaces);

122
src/client/objects.rs Normal file
View file

@ -0,0 +1,122 @@
use crate::client::{Client, ClientError};
use crate::ifs::wl_region::WlRegion;
use crate::ifs::wl_registry::WlRegistry;
use crate::ifs::wl_surface::WlSurface;
use crate::object::{Object, ObjectId};
use crate::utils::copyhashmap::CopyHashMap;
use ahash::AHashMap;
use std::cell::{RefCell, RefMut};
use std::mem;
use std::rc::Rc;
pub struct Objects {
registry: CopyHashMap<ObjectId, Rc<dyn Object>>,
registries: CopyHashMap<ObjectId, Rc<WlRegistry>>,
pub surfaces: CopyHashMap<ObjectId, Rc<WlSurface>>,
pub regions: CopyHashMap<ObjectId, Rc<WlRegion>>,
ids: RefCell<Vec<usize>>,
}
pub const MIN_SERVER_ID: u32 = 0xff000000;
const SEG_SIZE: usize = 8 * mem::size_of::<usize>();
impl Objects {
pub fn new() -> Self {
Self {
registry: Default::default(),
registries: Default::default(),
surfaces: Default::default(),
regions: Default::default(),
ids: RefCell::new(vec![]),
}
}
pub fn destroy(&self) {
self.registry.clear();
self.registries.clear();
self.surfaces.clear();
}
fn id(&self, client_data: &Client) -> Result<ObjectId, ClientError> {
const MAX_ID_OFFSET: u32 = u32::MAX - MIN_SERVER_ID;
let offset = self.id_offset();
if offset > MAX_ID_OFFSET {
log::error!(
"Client {} caused the server to allocate more than 0x{:x} ids",
client_data.id,
MAX_ID_OFFSET + 1
);
return Err(ClientError::TooManyIds);
}
Ok(ObjectId::from_raw(MIN_SERVER_ID + offset))
}
pub fn get_obj(&self, id: ObjectId) -> Result<Rc<dyn Object>, ClientError> {
match self.registry.get(&id) {
Some(o) => Ok(o),
_ => Err(ClientError::UnknownId),
}
}
pub fn add_server_object(&self, obj: Rc<dyn Object>) {
let id = obj.id();
assert!(id.raw() >= MIN_SERVER_ID);
assert!(!self.registry.contains(&id));
self.registry.set(id, obj.clone());
}
pub fn add_client_object(&self, obj: Rc<dyn Object>) -> Result<(), ClientError> {
let id = obj.id();
let res = (|| {
if id.raw() == 0 || id.raw() >= MIN_SERVER_ID {
return Err(ClientError::ClientIdOutOfBounds);
}
if self.registry.contains(&id) {
return Err(ClientError::IdAlreadyInUse);
}
self.registry.set(id, obj.clone());
Ok(())
})();
if let Err(e) = res {
return Err(ClientError::AddObjectError(id, Box::new(e)));
}
Ok(())
}
pub async fn remove_obj(&self, client_data: &Client, id: ObjectId) -> Result<(), ClientError> {
if self.registry.remove(&id).is_none() {
return Err(ClientError::UnknownId);
}
if id.raw() >= MIN_SERVER_ID {
let offset = (id.raw() - MIN_SERVER_ID) as usize;
let pos = offset / SEG_SIZE;
let seg_offset = offset % SEG_SIZE;
let mut ids = self.ids.borrow_mut();
if ids.len() <= pos {
return Err(ClientError::ServerIdOutOfBounds);
}
ids[pos] |= 1 << seg_offset;
}
client_data
.event(client_data.display()?.delete_id(id))
.await?;
Ok(())
}
pub fn registries(&self) -> RefMut<AHashMap<ObjectId, Rc<WlRegistry>>> {
self.registries.lock()
}
fn id_offset(&self) -> u32 {
let mut ids = self.ids.borrow_mut();
for (pos, seg) in ids.iter_mut().enumerate() {
if *seg != 0 {
let offset = seg.trailing_zeros();
*seg &= !(1 << offset);
return (pos * SEG_SIZE) as u32 + offset;
}
}
ids.push(!1);
((ids.len() - 1) * SEG_SIZE) as u32
}
}

154
src/client/tasks.rs Normal file
View file

@ -0,0 +1,154 @@
use crate::client::{Client, ClientError, WlEvent};
use crate::object::ObjectId;
use crate::utils::buffd::{BufFdIn, BufFdOut, WlFormatter, WlParser};
use crate::utils::oneshot::OneshotRx;
use crate::utils::vec_ext::VecExt;
use anyhow::anyhow;
use futures::{select, FutureExt};
use std::mem;
use std::rc::Rc;
pub async fn client(data: Rc<Client>, shutdown: OneshotRx<()>) {
let mut recv = data.state.eng.spawn(receive(data.clone())).fuse();
let _send = data.state.eng.spawn(send(data.clone()));
select! {
_ = recv => { },
_ = shutdown.fuse() => { },
}
drop(recv);
if !data.shutdown_sent.get() {
data.events.push(WlEvent::Shutdown);
}
match data.state.eng.timeout(5000) {
Ok(timeout) => {
timeout.await;
log::error!("Could not shut down client {} within 5 seconds", data.id.0);
}
Err(e) => {
log::error!("Could not create a timeout: {:#}", e);
}
}
data.state.clients.kill(data.id);
}
async fn receive(data: Rc<Client>) {
let display = data.display().unwrap();
let recv = async {
let mut buf = BufFdIn::new(data.socket.clone());
let mut data_buf = Vec::<u32>::new();
loop {
let mut hdr = [0u32, 0];
buf.read_full(&mut hdr[..]).await?;
let obj_id = ObjectId::from_raw(hdr[0]);
let len = (hdr[1] >> 16) as usize;
let request = hdr[1] & 0xffff;
let obj = match data.objects.get_obj(obj_id) {
Ok(obj) => obj,
_ => {
data.fatal_event(display.invalid_object(obj_id));
return Err(ClientError::InvalidObject(obj_id));
}
};
// log::trace!("obj: {}, request: {}, len: {}", obj_id, request, len);
if request >= obj.num_requests() {
data.invalid_request(&*obj, request);
return Err(ClientError::InvalidMethod);
}
if len < 8 {
return Err(ClientError::MessageSizeTooSmall);
}
if len % 4 != 0 {
return Err(ClientError::UnalignedMessage);
}
let len = len / 4 - 2;
data_buf.clear();
data_buf.reserve(len);
let unused = data_buf.split_at_spare_mut_ext().1;
buf.read_full(&mut unused[..len]).await?;
unsafe {
data_buf.set_len(len);
}
// log::trace!("{:x?}", data_buf);
let parser = WlParser::new(&mut buf, &data_buf[..]);
if let Err(e) = obj.handle_request(request, parser).await {
return Err(ClientError::RequestError(Box::new(e)));
}
data.event2(WlEvent::Flush).await?;
}
};
let res: Result<(), ClientError> = recv.await;
if let Err(e) = res {
if e.peer_closed() {
log::info!("Client {} terminated the connection", data.id.0);
data.state.clients.kill(data.id);
} else {
let e = anyhow!(e);
log::error!(
"An error occurred while trying to handle a message from client {}: {:#}",
data.id.0,
e
);
if !data.shutdown_sent.get() {
data.fatal_event(display.implementation_error(format!("{:#}", e)));
}
}
}
}
async fn send(data: Rc<Client>) {
let send = async {
let mut buf = BufFdOut::new(data.socket.clone());
let mut flush_requested = false;
loop {
let mut event = data.events.pop().await;
loop {
match event {
WlEvent::Flush => {
flush_requested = true;
}
WlEvent::Shutdown => {
buf.flush().await?;
return Ok(());
}
WlEvent::Event(e) => {
if log::log_enabled!(log::Level::Trace) {
let obj = e.obj();
log::trace!(
"Client {} <= {}@{}.{:?}",
data.id,
obj.interface().name(),
obj.id(),
e
);
}
e.format(&mut WlFormatter::new(&mut buf));
if buf.needs_flush() {
buf.flush().await?;
flush_requested = false;
}
}
}
event = match data.events.try_pop() {
Some(e) => e,
_ => break,
};
}
if mem::take(&mut flush_requested) {
buf.flush().await?;
}
}
};
let res: Result<(), ClientError> = send.await;
if let Err(e) = res {
if e.peer_closed() {
log::info!("Client {} terminated the connection", data.id.0);
} else {
log::error!(
"An error occurred while sending data to client {}: {:#}",
data.id.0,
e
);
}
}
data.state.clients.kill(data.id);
}

View file

@ -1,11 +1,11 @@
use crate::client::{Client, ClientError, DynEventFormatter};
use crate::ifs::wl_compositor::WlCompositorError;
use crate::ifs::wl_registry::WlRegistry;
use crate::ifs::wl_shm::WlShmError;
use crate::ifs::wl_subcompositor::WlSubcompositorError;
use crate::ifs::xdg_wm_base::XdgWmBaseError;
use crate::objects::{Interface, ObjectId};
use crate::object::{Interface, ObjectId};
use crate::utils::copyhashmap::CopyHashMap;
use crate::wl_client::{DynEventFormatter, WlClientData, WlClientError};
use crate::{NumCell, State};
use ahash::AHashSet;
use std::fmt::{Display, Formatter};
@ -19,7 +19,7 @@ pub enum GlobalError {
#[error("The requested global {0} does not exist")]
GlobalDoesNotExist(GlobalName),
#[error("An error occurred while trying to send all globals via a new registry")]
SendAllError(#[source] Box<WlClientError>),
SendAllError(#[source] Box<ClientError>),
#[error("An error occurred in a wl_compositor")]
WlCompositorError(#[source] Box<WlCompositorError>),
#[error("An error occurred in a wl_shm")]
@ -57,7 +57,7 @@ impl Display for GlobalName {
pub trait GlobalBind {
fn bind<'a>(
self: Rc<Self>,
client: &'a Rc<WlClientData>,
client: &'a Rc<Client>,
id: ObjectId,
version: u32,
) -> Pin<Box<dyn Future<Output = Result<(), GlobalError>> + 'a>>;
@ -121,7 +121,7 @@ impl Globals {
pub async fn notify_all(
&self,
client: &WlClientData,
client: &Client,
registry: &Rc<WlRegistry>,
) -> Result<(), GlobalError> {
let globals = self.registry.lock();
@ -136,7 +136,7 @@ impl Globals {
async fn broadcast<F: Fn(&Rc<WlRegistry>) -> DynEventFormatter>(&self, state: &State, f: F) {
let mut clients_to_check = AHashSet::new();
state.clients.broadcast(|c| {
let registries = c.objects.registries();
let registries = c.lock_registries();
for registry in registries.values() {
if c.event_locked(f(registry)) {
clients_to_check.insert(c.id);

View file

@ -1,8 +1,8 @@
mod types;
use crate::objects::{Interface, Object, ObjectError, ObjectId};
use crate::client::{ClientError, DynEventFormatter};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::WlParser;
use crate::wl_client::DynEventFormatter;
use std::rc::Rc;
use types::*;
@ -25,7 +25,7 @@ impl WlCallback {
&self,
_request: u32,
_parser: WlParser<'_, '_>,
) -> Result<(), ObjectError> {
) -> Result<(), ClientError> {
unreachable!();
}
}

View file

@ -1,7 +1,7 @@
use crate::client::EventFormatter;
use crate::ifs::wl_callback::{WlCallback, DONE};
use crate::objects::Object;
use crate::object::Object;
use crate::utils::buffd::WlFormatter;
use crate::wl_client::EventFormatter;
use std::fmt::{Debug, Formatter};
use std::rc::Rc;

View file

@ -1,13 +1,13 @@
mod types;
use crate::client::{AddObj, Client};
use crate::globals::{Global, GlobalName};
use crate::ifs::wl_region::WlRegion;
use crate::ifs::wl_surface::WlSurface;
use crate::objects::{Interface, Object, ObjectId};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::WlParser;
use crate::wl_client::WlClientData;
use std::rc::Rc;
pub use types::*;
use crate::ifs::wl_region::WlRegion;
const CREATE_SURFACE: u32 = 0;
const CREATE_REGION: u32 = 1;
@ -19,7 +19,7 @@ pub struct WlCompositorGlobal {
pub struct WlCompositorObj {
global: Rc<WlCompositorGlobal>,
id: ObjectId,
client: Rc<WlClientData>,
client: Rc<Client>,
version: u32,
}
@ -31,7 +31,7 @@ impl WlCompositorGlobal {
async fn bind_(
self: Rc<Self>,
id: ObjectId,
client: &Rc<WlClientData>,
client: &Rc<Client>,
version: u32,
) -> Result<(), WlCompositorError> {
let obj = Rc::new(WlCompositorObj {
@ -40,7 +40,7 @@ impl WlCompositorGlobal {
client: client.clone(),
version,
});
client.attach_client_object(obj)?;
client.add_client_obj(&obj)?;
Ok(())
}
}
@ -49,14 +49,14 @@ impl WlCompositorObj {
async fn create_surface(&self, parser: WlParser<'_, '_>) -> Result<(), CreateSurfaceError> {
let surface: CreateSurface = self.client.parse(self, parser)?;
let surface = Rc::new(WlSurface::new(surface.id, &self.client));
self.client.attach_client_object(surface)?;
self.client.add_client_obj(&surface)?;
Ok(())
}
async fn create_region(&self, parser: WlParser<'_, '_>) -> Result<(), CreateRegionError> {
let region: CreateRegion = self.client.parse(self, parser)?;
let region = Rc::new(WlRegion::new(region.id, &self.client));
self.client.attach_client_object(region)?;
self.client.add_client_obj(&region)?;
Ok(())
}

View file

@ -1,23 +1,20 @@
use crate::objects::{ObjectError, ObjectId};
use crate::client::{ClientError, RequestParser};
use crate::object::ObjectId;
use crate::utils::buffd::{WlParser, WlParserError};
use crate::wl_client::{RequestParser, WlClientError};
use std::fmt::{Debug, Formatter};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum WlCompositorError {
#[error(transparent)]
ObjectError(Box<ObjectError>),
#[error(transparent)]
ClientError(Box<WlClientError>),
ClientError(Box<ClientError>),
#[error("Could not process `create_surface` request")]
CreateSurfaceError(#[source] Box<CreateSurfaceError>),
#[error("Could not process `create_region` request")]
CreateRegionError(#[source] Box<CreateRegionError>),
}
efrom!(WlCompositorError, ObjectError, ObjectError);
efrom!(WlCompositorError, ClientError, WlClientError);
efrom!(WlCompositorError, ClientError, ClientError);
efrom!(WlCompositorError, CreateSurfaceError, CreateSurfaceError);
efrom!(WlCompositorError, CreateRegionError, CreateRegionError);
@ -26,22 +23,22 @@ pub enum CreateSurfaceError {
#[error("Parsing failed")]
ParseFailed(#[source] Box<WlParserError>),
#[error(transparent)]
ClientError(Box<WlClientError>),
ClientError(Box<ClientError>),
}
efrom!(CreateSurfaceError, ParseFailed, WlParserError);
efrom!(CreateSurfaceError, ClientError, WlClientError);
efrom!(CreateSurfaceError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum CreateRegionError {
#[error("Parsing failed")]
ParseFailed(#[source] Box<WlParserError>),
#[error(transparent)]
ClientError(Box<WlClientError>),
ClientError(Box<ClientError>),
}
efrom!(CreateRegionError, ParseFailed, WlParserError);
efrom!(CreateRegionError, ClientError, WlClientError);
efrom!(CreateRegionError, ClientError, ClientError);
pub(super) struct CreateSurface {
pub id: ObjectId,

View file

@ -1,10 +1,10 @@
mod types;
use crate::client::{AddObj, Client, ClientError, DynEventFormatter};
use crate::ifs::wl_callback::WlCallback;
use crate::ifs::wl_registry::WlRegistry;
use crate::objects::{Interface, Object, ObjectError, ObjectId, WL_DISPLAY_ID};
use crate::object::{Interface, Object, ObjectId, WL_DISPLAY_ID};
use crate::utils::buffd::WlParser;
use crate::wl_client::{DynEventFormatter, WlClientData};
use std::rc::Rc;
pub use types::*;
@ -20,11 +20,11 @@ const NO_MEMORY: u32 = 2;
const IMPLEMENTATION: u32 = 3;
pub struct WlDisplay {
client: Rc<WlClientData>,
client: Rc<Client>,
}
impl WlDisplay {
pub fn new(client: &Rc<WlClientData>) -> Self {
pub fn new(client: &Rc<Client>) -> Self {
Self {
client: client.clone(),
}
@ -46,19 +46,16 @@ impl WlDisplay {
async fn sync(&self, parser: WlParser<'_, '_>) -> Result<(), SyncError> {
let sync: Sync = self.client.parse(self, parser)?;
let cb = Rc::new(WlCallback::new(sync.callback));
self.client.attach_client_object(cb.clone())?;
self.client.add_client_obj(&cb)?;
self.client.event(cb.done()).await?;
self.client
.objects
.remove_obj(&self.client, cb.id())
.await?;
self.client.remove_obj(&*cb).await?;
Ok(())
}
async fn get_registry(&self, parser: WlParser<'_, '_>) -> Result<(), GetRegistryError> {
let gr: GetRegistry = self.client.parse(self, parser)?;
let registry = Rc::new(WlRegistry::new(gr.registry, &self.client));
self.client.attach_client_object(registry.clone())?;
self.client.add_client_obj(&registry)?;
self.client
.state
.globals
@ -124,7 +121,7 @@ impl Object for WlDisplay {
GET_REGISTRY + 1
}
fn into_display(self: Rc<Self>) -> Result<Rc<WlDisplay>, ObjectError> {
fn into_display(self: Rc<Self>) -> Result<Rc<WlDisplay>, ClientError> {
Ok(self)
}
}

View file

@ -1,8 +1,8 @@
use crate::client::{ClientError, EventFormatter, RequestParser};
use crate::globals::GlobalError;
use crate::ifs::wl_display::{WlDisplay, DELETE_ID, ERROR};
use crate::objects::{Object, ObjectError, ObjectId, WL_DISPLAY_ID};
use crate::object::{Object, ObjectId, WL_DISPLAY_ID};
use crate::utils::buffd::{WlFormatter, WlParser, WlParserError};
use crate::wl_client::{EventFormatter, RequestParser, WlClientError};
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
use thiserror::Error;
@ -22,32 +22,26 @@ efrom!(WlDisplayError, SyncError, SyncError);
pub enum GetRegistryError {
#[error("Parsing failed")]
ParseFailed(#[source] Box<WlParserError>),
#[error("An object error occurred")]
ObjectError(#[source] Box<ObjectError>),
#[error("An object error occurred")]
ClientError(#[source] Box<WlClientError>),
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("An error occurred while processing globals")]
GlobalError(#[source] Box<GlobalError>),
}
efrom!(GetRegistryError, ParseFailed, WlParserError);
efrom!(GetRegistryError, ObjectError, ObjectError);
efrom!(GetRegistryError, GlobalError, GlobalError);
efrom!(GetRegistryError, ClientError, WlClientError);
efrom!(GetRegistryError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum SyncError {
#[error("Parsing failed")]
ParseFailed(#[source] Box<WlParserError>),
#[error("An object error occurred")]
ObjectError(#[source] Box<ObjectError>),
#[error("A client error occurred")]
ClientError(#[source] Box<WlClientError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(SyncError, ParseFailed, WlParserError);
efrom!(SyncError, ObjectError, ObjectError);
efrom!(SyncError, ClientError, WlClientError);
efrom!(SyncError, ClientError, ClientError);
pub(super) struct GetRegistry {
pub registry: ObjectId,

View file

@ -1,13 +1,12 @@
mod types;
use crate::objects::{Interface, Object, ObjectError, ObjectId};
use crate::client::{AddObj, Client};
use crate::object::{Interface, Object, ObjectId};
use crate::pixman::Region;
use crate::utils::buffd::{WlParser, WlParserError};
use crate::wl_client::{RequestParser, WlClientData};
use crate::utils::buffd::WlParser;
use std::cell::RefCell;
use std::rc::Rc;
pub use types::*;
use crate::ifs::wl_display::WlDisplay;
const DESTROY: u32 = 0;
const ADD: u32 = 1;
@ -15,12 +14,12 @@ const SUBTRACT: u32 = 2;
pub struct WlRegion {
id: ObjectId,
client: Rc<WlClientData>,
client: Rc<Client>,
rect: RefCell<Region>,
}
impl WlRegion {
pub fn new(id: ObjectId, client: &Rc<WlClientData>) -> Self {
pub fn new(id: ObjectId, client: &Rc<Client>) -> Self {
Self {
id,
client: client.clone(),
@ -34,7 +33,7 @@ impl WlRegion {
async fn destroy(&self, parser: WlParser<'_, '_>) -> Result<(), DestroyError> {
let _destroy: Destroy = self.client.parse(self, parser)?;
self.client.objects.remove_obj(&self.client, self.id).await?;
self.client.remove_obj(self).await?;
Ok(())
}
@ -92,13 +91,4 @@ impl Object for WlRegion {
fn num_requests(&self) -> u32 {
SUBTRACT + 1
}
fn post_attach(self: Rc<Self>) {
self.client.objects.regions.set(self.id, self.clone());
}
fn pre_release(&self) -> Result<(), ObjectError> {
self.client.objects.regions.remove(&self.id);
Ok(())
}
}

View file

@ -1,6 +1,5 @@
use crate::objects::{ObjectError, ObjectId};
use crate::client::{ClientError, RequestParser};
use crate::utils::buffd::{WlParser, WlParserError};
use crate::wl_client::RequestParser;
use std::fmt::{Debug, Formatter};
use thiserror::Error;
@ -19,10 +18,10 @@ pub enum DestroyError {
#[error("Parsing failed")]
ParseFailed(#[source] Box<WlParserError>),
#[error(transparent)]
ObjectError(Box<ObjectError>),
ClientError(Box<ClientError>),
}
efrom!(DestroyError, ParseFailed, WlParserError);
efrom!(DestroyError, ObjectError, ObjectError);
efrom!(DestroyError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum AddError {

View file

@ -1,9 +1,9 @@
mod types;
use crate::client::{Client, DynEventFormatter};
use crate::globals::{Global, GlobalName};
use crate::objects::{Interface, Object, ObjectId};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::WlParser;
use crate::wl_client::{DynEventFormatter, WlClientData};
use std::rc::Rc;
pub use types::*;
@ -14,11 +14,11 @@ const GLOBAL_REMOVE: u32 = 1;
pub struct WlRegistry {
id: ObjectId,
client: Rc<WlClientData>,
client: Rc<Client>,
}
impl WlRegistry {
pub fn new(id: ObjectId, client: &Rc<WlClientData>) -> Self {
pub fn new(id: ObjectId, client: &Rc<Client>) -> Self {
Self {
id,
client: client.clone(),

View file

@ -1,8 +1,8 @@
use crate::client::{EventFormatter, RequestParser};
use crate::globals::{Global, GlobalError, GlobalName};
use crate::ifs::wl_registry::{WlRegistry, GLOBAL, GLOBAL_REMOVE};
use crate::objects::{Interface, Object, ObjectId};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::{WlFormatter, WlParser, WlParserError};
use crate::wl_client::{EventFormatter, RequestParser};
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
use thiserror::Error;

View file

@ -1,10 +1,10 @@
mod types;
use crate::client::{AddObj, Client};
use crate::globals::{Global, GlobalName};
use crate::ifs::wl_shm_pool::WlShmPool;
use crate::objects::{Interface, Object, ObjectId};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::WlParser;
use crate::wl_client::WlClientData;
use std::rc::Rc;
pub use types::*;
@ -19,7 +19,7 @@ pub struct WlShmGlobal {
pub struct WlShmObj {
global: Rc<WlShmGlobal>,
id: ObjectId,
client: Rc<WlClientData>,
client: Rc<Client>,
}
impl WlShmGlobal {
@ -30,7 +30,7 @@ impl WlShmGlobal {
async fn bind_(
self: Rc<Self>,
id: ObjectId,
client: &Rc<WlClientData>,
client: &Rc<Client>,
_version: u32,
) -> Result<(), WlShmError> {
let obj = Rc::new(WlShmObj {
@ -38,7 +38,7 @@ impl WlShmGlobal {
id,
client: client.clone(),
});
client.attach_client_object(obj.clone())?;
client.add_client_obj(&obj)?;
for &format in Format::formats() {
client
.event(Box::new(FormatE {
@ -63,7 +63,7 @@ impl WlShmObj {
create.fd,
create.size as usize,
)?);
self.client.attach_client_object(pool)?;
self.client.add_client_obj(&pool)?;
Ok(())
}

View file

@ -1,8 +1,8 @@
use crate::client::{ClientError, EventFormatter, RequestParser};
use crate::ifs::wl_shm::{Format, WlShmObj, FORMAT};
use crate::ifs::wl_shm_pool::WlShmPoolError;
use crate::objects::{Object, ObjectError, ObjectId};
use crate::object::{Object, ObjectId};
use crate::utils::buffd::{WlFormatter, WlParser, WlParserError};
use crate::wl_client::{EventFormatter, RequestParser, WlClientError};
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
use thiserror::Error;
@ -11,14 +11,11 @@ use uapi::OwnedFd;
#[derive(Debug, Error)]
pub enum WlShmError {
#[error(transparent)]
ObjectError(Box<ObjectError>),
#[error(transparent)]
ClientError(Box<WlClientError>),
ClientError(Box<ClientError>),
#[error("Could not process a `create_pool` request")]
CreatePoolError(#[from] CreatePoolError),
}
efrom!(WlShmError, ObjectError, ObjectError);
efrom!(WlShmError, ClientError, WlClientError);
efrom!(WlShmError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum CreatePoolError {
@ -29,11 +26,11 @@ pub enum CreatePoolError {
#[error(transparent)]
WlShmPoolError(Box<WlShmPoolError>),
#[error(transparent)]
ClientError(Box<WlClientError>),
ClientError(Box<ClientError>),
}
efrom!(CreatePoolError, ParseError, WlParserError);
efrom!(CreatePoolError, WlShmPoolError, WlShmPoolError);
efrom!(CreatePoolError, ClientError, WlClientError);
efrom!(CreatePoolError, ClientError, ClientError);
pub(super) struct CreatePool {
pub id: ObjectId,

View file

@ -1,9 +1,9 @@
mod types;
use crate::client::{AddObj, Client};
use crate::clientmem::ClientMem;
use crate::objects::{Interface, Object, ObjectId};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::WlParser;
use crate::wl_client::WlClientData;
use std::cell::RefCell;
use std::rc::Rc;
pub use types::*;
@ -15,7 +15,7 @@ const RESIZE: u32 = 2;
pub struct WlShmPool {
id: ObjectId,
client: Rc<WlClientData>,
client: Rc<Client>,
fd: OwnedFd,
mem: RefCell<Rc<ClientMem>>,
}
@ -23,7 +23,7 @@ pub struct WlShmPool {
impl WlShmPool {
pub fn new(
id: ObjectId,
client: &Rc<WlClientData>,
client: &Rc<Client>,
fd: OwnedFd,
len: usize,
) -> Result<Self, WlShmPoolError> {
@ -42,10 +42,7 @@ impl WlShmPool {
async fn destroy(&self, parser: WlParser<'_, '_>) -> Result<(), DestroyError> {
let _destroy: Destroy = self.client.parse(self, parser)?;
self.client
.objects
.remove_obj(&self.client, self.id)
.await?;
self.client.remove_obj(self).await?;
Ok(())
}

View file

@ -1,16 +1,14 @@
use crate::client::{ClientError, RequestParser};
use crate::clientmem::ClientMemError;
use crate::objects::{ObjectError, ObjectId};
use crate::object::ObjectId;
use crate::utils::buffd::{WlParser, WlParserError};
use crate::wl_client::{RequestParser, WlClientError};
use std::fmt::{Debug, Formatter};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum WlShmPoolError {
#[error(transparent)]
ObjectError(Box<ObjectError>),
#[error(transparent)]
ClientError(Box<WlClientError>),
ClientError(Box<ClientError>),
#[error("Could not process a `create_buffer` request")]
CreateBufferError(#[from] CreateBufferError),
#[error("Could not process a `destroy` request")]
@ -20,8 +18,7 @@ pub enum WlShmPoolError {
#[error(transparent)]
ClientMemError(Box<ClientMemError>),
}
efrom!(WlShmPoolError, ObjectError, ObjectError);
efrom!(WlShmPoolError, ClientError, WlClientError);
efrom!(WlShmPoolError, ClientError, ClientError);
efrom!(WlShmPoolError, ClientMemError, ClientMemError);
#[derive(Debug, Error)]
@ -29,20 +26,20 @@ pub enum CreateBufferError {
#[error("Parsing failed")]
ParseError(#[source] Box<WlParserError>),
#[error(transparent)]
ObjectError(Box<ObjectError>),
ClientError(Box<ClientError>),
}
efrom!(CreateBufferError, ParseError, WlParserError);
efrom!(CreateBufferError, ObjectError, ObjectError);
efrom!(CreateBufferError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum DestroyError {
#[error("Parsing failed")]
ParseError(#[source] Box<WlParserError>),
#[error(transparent)]
ObjectError(Box<ObjectError>),
ClientError(Box<ClientError>),
}
efrom!(DestroyError, ParseError, WlParserError);
efrom!(DestroyError, ObjectError, ObjectError);
efrom!(DestroyError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum ResizeError {

View file

@ -1,9 +1,9 @@
mod types;
use crate::client::{AddObj, Client, ClientError};
use crate::globals::{Global, GlobalName};
use crate::objects::{Interface, Object, ObjectError, ObjectId};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::WlParser;
use crate::wl_client::WlClientData;
use std::rc::Rc;
pub use types::*;
@ -24,11 +24,11 @@ impl WlSubcompositorGlobal {
async fn bind_(
self: Rc<Self>,
id: ObjectId,
client: &WlClientData,
client: &Client,
_version: u32,
) -> Result<(), WlSubcompositorError> {
let obj = Rc::new(WlSubcompositorObj { global: self, id });
client.attach_client_object(obj)?;
client.add_client_obj(&obj)?;
Ok(())
}
}
@ -38,7 +38,7 @@ impl WlSubcompositorObj {
&self,
request: u32,
parser: WlParser<'_, '_>,
) -> Result<(), ObjectError> {
) -> Result<(), ClientError> {
unreachable!();
}
}

View file

@ -1,14 +1,10 @@
use crate::objects::ObjectError;
use crate::wl_client::WlClientError;
use crate::client::ClientError;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum WlSubcompositorError {
#[error(transparent)]
ObjectError(Box<ObjectError>),
#[error(transparent)]
ClientError(Box<WlClientError>),
ClientError(Box<ClientError>),
}
efrom!(WlSubcompositorError, ObjectError, ObjectError);
efrom!(WlSubcompositorError, ClientError, WlClientError);
efrom!(WlSubcompositorError, ClientError, ClientError);

View file

@ -1,12 +1,12 @@
mod types;
use std::cell::Cell;
use crate::objects::{Interface, Object, ObjectError, ObjectId};
use crate::client::{Client, RequestParser};
use crate::object::{Interface, Object, ObjectId};
use crate::pixman::Region;
use crate::utils::buffd::{WlParser, WlParserError};
use crate::wl_client::{RequestParser, WlClientData};
use std::cell::Cell;
use std::rc::Rc;
pub use types::*;
use crate::pixman::Region;
const DESTROY: u32 = 0;
const ATTACH: u32 = 1;
@ -28,7 +28,7 @@ const INVALID_SIZE: u32 = 2;
pub struct WlSurface {
id: ObjectId,
client: Rc<WlClientData>,
client: Rc<Client>,
pending: PendingState,
}
@ -39,7 +39,7 @@ struct PendingState {
}
impl WlSurface {
pub fn new(id: ObjectId, client: &Rc<WlClientData>) -> Self {
pub fn new(id: ObjectId, client: &Rc<Client>) -> Self {
Self {
id,
client: client.clone(),
@ -150,13 +150,4 @@ impl Object for WlSurface {
fn num_requests(&self) -> u32 {
DAMAGE_BUFFER + 1
}
fn pre_release(&self) -> Result<(), ObjectError> {
self.client.objects.surfaces.remove(&self.id);
Ok(())
}
fn post_attach(self: Rc<Self>) {
self.client.objects.surfaces.set(self.id, self.clone());
}
}

View file

@ -1,6 +1,6 @@
use crate::objects::ObjectId;
use crate::client::{ClientError, RequestParser};
use crate::object::ObjectId;
use crate::utils::buffd::{WlParser, WlParserError};
use crate::wl_client::{RequestParser, WlClientError};
use std::fmt::{Debug, Formatter};
use thiserror::Error;
@ -75,20 +75,20 @@ pub enum SetOpaqueRegionError {
#[error("Parsing failed")]
ParseFailed(#[source] Box<WlParserError>),
#[error(transparent)]
ClientError(Box<WlClientError>),
ClientError(Box<ClientError>),
}
efrom!(SetOpaqueRegionError, ParseFailed, WlParserError);
efrom!(SetOpaqueRegionError, ClientError, WlClientError);
efrom!(SetOpaqueRegionError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum SetInputRegionError {
#[error("Parsing failed")]
ParseFailed(#[source] Box<WlParserError>),
#[error(transparent)]
ClientError(Box<WlClientError>),
ClientError(Box<ClientError>),
}
efrom!(SetInputRegionError, ParseFailed, WlParserError);
efrom!(SetInputRegionError, ClientError, WlClientError);
efrom!(SetInputRegionError, ClientError, ClientError);
#[derive(Debug, Error)]
pub enum CommitError {

View file

@ -1,9 +1,9 @@
mod types;
use crate::client::{AddObj, Client, ClientError};
use crate::globals::{Global, GlobalName};
use crate::objects::{Interface, Object, ObjectError, ObjectId};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::WlParser;
use crate::wl_client::WlClientData;
use std::rc::Rc;
pub use types::*;
@ -25,7 +25,7 @@ impl XdgWmBaseGlobal {
async fn bind_(
self: Rc<Self>,
id: ObjectId,
client: &WlClientData,
client: &Client,
version: u32,
) -> Result<(), XdgWmBaseError> {
let obj = Rc::new(XdgWmBaseObj {
@ -33,7 +33,7 @@ impl XdgWmBaseGlobal {
id,
version,
});
client.attach_client_object(obj)?;
client.add_client_obj(&obj)?;
Ok(())
}
}
@ -43,7 +43,7 @@ impl XdgWmBaseObj {
&self,
request: u32,
parser: WlParser<'_, '_>,
) -> Result<(), ObjectError> {
) -> Result<(), ClientError> {
unreachable!();
}
}

View file

@ -1,14 +1,10 @@
use crate::objects::ObjectError;
use crate::wl_client::WlClientError;
use crate::client::ClientError;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum XdgWmBaseError {
#[error(transparent)]
ObjectError(Box<ObjectError>),
#[error(transparent)]
ClientError(Box<WlClientError>),
ClientError(Box<ClientError>),
}
efrom!(XdgWmBaseError, ObjectError, ObjectError);
efrom!(XdgWmBaseError, ClientError, WlClientError);
efrom!(XdgWmBaseError, ClientError, ClientError);

View file

@ -10,13 +10,13 @@ macro_rules! efrom {
macro_rules! handle_request {
($oname:ty) => {
impl crate::objects::ObjectHandleRequest for $oname {
impl crate::object::ObjectHandleRequest for $oname {
fn handle_request<'a>(
&'a self,
request: u32,
parser: crate::utils::buffd::WlParser<'a, 'a>,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = Result<(), crate::objects::ObjectError>> + 'a>,
Box<dyn std::future::Future<Output = Result<(), crate::client::ClientError>> + 'a>,
> {
Box::pin(async move {
self.handle_request_(request, parser).await?;
@ -32,8 +32,8 @@ macro_rules! bind {
impl crate::globals::GlobalBind for $oname {
fn bind<'a>(
self: std::rc::Rc<Self>,
client: &'a std::rc::Rc<crate::wl_client::WlClientData>,
id: crate::objects::ObjectId,
client: &'a std::rc::Rc<crate::client::Client>,
id: crate::object::ObjectId,
version: u32,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = Result<(), crate::globals::GlobalError>> + 'a>,

View file

@ -1,4 +1,7 @@
#![feature(generic_associated_types, type_alias_impl_trait)]
use crate::acceptor::AcceptorError;
use crate::client::Clients;
use crate::clientmem::ClientMemError;
use crate::event_loop::EventLoopError;
use crate::globals::Globals;
@ -9,7 +12,6 @@ use crate::ifs::xdg_wm_base::XdgWmBaseGlobal;
use crate::sighand::SighandError;
use crate::state::State;
use crate::utils::numcell::NumCell;
use crate::wl_client::WlClients;
use anyhow::anyhow;
use log::LevelFilter;
use std::rc::Rc;
@ -19,18 +21,18 @@ use thiserror::Error;
mod macros;
mod acceptor;
mod async_engine;
mod client;
mod clientmem;
mod event_loop;
mod globals;
mod ifs;
mod objects;
mod object;
mod pixman;
mod sighand;
mod state;
mod time;
mod utils;
mod wheel;
mod wl_client;
fn main() {
env_logger::builder()
@ -68,7 +70,7 @@ fn main_() -> Result<(), MainError> {
let state = Rc::new(State {
eng: engine,
el: el.to_ref(),
clients: WlClients::new(),
clients: Clients::new(),
next_name: NumCell::new(1),
globals,
});

76
src/object.rs Normal file
View file

@ -0,0 +1,76 @@
use crate::client::ClientError;
use crate::ifs::wl_display::WlDisplay;
use crate::utils::buffd::WlParser;
use std::fmt::{Display, Formatter};
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
pub const WL_DISPLAY_ID: ObjectId = ObjectId(1);
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct ObjectId(u32);
impl ObjectId {
pub fn from_raw(raw: u32) -> Self {
Self(raw)
}
pub fn raw(self) -> u32 {
self.0
}
}
impl Display for ObjectId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}
pub trait ObjectHandleRequest {
fn handle_request<'a>(
&'a self,
request: u32,
parser: WlParser<'a, 'a>,
) -> Pin<Box<dyn Future<Output = Result<(), ClientError>> + 'a>>;
}
pub trait Object: ObjectHandleRequest + 'static {
fn id(&self) -> ObjectId;
fn interface(&self) -> Interface;
fn num_requests(&self) -> u32;
fn into_display(self: Rc<Self>) -> Result<Rc<WlDisplay>, ClientError> {
Err(ClientError::NotADisplay(self.id()))
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Interface {
WlDisplay,
WlCallback,
WlCompositor,
WlRegistry,
WlShm,
WlShmPool,
WlSubcompositor,
XdgWmBase,
WlSurface,
WlRegion,
}
impl Interface {
pub fn name(self) -> &'static str {
match self {
Interface::WlDisplay => "wl_display",
Interface::WlCallback => "wl_callback",
Interface::WlCompositor => "wl_compositor",
Interface::WlRegistry => "wl_registry",
Interface::WlShm => "wl_shm",
Interface::WlSubcompositor => "wl_subcompositor",
Interface::XdgWmBase => "xdg_wm_base",
Interface::WlSurface => "wl_surface",
Interface::WlShmPool => "wl_shm_pool",
Interface::WlRegion => "wl_region",
}
}
}

View file

@ -1,249 +0,0 @@
use crate::ifs::wl_compositor::WlCompositorError;
use crate::ifs::wl_display::{WlDisplay, WlDisplayError};
use crate::ifs::wl_registry::{WlRegistry, WlRegistryError};
use crate::ifs::wl_shm::WlShmError;
use crate::ifs::wl_shm_pool::WlShmPoolError;
use crate::ifs::wl_surface::{WlSurface, WlSurfaceError};
use crate::utils::buffd::{WlParser, WlParserError};
use crate::utils::copyhashmap::CopyHashMap;
use crate::wl_client::{WlClientData, WlClientError};
use ahash::AHashMap;
use std::cell::{RefCell, RefMut};
use std::fmt::{Display, Formatter};
use std::future::Future;
use std::mem;
use std::pin::Pin;
use std::rc::Rc;
use thiserror::Error;
use crate::ifs::wl_region::{WlRegion, WlRegionError};
#[derive(Debug, Error)]
pub enum ObjectError {
#[error("A client error occurred")]
ClientError(#[source] Box<WlClientError>),
#[error("Cannot parse the message")]
ParserError(#[source] Box<WlParserError>),
#[error("Server tried to allocate more than 0x1_00_00_00 ids")]
TooManyIds,
#[error("The server object id is out of bounds")]
ServerIdOutOfBounds,
#[error("The object id is unknown")]
UnknownId,
#[error("The id is already in use")]
IdAlreadyInUse,
#[error("The client object id is out of bounds")]
ClientIdOutOfBounds,
#[error("An error occurred in a `wl_display`")]
WlDisplayError(#[source] Box<WlDisplayError>),
#[error("An error occurred in a `wl_registry`")]
WlRegistryError(#[source] Box<WlRegistryError>),
#[error("Could not add object {0} to the client")]
AddObjectError(ObjectId, #[source] Box<ObjectError>),
#[error("An error occurred in a `wl_surface`")]
WlSurfaceError(#[source] Box<WlSurfaceError>),
#[error("An error occurred in a `wl_compositor`")]
WlCompositorError(#[source] Box<WlCompositorError>),
#[error("An error occurred in a `wl_shm`")]
WlShmError(#[source] Box<WlShmError>),
#[error("An error occurred in a `wl_shm_pool`")]
WlShmPoolError(#[source] Box<WlShmPoolError>),
#[error("An error occurred in a `wl_region`")]
WlRegionError(#[source] Box<WlRegionError>),
#[error("Object {0} is not a display")]
NotADisplay(ObjectId),
}
efrom!(ObjectError, ClientError, WlClientError);
efrom!(ObjectError, ParserError, WlParserError);
efrom!(ObjectError, WlDisplayError, WlDisplayError);
efrom!(ObjectError, WlRegistryError, WlRegistryError);
efrom!(ObjectError, WlSurfaceError, WlSurfaceError);
efrom!(ObjectError, WlCompositorError, WlCompositorError);
efrom!(ObjectError, WlShmError, WlShmError);
efrom!(ObjectError, WlShmPoolError, WlShmPoolError);
efrom!(ObjectError, WlRegionError, WlRegionError);
pub const WL_DISPLAY_ID: ObjectId = ObjectId(1);
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct ObjectId(u32);
impl ObjectId {
pub fn from_raw(raw: u32) -> Self {
Self(raw)
}
pub fn raw(self) -> u32 {
self.0
}
}
impl Display for ObjectId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}
pub trait ObjectHandleRequest {
fn handle_request<'a>(
&'a self,
request: u32,
parser: WlParser<'a, 'a>,
) -> Pin<Box<dyn Future<Output = Result<(), ObjectError>> + 'a>>;
}
pub trait Object: ObjectHandleRequest {
fn id(&self) -> ObjectId;
fn interface(&self) -> Interface;
fn num_requests(&self) -> u32;
fn pre_release(&self) -> Result<(), ObjectError> {
Ok(())
}
fn post_attach(self: Rc<Self>) {}
fn into_display(self: Rc<Self>) -> Result<Rc<WlDisplay>, ObjectError> {
Err(ObjectError::NotADisplay(self.id()))
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Interface {
WlDisplay,
WlCallback,
WlCompositor,
WlRegistry,
WlShm,
WlShmPool,
WlSubcompositor,
XdgWmBase,
WlSurface,
WlRegion,
}
impl Interface {
pub fn name(self) -> &'static str {
match self {
Interface::WlDisplay => "wl_display",
Interface::WlCallback => "wl_callback",
Interface::WlCompositor => "wl_compositor",
Interface::WlRegistry => "wl_registry",
Interface::WlShm => "wl_shm",
Interface::WlSubcompositor => "wl_subcompositor",
Interface::XdgWmBase => "xdg_wm_base",
Interface::WlSurface => "wl_surface",
Interface::WlShmPool => "wl_shm_pool",
Interface::WlRegion => "wl_region",
}
}
}
pub struct Objects {
registry: CopyHashMap<ObjectId, Rc<dyn Object>>,
registries: CopyHashMap<ObjectId, Rc<WlRegistry>>,
pub surfaces: CopyHashMap<ObjectId, Rc<WlSurface>>,
pub regions: CopyHashMap<ObjectId, Rc<WlRegion>>,
ids: RefCell<Vec<usize>>,
}
const MIN_SERVER_ID: u32 = 0xff000000;
const SEG_SIZE: usize = 8 * mem::size_of::<usize>();
impl Objects {
pub fn new() -> Self {
Self {
registry: Default::default(),
registries: Default::default(),
surfaces: Default::default(),
regions: Default::default(),
ids: RefCell::new(vec![]),
}
}
pub fn destroy(&self) {
self.registry.clear();
self.registries.clear();
self.surfaces.clear();
}
fn id(&self, client_data: &WlClientData) -> Result<ObjectId, ObjectError> {
const MAX_ID_OFFSET: u32 = u32::MAX - MIN_SERVER_ID;
let offset = self.id_offset();
if offset > MAX_ID_OFFSET {
log::error!(
"Client {} caused the server to allocate more than 0x{:x} ids",
client_data.id,
MAX_ID_OFFSET + 1
);
return Err(ObjectError::TooManyIds);
}
Ok(ObjectId(MIN_SERVER_ID + offset))
}
pub fn get_obj(&self, id: ObjectId) -> Result<Rc<dyn Object>, ObjectError> {
match self.registry.get(&id) {
Some(o) => Ok(o),
_ => Err(ObjectError::UnknownId),
}
}
pub fn add_client_object(&self, obj: Rc<dyn Object>) -> Result<(), ObjectError> {
let id = obj.id();
let res = (|| {
if id.0 == 0 || id.0 >= MIN_SERVER_ID {
return Err(ObjectError::ClientIdOutOfBounds);
}
if self.registry.contains(&id) {
return Err(ObjectError::IdAlreadyInUse);
}
self.registry.set(id, obj.clone());
obj.post_attach();
Ok(())
})();
if let Err(e) = res {
return Err(ObjectError::AddObjectError(id, Box::new(e)));
}
Ok(())
}
pub async fn remove_obj(
&self,
client_data: &WlClientData,
id: ObjectId,
) -> Result<(), ObjectError> {
let obj = match self.registry.remove(&id) {
Some(o) => o,
_ => return Err(ObjectError::UnknownId),
};
obj.pre_release()?;
if id.0 >= MIN_SERVER_ID {
let offset = (id.0 - MIN_SERVER_ID) as usize;
let pos = offset / SEG_SIZE;
let seg_offset = offset % SEG_SIZE;
let mut ids = self.ids.borrow_mut();
if ids.len() <= pos {
return Err(ObjectError::ServerIdOutOfBounds);
}
ids[pos] |= 1 << seg_offset;
}
client_data
.event(client_data.display()?.delete_id(id))
.await?;
Ok(())
}
pub fn registries(&self) -> RefMut<AHashMap<ObjectId, Rc<WlRegistry>>> {
self.registries.lock()
}
fn id_offset(&self) -> u32 {
let mut ids = self.ids.borrow_mut();
for (pos, seg) in ids.iter_mut().enumerate() {
if *seg != 0 {
let offset = seg.trailing_zeros();
*seg &= !(1 << offset);
return (pos * SEG_SIZE) as u32 + offset;
}
}
ids.push(!1);
((ids.len() - 1) * SEG_SIZE) as u32
}
}

View file

@ -1,4 +1,3 @@
use std::ops::{Add, Sub};
use std::ptr;
use uapi::c;

View file

@ -1,14 +1,14 @@
use crate::async_engine::AsyncEngine;
use crate::client::Clients;
use crate::event_loop::EventLoopRef;
use crate::globals::Globals;
use crate::utils::numcell::NumCell;
use crate::wl_client::WlClients;
use std::rc::Rc;
pub struct State {
pub eng: Rc<AsyncEngine>,
pub el: EventLoopRef,
pub clients: WlClients,
pub clients: Clients,
pub next_name: NumCell<u32>,
pub globals: Globals,
}

View file

@ -1,4 +1,4 @@
use crate::objects::ObjectId;
use crate::object::ObjectId;
use crate::utils::buffd::buf_out::{BufFdOut, MsgFds};
use std::mem;
use std::mem::MaybeUninit;

View file

@ -1,5 +1,5 @@
use crate::globals::GlobalName;
use crate::objects::ObjectId;
use crate::object::ObjectId;
use crate::utils::buffd::BufFdIn;
use thiserror::Error;
use uapi::OwnedFd;

View file

@ -1,420 +0,0 @@
use crate::async_engine::{AsyncError, AsyncFd, SpawnedFuture};
use crate::ifs::wl_display::WlDisplay;
use crate::objects::{Object, ObjectError, ObjectId, Objects, WL_DISPLAY_ID};
use crate::state::State;
use crate::utils::buffd::{BufFdError, BufFdIn, BufFdOut, WlFormatter, WlParser, WlParserError};
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::numcell::NumCell;
use crate::utils::oneshot::{oneshot, OneshotRx, OneshotTx};
use crate::utils::queue::AsyncQueue;
use crate::utils::vec_ext::VecExt;
use anyhow::anyhow;
use futures::{select, FutureExt};
use std::cell::Cell;
use std::fmt::{Debug, Display, Formatter};
use std::mem;
use std::rc::Rc;
use thiserror::Error;
use uapi::OwnedFd;
use crate::ifs::wl_region::WlRegion;
#[derive(Debug, Error)]
pub enum WlClientError {
#[error("An error occurred in the async engine")]
Async(#[from] AsyncError),
#[error("An error occurred reading from/writing to the client")]
Io(#[from] BufFdError),
#[error("An error occurred while processing a request")]
RequestError(#[source] Box<ObjectError>),
#[error("Client tried to invoke a non-existent method")]
InvalidMethod,
#[error("Client tried to access non-existent object {0}")]
InvalidObject(ObjectId),
#[error("The message size is < 8")]
MessageSizeTooSmall,
#[error("The size of the message is not a multiple of 4")]
UnalignedMessage,
#[error("The outgoing buffer overflowed")]
OutBufferOverflow,
#[error("The requested client {0} does not exist")]
ClientDoesNotExist(ClientId),
#[error(transparent)]
ObjectError(Box<ObjectError>),
#[error("There is no region with id {0}")]
RegionDoesNotExist(ObjectId),
}
efrom!(WlClientError, ObjectError, ObjectError);
impl WlClientError {
fn peer_closed(&self) -> bool {
match self {
WlClientError::Io(BufFdError::Closed) => true,
_ => false,
}
}
}
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct ClientId(u64);
impl Display for ClientId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}
pub struct WlClients {
next_client_id: NumCell<u64>,
clients: CopyHashMap<ClientId, Rc<WlClient>>,
shutdown_clients: CopyHashMap<ClientId, Rc<WlClient>>,
}
impl WlClients {
pub fn new() -> Self {
Self {
next_client_id: NumCell::new(1),
clients: CopyHashMap::new(),
shutdown_clients: CopyHashMap::new(),
}
}
pub fn id(&self) -> ClientId {
ClientId(self.next_client_id.fetch_add(1))
}
pub fn get(&self, id: ClientId) -> Result<Rc<WlClientData>, WlClientError> {
match self.clients.get(&id) {
Some(c) => Ok(c.data.clone()),
_ => Err(WlClientError::ClientDoesNotExist(id)),
}
}
pub fn spawn(
&self,
id: ClientId,
global: &Rc<State>,
socket: OwnedFd,
) -> Result<(), WlClientError> {
let (send, recv) = oneshot();
let data = Rc::new(WlClientData {
id,
state: global.clone(),
socket: global.eng.fd(&Rc::new(socket))?,
objects: Objects::new(),
events: AsyncQueue::new(),
shutdown: Cell::new(Some(send)),
shutdown_sent: Cell::new(false),
});
data.objects
.add_client_object(Rc::new(WlDisplay::new(&data)))
.expect("");
let client = Rc::new(WlClient {
_handler: global.eng.spawn(client(data.clone(), recv)),
data,
});
self.clients.set(client.data.id, client.clone());
log::info!("Client {} connected", id);
Ok(())
}
pub fn kill(&self, client: ClientId) {
log::info!("Removing client {}", client.0);
if self.clients.remove(&client).is_none() {
self.shutdown_clients.remove(&client);
}
}
pub fn shutdown(&self, client_id: ClientId) {
if let Some(client) = self.clients.remove(&client_id) {
log::info!("Shutting down client {}", client.data.id.0);
client.data.shutdown.replace(None).unwrap().send(());
client.data.events.push(WlEvent::Shutdown);
client.data.shutdown_sent.set(true);
self.shutdown_clients.set(client_id, client);
}
}
pub fn broadcast<B>(&self, mut f: B)
where
B: FnMut(&Rc<WlClientData>),
{
let clients = self.clients.lock();
for client in clients.values() {
f(&client.data);
}
}
}
struct WlClient {
data: Rc<WlClientData>,
_handler: SpawnedFuture<()>,
}
impl Drop for WlClient {
fn drop(&mut self) {
self.data.objects.destroy();
}
}
pub trait EventFormatter: Debug {
fn format(self: Box<Self>, fmt: &mut WlFormatter<'_>);
fn obj(&self) -> &dyn Object;
}
pub type DynEventFormatter = Box<dyn EventFormatter>;
pub trait RequestParser<'a>: Debug + Sized {
fn parse(parser: &mut WlParser<'_, 'a>) -> Result<Self, WlParserError>;
}
enum WlEvent {
Flush,
Shutdown,
Event(Box<dyn EventFormatter>),
}
pub struct WlClientData {
pub id: ClientId,
pub state: Rc<State>,
socket: AsyncFd,
pub objects: Objects,
events: AsyncQueue<WlEvent>,
shutdown: Cell<Option<OneshotTx<()>>>,
shutdown_sent: Cell<bool>,
}
const MAX_PENDING_EVENTS: usize = 100;
impl WlClientData {
pub fn invalid_request(&self, obj: &dyn Object, request: u32) {
log::error!(
"Client {} sent an invalid request {} on object {} of type {}",
self.id.0,
request,
obj.id(),
obj.interface().name(),
);
match self.display() {
Ok(d) => self.fatal_event(d.invalid_request(obj, request)),
Err(e) => {
log::error!(
"Could not retrieve display of client {}: {:#}",
self.id,
anyhow!(e)
);
self.state.clients.kill(self.id);
}
}
}
pub fn display(&self) -> Result<Rc<WlDisplay>, WlClientError> {
Ok(self.objects.get_obj(WL_DISPLAY_ID)?.into_display()?)
}
pub fn parse<'a, R: RequestParser<'a>>(
&self,
obj: &impl Object,
mut parser: WlParser<'_, 'a>,
) -> Result<R, WlParserError> {
let res = R::parse(&mut parser)?;
parser.eof()?;
log::trace!(
"Client {} -> {}@{}.{:?}",
self.id,
obj.interface().name(),
obj.id(),
res
);
Ok(res)
}
pub fn fatal_event(&self, event: Box<dyn EventFormatter>) {
self.events.push(WlEvent::Event(event));
self.state.clients.shutdown(self.id);
}
pub fn event_locked(&self, event: Box<dyn EventFormatter>) -> bool {
self.events.push(WlEvent::Event(event));
self.events.size() > MAX_PENDING_EVENTS
}
pub async fn event(&self, event: Box<dyn EventFormatter>) -> Result<(), WlClientError> {
self.event2(WlEvent::Event(event)).await
}
async fn event2(&self, event: WlEvent) -> Result<(), WlClientError> {
self.events.push(event);
self.check_queue_size().await
}
pub async fn check_queue_size(&self) -> Result<(), WlClientError> {
if self.events.size() > MAX_PENDING_EVENTS {
self.state.eng.yield_now().await;
if self.events.size() > MAX_PENDING_EVENTS {
log::error!("Client {} is too slow at fetching events", self.id.0);
self.state.clients.kill(self.id);
return Err(WlClientError::OutBufferOverflow);
}
}
Ok(())
}
pub fn attach_client_object(&self, obj: Rc<dyn Object>) -> Result<(), WlClientError> {
self.objects.add_client_object(obj.clone())?;
obj.post_attach();
Ok(())
}
pub fn get_region(&self, id: ObjectId) -> Result<Rc<WlRegion>, WlClientError> {
match self.objects.regions.get(&id) {
Some(r) => Ok(r),
_ => Err(WlClientError::RegionDoesNotExist(id)),
}
}
}
async fn client(data: Rc<WlClientData>, shutdown: OneshotRx<()>) {
let mut recv = data.state.eng.spawn(receive(data.clone())).fuse();
let _send = data.state.eng.spawn(send(data.clone()));
select! {
_ = recv => { },
_ = shutdown.fuse() => { },
}
drop(recv);
if !data.shutdown_sent.get() {
data.events.push(WlEvent::Shutdown);
}
match data.state.eng.timeout(5000) {
Ok(timeout) => {
timeout.await;
log::error!("Could not shut down client {} within 5 seconds", data.id.0);
}
Err(e) => {
log::error!("Could not create a timeout: {:#}", e);
}
}
data.state.clients.kill(data.id);
}
async fn receive(data: Rc<WlClientData>) {
let display = data.display().unwrap();
let recv = async {
let mut buf = BufFdIn::new(data.socket.clone());
let mut data_buf = Vec::<u32>::new();
loop {
let mut hdr = [0u32, 0];
buf.read_full(&mut hdr[..]).await?;
let obj_id = ObjectId::from_raw(hdr[0]);
let len = (hdr[1] >> 16) as usize;
let request = hdr[1] & 0xffff;
let obj = match data.objects.get_obj(obj_id) {
Ok(obj) => obj,
_ => {
data.fatal_event(display.invalid_object(obj_id));
return Err(WlClientError::InvalidObject(obj_id));
}
};
// log::trace!("obj: {}, request: {}, len: {}", obj_id, request, len);
if request >= obj.num_requests() {
data.invalid_request(&*obj, request);
return Err(WlClientError::InvalidMethod);
}
if len < 8 {
return Err(WlClientError::MessageSizeTooSmall);
}
if len % 4 != 0 {
return Err(WlClientError::UnalignedMessage);
}
let len = len / 4 - 2;
data_buf.clear();
data_buf.reserve(len);
let unused = data_buf.split_at_spare_mut_ext().1;
buf.read_full(&mut unused[..len]).await?;
unsafe {
data_buf.set_len(len);
}
// log::trace!("{:x?}", data_buf);
let parser = WlParser::new(&mut buf, &data_buf[..]);
if let Err(e) = obj.handle_request(request, parser).await {
return Err(WlClientError::RequestError(Box::new(e)));
}
data.event2(WlEvent::Flush).await?;
}
};
let res: Result<(), WlClientError> = recv.await;
if let Err(e) = res {
if e.peer_closed() {
log::info!("Client {} terminated the connection", data.id.0);
data.state.clients.kill(data.id);
} else {
let e = anyhow!(e);
log::error!(
"An error occurred while trying to handle a message from client {}: {:#}",
data.id.0,
e
);
if !data.shutdown_sent.get() {
data.fatal_event(display.implementation_error(format!("{:#}", e)));
}
}
}
}
async fn send(data: Rc<WlClientData>) {
let send = async {
let mut buf = BufFdOut::new(data.socket.clone());
let mut flush_requested = false;
loop {
let mut event = data.events.pop().await;
loop {
match event {
WlEvent::Flush => {
flush_requested = true;
}
WlEvent::Shutdown => {
buf.flush().await?;
return Ok(());
}
WlEvent::Event(e) => {
if log::log_enabled!(log::Level::Trace) {
let obj = e.obj();
log::trace!(
"Client {} <= {}@{}.{:?}",
data.id,
obj.interface().name(),
obj.id(),
e
);
}
e.format(&mut WlFormatter::new(&mut buf));
if buf.needs_flush() {
buf.flush().await?;
flush_requested = false;
}
}
}
event = match data.events.try_pop() {
Some(e) => e,
_ => break,
};
}
if mem::take(&mut flush_requested) {
buf.flush().await?;
}
}
};
let res: Result<(), WlClientError> = send.await;
if let Err(e) = res {
if e.peer_closed() {
log::info!("Client {} terminated the connection", data.id.0);
} else {
log::error!(
"An error occurred while sending data to client {}: {:#}",
data.id.0,
e
);
}
}
data.state.clients.kill(data.id);
}