From c21f231ce7292c09224a9c7155e3257c1b15216d Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sun, 2 Jan 2022 16:30:30 +0100 Subject: [PATCH] autocommit 2022-01-02 16:30:30 CET --- src/acceptor.rs | 4 +- src/client/mod.rs | 395 ++++++++++++++++++++++++++++ src/client/objects.rs | 122 +++++++++ src/client/tasks.rs | 154 +++++++++++ src/globals.rs | 12 +- src/ifs/wl_callback/mod.rs | 6 +- src/ifs/wl_callback/types.rs | 4 +- src/ifs/wl_compositor/mod.rs | 16 +- src/ifs/wl_compositor/types.rs | 19 +- src/ifs/wl_display/mod.rs | 19 +- src/ifs/wl_display/types.rs | 22 +- src/ifs/wl_region/mod.rs | 22 +- src/ifs/wl_region/types.rs | 7 +- src/ifs/wl_registry/mod.rs | 8 +- src/ifs/wl_registry/types.rs | 4 +- src/ifs/wl_shm/mod.rs | 12 +- src/ifs/wl_shm/types.rs | 15 +- src/ifs/wl_shm_pool/mod.rs | 13 +- src/ifs/wl_shm_pool/types.rs | 19 +- src/ifs/wl_subcompositor/mod.rs | 10 +- src/ifs/wl_subcompositor/types.rs | 10 +- src/ifs/wl_surface/mod.rs | 21 +- src/ifs/wl_surface/types.rs | 12 +- src/ifs/xdg_wm_base/mod.rs | 10 +- src/ifs/xdg_wm_base/types.rs | 10 +- src/macros.rs | 8 +- src/main.rs | 10 +- src/object.rs | 76 ++++++ src/objects.rs | 249 ------------------ src/{pixman/mod.rs => pixman.rs} | 1 - src/state.rs | 4 +- src/utils/buffd/wl_formatter.rs | 2 +- src/utils/buffd/wl_parser.rs | 2 +- src/wl_client.rs | 420 ------------------------------ 34 files changed, 874 insertions(+), 844 deletions(-) create mode 100644 src/client/mod.rs create mode 100644 src/client/objects.rs create mode 100644 src/client/tasks.rs create mode 100644 src/object.rs delete mode 100644 src/objects.rs rename src/{pixman/mod.rs => pixman.rs} (98%) delete mode 100644 src/wl_client.rs diff --git a/src/acceptor.rs b/src/acceptor.rs index 6eeb0816..08b410ce 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -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")] diff --git a/src/client/mod.rs b/src/client/mod.rs new file mode 100644 index 00000000..624e0eaa --- /dev/null +++ b/src/client/mod.rs @@ -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), + #[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), + #[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), + #[error("An error occurred in a `wl_registry`")] + WlRegistryError(#[source] Box), + #[error("Could not add object {0} to the client")] + AddObjectError(ObjectId, #[source] Box), + #[error("An error occurred in a `wl_surface`")] + WlSurfaceError(#[source] Box), + #[error("An error occurred in a `wl_compositor`")] + WlCompositorError(#[source] Box), + #[error("An error occurred in a `wl_shm`")] + WlShmError(#[source] Box), + #[error("An error occurred in a `wl_shm_pool`")] + WlShmPoolError(#[source] Box), + #[error("An error occurred in a `wl_region`")] + WlRegionError(#[source] Box), + #[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, + clients: CopyHashMap>, + shutdown_clients: CopyHashMap>, +} + +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, ClientError> { + match self.clients.get(&id) { + Some(c) => Ok(c.data.clone()), + _ => Err(ClientError::ClientDoesNotExist(id)), + } + } + + pub fn spawn( + &self, + id: ClientId, + global: &Rc, + 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(&self, mut f: B) + where + B: FnMut(&Rc), + { + let clients = self.clients.lock(); + for client in clients.values() { + f(&client.data); + } + } +} + +struct ClientHolder { + data: Rc, + _handler: SpawnedFuture<()>, +} + +impl Drop for ClientHolder { + fn drop(&mut self) { + self.data.objects.destroy(); + } +} + +pub trait EventFormatter: Debug { + fn format(self: Box, fmt: &mut WlFormatter<'_>); + fn obj(&self) -> &dyn Object; +} + +pub type DynEventFormatter = Box; + +pub trait RequestParser<'a>: Debug + Sized { + fn parse(parser: &mut WlParser<'_, 'a>) -> Result; +} + +enum WlEvent { + Flush, + Shutdown, + Event(Box), +} + +pub struct Client { + pub id: ClientId, + pub state: Rc, + socket: AsyncFd, + objects: Objects, + events: AsyncQueue, + shutdown: Cell>>, + shutdown_sent: Cell, +} + +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, 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 { + 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) { + self.events.push(WlEvent::Event(event)); + self.state.clients.shutdown(self.id); + } + + pub fn event_locked(&self, event: Box) -> bool { + self.events.push(WlEvent::Event(event)); + self.events.size() > MAX_PENDING_EVENTS + } + + pub async fn event(&self, event: Box) -> 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, ClientError> { + match self.objects.regions.get(&id) { + Some(r) => Ok(r), + _ => Err(ClientError::RegionDoesNotExist(id)), + } + } + + fn simple_add_obj(&self, obj: &Rc, 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> + 'a { + self.objects.remove_obj(self, id) + } + + pub fn lock_registries(&self) -> RefMut>> { + self.objects.registries() + } +} + +pub trait AddObj { + type RemoveObj<'a>: Future> + 'a; + + fn add_client_obj(&self, obj: &Rc) -> Result<(), ClientError> { + self.add_obj(obj, true) + } + + fn add_server_obj(&self, obj: &Rc) { + self.add_obj(obj, false).expect("add_server_obj failed") + } + + fn add_obj(&self, obj: &Rc, 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> + '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> + '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); diff --git a/src/client/objects.rs b/src/client/objects.rs new file mode 100644 index 00000000..758244ae --- /dev/null +++ b/src/client/objects.rs @@ -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>, + registries: CopyHashMap>, + pub surfaces: CopyHashMap>, + pub regions: CopyHashMap>, + ids: RefCell>, +} + +pub const MIN_SERVER_ID: u32 = 0xff000000; +const SEG_SIZE: usize = 8 * mem::size_of::(); + +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 { + 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, ClientError> { + match self.registry.get(&id) { + Some(o) => Ok(o), + _ => Err(ClientError::UnknownId), + } + } + + pub fn add_server_object(&self, obj: Rc) { + 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) -> 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>> { + 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 + } +} diff --git a/src/client/tasks.rs b/src/client/tasks.rs new file mode 100644 index 00000000..e6e8a203 --- /dev/null +++ b/src/client/tasks.rs @@ -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, 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) { + let display = data.display().unwrap(); + let recv = async { + let mut buf = BufFdIn::new(data.socket.clone()); + let mut data_buf = Vec::::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) { + 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); +} diff --git a/src/globals.rs b/src/globals.rs index b4b525cd..7a3b2456 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -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), + SendAllError(#[source] Box), #[error("An error occurred in a wl_compositor")] WlCompositorError(#[source] Box), #[error("An error occurred in a wl_shm")] @@ -57,7 +57,7 @@ impl Display for GlobalName { pub trait GlobalBind { fn bind<'a>( self: Rc, - client: &'a Rc, + client: &'a Rc, id: ObjectId, version: u32, ) -> Pin> + 'a>>; @@ -121,7 +121,7 @@ impl Globals { pub async fn notify_all( &self, - client: &WlClientData, + client: &Client, registry: &Rc, ) -> Result<(), GlobalError> { let globals = self.registry.lock(); @@ -136,7 +136,7 @@ impl Globals { async fn broadcast) -> 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); diff --git a/src/ifs/wl_callback/mod.rs b/src/ifs/wl_callback/mod.rs index 190e3081..e9e5a7b5 100644 --- a/src/ifs/wl_callback/mod.rs +++ b/src/ifs/wl_callback/mod.rs @@ -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!(); } } diff --git a/src/ifs/wl_callback/types.rs b/src/ifs/wl_callback/types.rs index d8dc99a1..95132169 100644 --- a/src/ifs/wl_callback/types.rs +++ b/src/ifs/wl_callback/types.rs @@ -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; diff --git a/src/ifs/wl_compositor/mod.rs b/src/ifs/wl_compositor/mod.rs index 29a150e2..3cf16ca9 100644 --- a/src/ifs/wl_compositor/mod.rs +++ b/src/ifs/wl_compositor/mod.rs @@ -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, id: ObjectId, - client: Rc, + client: Rc, version: u32, } @@ -31,7 +31,7 @@ impl WlCompositorGlobal { async fn bind_( self: Rc, id: ObjectId, - client: &Rc, + client: &Rc, 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(®ion)?; Ok(()) } diff --git a/src/ifs/wl_compositor/types.rs b/src/ifs/wl_compositor/types.rs index 4ce32cfd..57ff263c 100644 --- a/src/ifs/wl_compositor/types.rs +++ b/src/ifs/wl_compositor/types.rs @@ -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), - #[error(transparent)] - ClientError(Box), + ClientError(Box), #[error("Could not process `create_surface` request")] CreateSurfaceError(#[source] Box), #[error("Could not process `create_region` request")] CreateRegionError(#[source] Box), } -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), #[error(transparent)] - ClientError(Box), + ClientError(Box), } efrom!(CreateSurfaceError, ParseFailed, WlParserError); -efrom!(CreateSurfaceError, ClientError, WlClientError); +efrom!(CreateSurfaceError, ClientError, ClientError); #[derive(Debug, Error)] pub enum CreateRegionError { #[error("Parsing failed")] ParseFailed(#[source] Box), #[error(transparent)] - ClientError(Box), + ClientError(Box), } efrom!(CreateRegionError, ParseFailed, WlParserError); -efrom!(CreateRegionError, ClientError, WlClientError); +efrom!(CreateRegionError, ClientError, ClientError); pub(super) struct CreateSurface { pub id: ObjectId, diff --git a/src/ifs/wl_display/mod.rs b/src/ifs/wl_display/mod.rs index e26f9456..12ed592f 100644 --- a/src/ifs/wl_display/mod.rs +++ b/src/ifs/wl_display/mod.rs @@ -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, + client: Rc, } impl WlDisplay { - pub fn new(client: &Rc) -> Self { + pub fn new(client: &Rc) -> 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(®istry)?; self.client .state .globals @@ -124,7 +121,7 @@ impl Object for WlDisplay { GET_REGISTRY + 1 } - fn into_display(self: Rc) -> Result, ObjectError> { + fn into_display(self: Rc) -> Result, ClientError> { Ok(self) } } diff --git a/src/ifs/wl_display/types.rs b/src/ifs/wl_display/types.rs index 4216ceaa..c7fb4335 100644 --- a/src/ifs/wl_display/types.rs +++ b/src/ifs/wl_display/types.rs @@ -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), - #[error("An object error occurred")] - ObjectError(#[source] Box), - #[error("An object error occurred")] - ClientError(#[source] Box), + #[error(transparent)] + ClientError(Box), #[error("An error occurred while processing globals")] GlobalError(#[source] Box), } 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), - #[error("An object error occurred")] - ObjectError(#[source] Box), - #[error("A client error occurred")] - ClientError(#[source] Box), + #[error(transparent)] + ClientError(Box), } efrom!(SyncError, ParseFailed, WlParserError); -efrom!(SyncError, ObjectError, ObjectError); -efrom!(SyncError, ClientError, WlClientError); +efrom!(SyncError, ClientError, ClientError); pub(super) struct GetRegistry { pub registry: ObjectId, diff --git a/src/ifs/wl_region/mod.rs b/src/ifs/wl_region/mod.rs index fb62f5b2..2a2c21ee 100644 --- a/src/ifs/wl_region/mod.rs +++ b/src/ifs/wl_region/mod.rs @@ -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, + client: Rc, rect: RefCell, } impl WlRegion { - pub fn new(id: ObjectId, client: &Rc) -> Self { + pub fn new(id: ObjectId, client: &Rc) -> 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.client.objects.regions.set(self.id, self.clone()); - } - - fn pre_release(&self) -> Result<(), ObjectError> { - self.client.objects.regions.remove(&self.id); - Ok(()) - } } diff --git a/src/ifs/wl_region/types.rs b/src/ifs/wl_region/types.rs index 0efb18dc..90f7053c 100644 --- a/src/ifs/wl_region/types.rs +++ b/src/ifs/wl_region/types.rs @@ -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), #[error(transparent)] - ObjectError(Box), + ClientError(Box), } efrom!(DestroyError, ParseFailed, WlParserError); -efrom!(DestroyError, ObjectError, ObjectError); +efrom!(DestroyError, ClientError, ClientError); #[derive(Debug, Error)] pub enum AddError { diff --git a/src/ifs/wl_registry/mod.rs b/src/ifs/wl_registry/mod.rs index 113c3baf..e4ca5e0b 100644 --- a/src/ifs/wl_registry/mod.rs +++ b/src/ifs/wl_registry/mod.rs @@ -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, + client: Rc, } impl WlRegistry { - pub fn new(id: ObjectId, client: &Rc) -> Self { + pub fn new(id: ObjectId, client: &Rc) -> Self { Self { id, client: client.clone(), diff --git a/src/ifs/wl_registry/types.rs b/src/ifs/wl_registry/types.rs index 6ef1f55a..1d8c6e6e 100644 --- a/src/ifs/wl_registry/types.rs +++ b/src/ifs/wl_registry/types.rs @@ -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; diff --git a/src/ifs/wl_shm/mod.rs b/src/ifs/wl_shm/mod.rs index 59bc321f..72e54789 100644 --- a/src/ifs/wl_shm/mod.rs +++ b/src/ifs/wl_shm/mod.rs @@ -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, id: ObjectId, - client: Rc, + client: Rc, } impl WlShmGlobal { @@ -30,7 +30,7 @@ impl WlShmGlobal { async fn bind_( self: Rc, id: ObjectId, - client: &Rc, + client: &Rc, _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(()) } diff --git a/src/ifs/wl_shm/types.rs b/src/ifs/wl_shm/types.rs index 2d101438..9f1b082b 100644 --- a/src/ifs/wl_shm/types.rs +++ b/src/ifs/wl_shm/types.rs @@ -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), - #[error(transparent)] - ClientError(Box), + ClientError(Box), #[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), #[error(transparent)] - ClientError(Box), + ClientError(Box), } efrom!(CreatePoolError, ParseError, WlParserError); efrom!(CreatePoolError, WlShmPoolError, WlShmPoolError); -efrom!(CreatePoolError, ClientError, WlClientError); +efrom!(CreatePoolError, ClientError, ClientError); pub(super) struct CreatePool { pub id: ObjectId, diff --git a/src/ifs/wl_shm_pool/mod.rs b/src/ifs/wl_shm_pool/mod.rs index cbd0875d..415fdb69 100644 --- a/src/ifs/wl_shm_pool/mod.rs +++ b/src/ifs/wl_shm_pool/mod.rs @@ -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, + client: Rc, fd: OwnedFd, mem: RefCell>, } @@ -23,7 +23,7 @@ pub struct WlShmPool { impl WlShmPool { pub fn new( id: ObjectId, - client: &Rc, + client: &Rc, fd: OwnedFd, len: usize, ) -> Result { @@ -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(()) } diff --git a/src/ifs/wl_shm_pool/types.rs b/src/ifs/wl_shm_pool/types.rs index 2726958d..3d26830d 100644 --- a/src/ifs/wl_shm_pool/types.rs +++ b/src/ifs/wl_shm_pool/types.rs @@ -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), - #[error(transparent)] - ClientError(Box), + ClientError(Box), #[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), } -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), #[error(transparent)] - ObjectError(Box), + ClientError(Box), } efrom!(CreateBufferError, ParseError, WlParserError); -efrom!(CreateBufferError, ObjectError, ObjectError); +efrom!(CreateBufferError, ClientError, ClientError); #[derive(Debug, Error)] pub enum DestroyError { #[error("Parsing failed")] ParseError(#[source] Box), #[error(transparent)] - ObjectError(Box), + ClientError(Box), } efrom!(DestroyError, ParseError, WlParserError); -efrom!(DestroyError, ObjectError, ObjectError); +efrom!(DestroyError, ClientError, ClientError); #[derive(Debug, Error)] pub enum ResizeError { diff --git a/src/ifs/wl_subcompositor/mod.rs b/src/ifs/wl_subcompositor/mod.rs index 960cc4e4..d39a514d 100644 --- a/src/ifs/wl_subcompositor/mod.rs +++ b/src/ifs/wl_subcompositor/mod.rs @@ -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, 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!(); } } diff --git a/src/ifs/wl_subcompositor/types.rs b/src/ifs/wl_subcompositor/types.rs index 90b4c17e..82b9511d 100644 --- a/src/ifs/wl_subcompositor/types.rs +++ b/src/ifs/wl_subcompositor/types.rs @@ -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), - #[error(transparent)] - ClientError(Box), + ClientError(Box), } -efrom!(WlSubcompositorError, ObjectError, ObjectError); -efrom!(WlSubcompositorError, ClientError, WlClientError); +efrom!(WlSubcompositorError, ClientError, ClientError); diff --git a/src/ifs/wl_surface/mod.rs b/src/ifs/wl_surface/mod.rs index d461e7d3..aa90ad38 100644 --- a/src/ifs/wl_surface/mod.rs +++ b/src/ifs/wl_surface/mod.rs @@ -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, + client: Rc, pending: PendingState, } @@ -39,7 +39,7 @@ struct PendingState { } impl WlSurface { - pub fn new(id: ObjectId, client: &Rc) -> Self { + pub fn new(id: ObjectId, client: &Rc) -> 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.client.objects.surfaces.set(self.id, self.clone()); - } } diff --git a/src/ifs/wl_surface/types.rs b/src/ifs/wl_surface/types.rs index 10fb50bb..019e3a92 100644 --- a/src/ifs/wl_surface/types.rs +++ b/src/ifs/wl_surface/types.rs @@ -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), #[error(transparent)] - ClientError(Box), + ClientError(Box), } efrom!(SetOpaqueRegionError, ParseFailed, WlParserError); -efrom!(SetOpaqueRegionError, ClientError, WlClientError); +efrom!(SetOpaqueRegionError, ClientError, ClientError); #[derive(Debug, Error)] pub enum SetInputRegionError { #[error("Parsing failed")] ParseFailed(#[source] Box), #[error(transparent)] - ClientError(Box), + ClientError(Box), } efrom!(SetInputRegionError, ParseFailed, WlParserError); -efrom!(SetInputRegionError, ClientError, WlClientError); +efrom!(SetInputRegionError, ClientError, ClientError); #[derive(Debug, Error)] pub enum CommitError { diff --git a/src/ifs/xdg_wm_base/mod.rs b/src/ifs/xdg_wm_base/mod.rs index 64db8476..3a07b430 100644 --- a/src/ifs/xdg_wm_base/mod.rs +++ b/src/ifs/xdg_wm_base/mod.rs @@ -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, 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!(); } } diff --git a/src/ifs/xdg_wm_base/types.rs b/src/ifs/xdg_wm_base/types.rs index 864a5a3f..b373714b 100644 --- a/src/ifs/xdg_wm_base/types.rs +++ b/src/ifs/xdg_wm_base/types.rs @@ -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), - #[error(transparent)] - ClientError(Box), + ClientError(Box), } -efrom!(XdgWmBaseError, ObjectError, ObjectError); -efrom!(XdgWmBaseError, ClientError, WlClientError); +efrom!(XdgWmBaseError, ClientError, ClientError); diff --git a/src/macros.rs b/src/macros.rs index 807441c9..1515bb02 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -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> + 'a>, + Box> + '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, - client: &'a std::rc::Rc, - id: crate::objects::ObjectId, + client: &'a std::rc::Rc, + id: crate::object::ObjectId, version: u32, ) -> std::pin::Pin< Box> + 'a>, diff --git a/src/main.rs b/src/main.rs index e08193a9..f67d37ab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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, }); diff --git a/src/object.rs b/src/object.rs new file mode 100644 index 00000000..91cd97f4 --- /dev/null +++ b/src/object.rs @@ -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> + 'a>>; +} + +pub trait Object: ObjectHandleRequest + 'static { + fn id(&self) -> ObjectId; + fn interface(&self) -> Interface; + fn num_requests(&self) -> u32; + fn into_display(self: Rc) -> Result, 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", + } + } +} diff --git a/src/objects.rs b/src/objects.rs deleted file mode 100644 index 0d35b7d1..00000000 --- a/src/objects.rs +++ /dev/null @@ -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), - #[error("Cannot parse the message")] - ParserError(#[source] Box), - #[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), - #[error("An error occurred in a `wl_registry`")] - WlRegistryError(#[source] Box), - #[error("Could not add object {0} to the client")] - AddObjectError(ObjectId, #[source] Box), - #[error("An error occurred in a `wl_surface`")] - WlSurfaceError(#[source] Box), - #[error("An error occurred in a `wl_compositor`")] - WlCompositorError(#[source] Box), - #[error("An error occurred in a `wl_shm`")] - WlShmError(#[source] Box), - #[error("An error occurred in a `wl_shm_pool`")] - WlShmPoolError(#[source] Box), - #[error("An error occurred in a `wl_region`")] - WlRegionError(#[source] Box), - #[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> + '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) {} - fn into_display(self: Rc) -> Result, 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>, - registries: CopyHashMap>, - pub surfaces: CopyHashMap>, - pub regions: CopyHashMap>, - ids: RefCell>, -} - -const MIN_SERVER_ID: u32 = 0xff000000; -const SEG_SIZE: usize = 8 * mem::size_of::(); - -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 { - 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, ObjectError> { - match self.registry.get(&id) { - Some(o) => Ok(o), - _ => Err(ObjectError::UnknownId), - } - } - - pub fn add_client_object(&self, obj: Rc) -> 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>> { - 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 - } -} diff --git a/src/pixman/mod.rs b/src/pixman.rs similarity index 98% rename from src/pixman/mod.rs rename to src/pixman.rs index fc4f674a..e3ee26fc 100644 --- a/src/pixman/mod.rs +++ b/src/pixman.rs @@ -1,4 +1,3 @@ -use std::ops::{Add, Sub}; use std::ptr; use uapi::c; diff --git a/src/state.rs b/src/state.rs index c0832fc9..1bf59bad 100644 --- a/src/state.rs +++ b/src/state.rs @@ -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, pub el: EventLoopRef, - pub clients: WlClients, + pub clients: Clients, pub next_name: NumCell, pub globals: Globals, } diff --git a/src/utils/buffd/wl_formatter.rs b/src/utils/buffd/wl_formatter.rs index b51eb59a..1e3299aa 100644 --- a/src/utils/buffd/wl_formatter.rs +++ b/src/utils/buffd/wl_formatter.rs @@ -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; diff --git a/src/utils/buffd/wl_parser.rs b/src/utils/buffd/wl_parser.rs index 043c92ad..d74abb92 100644 --- a/src/utils/buffd/wl_parser.rs +++ b/src/utils/buffd/wl_parser.rs @@ -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; diff --git a/src/wl_client.rs b/src/wl_client.rs deleted file mode 100644 index 1799e1ff..00000000 --- a/src/wl_client.rs +++ /dev/null @@ -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), - #[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), - #[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, - clients: CopyHashMap>, - shutdown_clients: CopyHashMap>, -} - -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, WlClientError> { - match self.clients.get(&id) { - Some(c) => Ok(c.data.clone()), - _ => Err(WlClientError::ClientDoesNotExist(id)), - } - } - - pub fn spawn( - &self, - id: ClientId, - global: &Rc, - 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(&self, mut f: B) - where - B: FnMut(&Rc), - { - let clients = self.clients.lock(); - for client in clients.values() { - f(&client.data); - } - } -} - -struct WlClient { - data: Rc, - _handler: SpawnedFuture<()>, -} - -impl Drop for WlClient { - fn drop(&mut self) { - self.data.objects.destroy(); - } -} - -pub trait EventFormatter: Debug { - fn format(self: Box, fmt: &mut WlFormatter<'_>); - fn obj(&self) -> &dyn Object; -} - -pub type DynEventFormatter = Box; - -pub trait RequestParser<'a>: Debug + Sized { - fn parse(parser: &mut WlParser<'_, 'a>) -> Result; -} - -enum WlEvent { - Flush, - Shutdown, - Event(Box), -} - -pub struct WlClientData { - pub id: ClientId, - pub state: Rc, - socket: AsyncFd, - pub objects: Objects, - events: AsyncQueue, - shutdown: Cell>>, - shutdown_sent: Cell, -} - -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, 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 { - 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) { - self.events.push(WlEvent::Event(event)); - self.state.clients.shutdown(self.id); - } - - pub fn event_locked(&self, event: Box) -> bool { - self.events.push(WlEvent::Event(event)); - self.events.size() > MAX_PENDING_EVENTS - } - - pub async fn event(&self, event: Box) -> 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) -> Result<(), WlClientError> { - self.objects.add_client_object(obj.clone())?; - obj.post_attach(); - Ok(()) - } - - pub fn get_region(&self, id: ObjectId) -> Result, WlClientError> { - match self.objects.regions.get(&id) { - Some(r) => Ok(r), - _ => Err(WlClientError::RegionDoesNotExist(id)), - } - } -} - -async fn client(data: Rc, 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) { - let display = data.display().unwrap(); - let recv = async { - let mut buf = BufFdIn::new(data.socket.clone()); - let mut data_buf = Vec::::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) { - 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); -}