wayland-commons-0.29.5/.cargo_vcs_info.json0000644000000001550000000000100142420ustar { "git": { "sha1": "8f4127a21d65cf10189ff0e3b78983e9686dd288" }, "path_in_vcs": "wayland-commons" }wayland-commons-0.29.5/Cargo.lock0000644000000043520000000000100122200ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "libc" version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "memoffset" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg", ] [[package]] name = "nix" version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" dependencies = [ "bitflags", "cfg-if", "libc", "memoffset", ] [[package]] name = "once_cell" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" [[package]] name = "pkg-config" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] name = "smallvec" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "wayland-commons" version = "0.29.5" dependencies = [ "nix", "once_cell", "smallvec", "wayland-sys", ] [[package]] name = "wayland-sys" version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" dependencies = [ "pkg-config", ] wayland-commons-0.29.5/Cargo.toml0000644000000022000000000000100122310ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "wayland-commons" version = "0.29.5" authors = ["Victor Berger "] description = "Common types and structures used by wayland-client and wayland-server." documentation = "https://smithay.github.io/wayland-rs/wayland_commons/" readme = "README.md" keywords = ["wayland"] categories = [ "gui", "api-bindings", ] license = "MIT" repository = "https://github.com/smithay/wayland-rs" [dependencies.nix] version = "0.24.1" features = [ "fs", "socket", "uio", ] default-features = false [dependencies.once_cell] version = "1.1" [dependencies.smallvec] version = "1" [dependencies.wayland-sys] version = "0.29.5" wayland-commons-0.29.5/Cargo.toml.orig000064400000000000000000000012211046102023000157140ustar 00000000000000[package] name = "wayland-commons" version = "0.29.5" authors = ["Victor Berger "] repository = "https://github.com/smithay/wayland-rs" documentation = "https://smithay.github.io/wayland-rs/wayland_commons/" description = "Common types and structures used by wayland-client and wayland-server." license = "MIT" edition = "2018" categories = ["gui", "api-bindings"] keywords = ["wayland"] readme = "README.md" [dependencies] wayland-sys = { version = "0.29.5", path = "../wayland-sys" } once_cell = "1.1" smallvec = "1" [dependencies.nix] version = "0.24.1" default-features = false features = [ "fs", "socket", "uio", ] wayland-commons-0.29.5/LICENSE.txt000064400000000000000000000020401046102023000146500ustar 00000000000000Copyright (c) 2015 Victor Berger Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.wayland-commons-0.29.5/README.md000064400000000000000000000013331046102023000143100ustar 00000000000000[![crates.io](https://img.shields.io/crates/v/wayland-commons.svg)](https://crates.io/crates/wayland-commons) [![docs.rs](https://docs.rs/wayland-commons/badge.svg)](https://docs.rs/wayland-commons) [![Continuous Integration](https://github.com/Smithay/wayland-rs/workflows/Continuous%20Integration/badge.svg)](https://github.com/Smithay/wayland-rs/actions?query=workflow%3A%22Continuous+Integration%22) [![codecov](https://codecov.io/gh/Smithay/wayland-rs/branch/master/graph/badge.svg)](https://codecov.io/gh/Smithay/wayland-rs) # wayland-commons This crate regroups common routine and code used by `wayland-client` and `wayland-server`, as such, you should not need to use it directly, but instead use one of these two crates.wayland-commons-0.29.5/examples/manual_global_list.rs000064400000000000000000000026671046102023000210600ustar 00000000000000extern crate wayland_commons as wc; use std::env; use std::os::unix::io::{FromRawFd, IntoRawFd}; use std::os::unix::net::UnixStream; use std::path::PathBuf; use wc::smallvec; use wc::socket::{BufferedSocket, Socket}; use wc::wire::{Argument, ArgumentType, Message, MessageDesc}; fn main() { let xdg_dir = env::var_os("XDG_RUNTIME_DIR").unwrap(); let mut path: PathBuf = xdg_dir.into(); path.push("wayland-0"); let socket = UnixStream::connect(path).unwrap(); let mut socket = BufferedSocket::new(unsafe { Socket::from_raw_fd(socket.into_raw_fd()) }); socket .write_message(&Message { sender_id: 1, // wl_display opcode: 1, // get registry args: smallvec![ Argument::NewId(2), // id of the created registry ], }) .unwrap(); socket.flush().unwrap(); ::std::thread::sleep(::std::time::Duration::from_millis(500)); // sleep 0.5 seconds let ret = socket.read_messages( |id, opcode| match (id, opcode) { (2, 0) => Some(&GLOBAL_EVENT.signature), _ => None, }, |msg| { println!("{:?}", msg); true }, ); println!("{:?}", ret); } /* * The registry interface */ const GLOBAL_EVENT: MessageDesc = MessageDesc { name: "global", signature: &[ArgumentType::Uint, ArgumentType::Str, ArgumentType::Uint], since: 1, destructor: false, }; wayland-commons-0.29.5/src/debug.rs000064400000000000000000000033311046102023000152540ustar 00000000000000//! Debugging helpers to handle `WAYLAND_DEBUG` env variable. use std::time::{SystemTime, UNIX_EPOCH}; use crate::wire::Argument; /// Print the dispatched message to stderr in a following format: /// /// [timestamp] <- interface@id.msg_name(args) pub fn print_dispatched_message(interface: &str, id: u32, msg_name: &str, args: &[Argument]) { // Add timestamp to output. print_timestamp(); eprint!(" <- {}@{}.{}", interface, id, msg_name); print_args(args); // Add a new line. eprintln!(); } /// Print the send message to stderr in a following format: /// /// [timestamp] -> interface@id.msg_name(args) /// /// If `is_alive` is `false` the `[ZOMBIE]` is added after `id`. pub fn print_send_message( interface: &str, id: u32, is_alive: bool, msg_name: &str, args: &[Argument], ) { // Add timestamp to output. print_timestamp(); eprint!(" -> {}@{}{}.{}", interface, id, if is_alive { "" } else { "[ZOMBIE]" }, msg_name); print_args(args); // Add a new line. eprintln!(); } /// Print arguments with opening/closing bracket. fn print_args(args: &[Argument]) { let num_args = args.len(); eprint!("("); if num_args > 0 { // Explicitly handle first argument to handle one arg functions nicely. eprint!("{}", args[0]); // Handle the rest. for arg in args.iter().take(num_args).skip(1) { eprint!(", {}", arg); } } eprint!(")") } /// Print timestamp in seconds.microseconds format. fn print_timestamp() { if let Ok(timestamp) = SystemTime::now().duration_since(UNIX_EPOCH) { let sc = timestamp.as_secs(); let ms = timestamp.subsec_micros(); eprint!("[{}.{:06}]", sc, ms); } } wayland-commons-0.29.5/src/filter.rs000064400000000000000000000071771046102023000154670ustar 00000000000000//! Filter use std::{cell::RefCell, collections::VecDeque, rc::Rc}; /// Holder of global dispatch-related data /// /// This struct serves as a dynamic container for the dispatch-time /// global data that you gave to the dispatch method, and is given as /// input to all your callbacks. It allows you to share global state /// between your filters. /// /// The main method of interest is the `get` method, which allows you to /// access a `&mut _` reference to the global data itself. The other methods /// are mostly used internally by the crate. pub struct DispatchData<'a> { data: &'a mut dyn std::any::Any, } impl<'a> std::fmt::Debug for DispatchData<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("DispatchData { ... }") } } impl<'a> DispatchData<'a> { /// Access the dispatch data knowing its type /// /// Will return `None` if the provided type is not the correct /// inner type. pub fn get(&mut self) -> Option<&mut T> { self.data.downcast_mut() } /// Wrap a mutable reference /// /// This creates a new `DispatchData` from a mutable reference pub fn wrap(data: &'a mut T) -> DispatchData<'a> { DispatchData { data } } /// Reborrows this `DispatchData` to create a new one with the same content /// /// This is a quick and cheap way to propagate the `DispatchData` down a /// callback stack by value. It is basically a noop only there to ease /// work with the borrow checker. pub fn reborrow(&mut self) -> DispatchData { DispatchData { data: &mut *self.data } } } struct Inner { pending: RefCell>, cb: RefCell, } type DynInner = Inner, DispatchData<'_>)>; /// An event filter /// /// Can be used in wayland-client and wayland-server to aggregate /// messages from different objects into the same closure. /// /// You need to provide it a closure of type `FnMut(E, &Filter)`, /// which will be called any time a message is sent to the filter /// via the `send(..)` method. Your closure also receives a handle /// to the filter as argument, so that you can use it from within /// the callback (to assign new wayland objects to this filter for /// example). /// /// The `Filter` can be cloned, and all clones send messages to the /// same closure. However it is not threadsafe. pub struct Filter { inner: Rc>, } impl std::fmt::Debug for Filter { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Filter").field("pending", &self.inner.pending).finish() } } impl Clone for Filter { fn clone(&self) -> Filter { Filter { inner: self.inner.clone() } } } impl Filter { /// Create a new filter from given closure pub fn new, DispatchData<'_>) + 'static>(f: F) -> Filter { Filter { inner: Rc::new(Inner { pending: RefCell::new(VecDeque::new()), cb: RefCell::new(f) }), } } /// Send a message to this filter pub fn send(&self, evt: E, mut data: DispatchData) { // gracefully handle reentrancy if let Ok(mut guard) = self.inner.cb.try_borrow_mut() { (&mut *guard)(evt, self, data.reborrow()); // process all events that might have been enqueued by the cb while let Some(evt) = self.inner.pending.borrow_mut().pop_front() { (&mut *guard)(evt, self, data.reborrow()); } } else { self.inner.pending.borrow_mut().push_back(evt); } } } wayland-commons-0.29.5/src/lib.rs000064400000000000000000000170071046102023000147410ustar 00000000000000//! Common definitions for wayland //! //! This crate hosts common type and traits used to represent wayland messages //! and routines in the `wayland-client` and `wayland-server` crates. //! //! This notably includes the `Interface` trait, which can exhaustively describe //! any wayland interface. Its implementations are intended to be generated by the //! `wayland-scanner` crate. //! //! The principal user-facing definition provided by this crate is the `Implementation` //! trait, which as a user of `wayland-client` or `wayland-server` you will be using //! to define objects able to handle the messages your program receives. Note that //! this trait is auto-implemented for closures with appropriate signature, for //! convenience. #![warn(missing_docs, missing_debug_implementations)] #[macro_use] extern crate nix; use std::os::raw::c_void; use wayland_sys::common as syscom; pub mod debug; pub mod filter; pub mod map; pub mod socket; pub mod user_data; pub mod wire; pub use smallvec::smallvec; /// A group of messages /// /// This represents a group of message that can be serialized on the protocol wire. /// Typically the set of events or requests of a single interface. /// /// Implementations of this trait are supposed to be /// generated using the `wayland-scanner` crate. pub trait MessageGroup: Sized { /// Wire representation of this MessageGroup const MESSAGES: &'static [wire::MessageDesc]; /// The wrapper type for ObjectMap allowing the mapping of Object and /// NewId arguments to the object map during parsing. type Map; /// The opcode of this message fn opcode(&self) -> u16; /// Whether this message is a destructor /// /// If it is, once send or receive the associated object cannot be used any more. fn is_destructor(&self) -> bool; /// The minimal object version for which this message exists fn since(&self) -> u32; /// Retrieve the child `Object` associated with this message if any fn child( opcode: u16, version: u32, meta: &Meta, ) -> Option>; /// Construct a message from its raw representation // -- The lint is allowed because fixing it would be a breaking change -- #[allow(clippy::result_unit_err)] fn from_raw(msg: wire::Message, map: &mut Self::Map) -> Result; /// Turn this message into its raw representation fn into_raw(self, send_id: u32) -> wire::Message; /// Construct a message of this group from its C representation /// /// # Safety /// /// The pointers provided to this function must all be valid pointers from /// `libwayland-client` // -- The lint is allowed because fixing it would be a breaking change -- #[allow(clippy::result_unit_err)] unsafe fn from_raw_c( obj: *mut c_void, opcode: u32, args: *const syscom::wl_argument, ) -> Result; /// Build a C representation of this message /// /// It can only be accessed from the provided closure, and this consumes /// the message. // -- The lint is allowed because fixing it would be a breaking change -- #[allow(clippy::wrong_self_convention)] fn as_raw_c_in(self, f: F) -> T where F: FnOnce(u32, &mut [syscom::wl_argument]) -> T; } /// The description of a wayland interface /// /// Implementations of this trait are supposed to be /// generated using the `wayland-scanner` crate. pub trait Interface: 'static { /// Set of requests associated to this interface /// /// Requests are messages from the client to the server type Request: MessageGroup + 'static; /// Set of events associated to this interface /// /// Events are messages from the server to the client type Event: MessageGroup + 'static; /// Name of this interface const NAME: &'static str; /// Maximum supported version of this interface /// /// This is the maximum version supported by the protocol specification currently /// used by this library, and should not be used as-is in your code, as a version /// change can subtly change the behavior of some objects. /// /// Server are supposed to be able to handle all versions from 1 to the one they /// advertise through the registry, and clients can choose any version among the /// ones the server supports. const VERSION: u32; /// Pointer to the C representation of this interface fn c_interface() -> *const syscom::wl_interface; } /// An empty enum representing a MessageGroup with no messages #[derive(Debug)] pub enum NoMessage {} #[cfg(not(tarpaulin_include))] impl MessageGroup for NoMessage { const MESSAGES: &'static [wire::MessageDesc] = &[]; type Map = (); fn is_destructor(&self) -> bool { match *self {} } fn opcode(&self) -> u16 { match *self {} } fn since(&self) -> u32 { match *self {} } fn child(_: u16, _: u32, _: &M) -> Option> { None } fn from_raw(_: wire::Message, _: &mut ()) -> Result { Err(()) } fn into_raw(self, _: u32) -> wire::Message { match self {} } unsafe fn from_raw_c( _obj: *mut c_void, _opcode: u32, _args: *const syscom::wl_argument, ) -> Result { Err(()) } fn as_raw_c_in(self, _f: F) -> T where F: FnOnce(u32, &mut [syscom::wl_argument]) -> T, { match self {} } } /// Stores a value in a threadafe container that /// only lets you access it from its owning thread /// /// If the ThreadGuard is dropped from the wrong thread, /// the underlying value will be leaked. #[derive(Debug)] pub struct ThreadGuard { thread: std::thread::ThreadId, val: std::mem::ManuallyDrop, } impl ThreadGuard { /// Create a new ThreadGuard wrapper pub fn new(val: T) -> ThreadGuard { ThreadGuard { val: std::mem::ManuallyDrop::new(val), thread: std::thread::current().id() } } } impl ThreadGuard { /// Access the underlying value /// /// Panics if done on the wrong thread pub fn get(&self) -> &T { self.try_get().expect("Attempted to access a ThreadGuard contents from the wrong thread.") } /// Mutably access the underlying value /// /// Panics if done on the wrong thread pub fn get_mut(&mut self) -> &mut T { self.try_get_mut() .expect("Attempted to access a ThreadGuard contents from the wrong thread.") } /// Try to access the underlying value /// /// Returns `None` if done on the wrong thread pub fn try_get(&self) -> Option<&T> { if self.thread == ::std::thread::current().id() { Some(&self.val) } else { None } } /// Try to mutably access the underlying value /// /// Returns `None` if done on the wrong thread pub fn try_get_mut(&mut self) -> Option<&mut T> { if self.thread == ::std::thread::current().id() { Some(&mut self.val) } else { None } } } impl Drop for ThreadGuard { fn drop(&mut self) { // We can only actually perform the drop if we are on the right thread // otherwise it may be racy, so we just leak the value if self.thread == ::std::thread::current().id() { unsafe { std::mem::ManuallyDrop::drop(&mut self.val) } } } } unsafe impl Send for ThreadGuard {} unsafe impl Sync for ThreadGuard {} wayland-commons-0.29.5/src/map.rs000064400000000000000000000206231046102023000147460ustar 00000000000000//! Wayland objects map use crate::{Interface, MessageGroup, NoMessage}; use std::cmp::Ordering; /// Limit separating server-created from client-created objects IDs in the namespace pub const SERVER_ID_LIMIT: u32 = 0xFF00_0000; /// A trait representing the metadata a wayland implementation /// may attach to an object. pub trait ObjectMetadata: Clone { /// Create the metadata for a child object /// /// Mostly needed for client side, to propagate the event queues fn child(&self) -> Self; } impl ObjectMetadata for () { fn child(&self) {} } /// The representation of a protocol object #[derive(Clone)] pub struct Object { /// Interface name of this object pub interface: &'static str, /// Version of this object pub version: u32, /// Description of the requests of this object pub requests: &'static [crate::wire::MessageDesc], /// Description of the events of this object pub events: &'static [crate::wire::MessageDesc], /// Metadata associated to this object (ex: its event queue client side) pub meta: Meta, /// A function which, from an opcode, a version, and the Meta, creates a child /// object associated with this event if any pub childs_from_events: fn(u16, u32, &Meta) -> Option>, /// A function which, from an opcode, a version, and the Meta, creates a child /// object associated with this request if any pub childs_from_requests: fn(u16, u32, &Meta) -> Option>, } impl std::fmt::Debug for Object { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Object") .field("interface", &self.interface) .field("version", &self.version) .field("requests", &self.requests) .field("events", &self.events) .field("meta", &self.meta) .finish() } } impl Object { /// Create an Object corresponding to given interface and version pub fn from_interface(version: u32, meta: Meta) -> Object { Object { interface: I::NAME, version, requests: I::Request::MESSAGES, events: I::Event::MESSAGES, meta, childs_from_events: childs_from::, childs_from_requests: childs_from::, } } /// Create an optional `Object` corresponding to the possible `new_id` associated /// with given event opcode pub fn event_child(&self, opcode: u16) -> Option> { (self.childs_from_events)(opcode, self.version, &self.meta) } /// Create an optional `Object` corresponding to the possible `new_id` associated /// with given request opcode pub fn request_child(&self, opcode: u16) -> Option> { (self.childs_from_requests)(opcode, self.version, &self.meta) } /// Check whether this object is of given interface pub fn is_interface(&self) -> bool { // TODO: we might want to be more robust than that self.interface == I::NAME } /// Create a placeholder object that will be filled-in by the message logic pub fn placeholder(meta: Meta) -> Object { Object { interface: "", version: 0, requests: &[], events: &[], meta, childs_from_events: childs_from::, childs_from_requests: childs_from::, } } } fn childs_from( opcode: u16, version: u32, meta: &Meta, ) -> Option> { M::child(opcode, version, meta) } /// A holder for the object store of a connection /// /// Keeps track of which object id is associated to which /// interface object, and which is currently unused. #[derive(Default, Debug)] pub struct ObjectMap { client_objects: Vec>>, server_objects: Vec>>, } impl ObjectMap { /// Create a new empty object map pub fn new() -> ObjectMap { ObjectMap { client_objects: Vec::new(), server_objects: Vec::new() } } /// Find an object in the store pub fn find(&self, id: u32) -> Option> { if id == 0 { None } else if id >= SERVER_ID_LIMIT { self.server_objects.get((id - SERVER_ID_LIMIT) as usize).and_then(Clone::clone) } else { self.client_objects.get((id - 1) as usize).and_then(Clone::clone) } } /// Remove an object from the store /// /// Does nothing if the object didn't previously exists pub fn remove(&mut self, id: u32) { if id == 0 { // nothing } else if id >= SERVER_ID_LIMIT { if let Some(place) = self.server_objects.get_mut((id - SERVER_ID_LIMIT) as usize) { *place = None; } } else if let Some(place) = self.client_objects.get_mut((id - 1) as usize) { *place = None; } } /// Insert given object for given id /// /// Can fail if the requested id is not the next free id of this store. /// (In which case this is a protocol error) // -- The lint is allowed because fixing it would be a breaking change -- #[allow(clippy::result_unit_err)] pub fn insert_at(&mut self, id: u32, object: Object) -> Result<(), ()> { if id == 0 { Err(()) } else if id >= SERVER_ID_LIMIT { insert_in_at(&mut self.server_objects, (id - SERVER_ID_LIMIT) as usize, object) } else { insert_in_at(&mut self.client_objects, (id - 1) as usize, object) } } /// Allocate a new id for an object in the client namespace pub fn client_insert_new(&mut self, object: Object) -> u32 { insert_in(&mut self.client_objects, object) + 1 } /// Allocate a new id for an object in the server namespace pub fn server_insert_new(&mut self, object: Object) -> u32 { insert_in(&mut self.server_objects, object) + SERVER_ID_LIMIT } /// Mutably access an object of the map // -- The lint is allowed because fixing it would be a breaking change -- #[allow(clippy::result_unit_err)] pub fn with) -> T>(&mut self, id: u32, f: F) -> Result { if id == 0 { Err(()) } else if id >= SERVER_ID_LIMIT { if let Some(&mut Some(ref mut obj)) = self.server_objects.get_mut((id - SERVER_ID_LIMIT) as usize) { Ok(f(obj)) } else { Err(()) } } else if let Some(&mut Some(ref mut obj)) = self.client_objects.get_mut((id - 1) as usize) { Ok(f(obj)) } else { Err(()) } } /// Mutably access all objects of the map in sequence pub fn with_all)>(&mut self, mut f: F) { for (id, place) in self.client_objects.iter_mut().enumerate() { if let Some(ref mut obj) = *place { f(id as u32 + 1, obj); } } for (id, place) in self.server_objects.iter_mut().enumerate() { if let Some(ref mut obj) = *place { f(id as u32 + SERVER_ID_LIMIT, obj); } } } } // insert a new object in a store at the first free place fn insert_in( store: &mut Vec>>, object: Object, ) -> u32 { match store.iter().position(Option::is_none) { Some(id) => { store[id] = Some(object); id as u32 } None => { store.push(Some(object)); (store.len() - 1) as u32 } } } // insert an object at a given place in a store fn insert_in_at( store: &mut Vec>>, id: usize, object: Object, ) -> Result<(), ()> { match id.cmp(&store.len()) { Ordering::Greater => Err(()), Ordering::Equal => { store.push(Some(object)); Ok(()) } Ordering::Less => { let previous = &mut store[id]; if !previous.is_none() { return Err(()); } *previous = Some(object); Ok(()) } } } wayland-commons-0.29.5/src/socket.rs000064400000000000000000000537441046102023000154730ustar 00000000000000//! Wayland socket manipulation use std::io::{IoSlice, IoSliceMut}; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use nix::{sys::socket, Result as NixResult}; use crate::wire::{ArgumentType, Message, MessageParseError, MessageWriteError}; /// Maximum number of FD that can be sent in a single socket message pub const MAX_FDS_OUT: usize = 28; /// Maximum number of bytes that can be sent in a single socket message pub const MAX_BYTES_OUT: usize = 4096; /* * Socket */ /// A wayland socket #[derive(Debug)] pub struct Socket { fd: RawFd, } impl Socket { /// Send a single message to the socket /// /// A single socket message can contain several wayland messages /// /// The `fds` slice should not be longer than `MAX_FDS_OUT`, and the `bytes` /// slice should not be longer than `MAX_BYTES_OUT` otherwise the receiving /// end may lose some data. pub fn send_msg(&self, bytes: &[u8], fds: &[RawFd]) -> NixResult<()> { let flags = socket::MsgFlags::MSG_DONTWAIT | socket::MsgFlags::MSG_NOSIGNAL; let iov = [IoSlice::new(bytes)]; if !fds.is_empty() { let cmsgs = [socket::ControlMessage::ScmRights(fds)]; socket::sendmsg::<()>(self.fd, &iov, &cmsgs, flags, None)?; } else { socket::sendmsg::<()>(self.fd, &iov, &[], flags, None)?; }; Ok(()) } /// Receive a single message from the socket /// /// Return the number of bytes received and the number of Fds received. /// /// Errors with `WouldBlock` is no message is available. /// /// A single socket message can contain several wayland messages. /// /// The `buffer` slice should be at least `MAX_BYTES_OUT` long and the `fds` /// slice `MAX_FDS_OUT` long, otherwise some data of the received message may /// be lost. pub fn rcv_msg(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> NixResult<(usize, usize)> { let mut cmsg = cmsg_space!([RawFd; MAX_FDS_OUT]); let mut iov = [IoSliceMut::new(buffer)]; let msg = socket::recvmsg::<()>( self.fd, &mut iov[..], Some(&mut cmsg), socket::MsgFlags::MSG_DONTWAIT | socket::MsgFlags::MSG_CMSG_CLOEXEC | socket::MsgFlags::MSG_NOSIGNAL, )?; let mut fd_count = 0; let received_fds = msg.cmsgs().flat_map(|cmsg| match cmsg { socket::ControlMessageOwned::ScmRights(s) => s, _ => Vec::new(), }); for (fd, place) in received_fds.zip(fds.iter_mut()) { fd_count += 1; *place = fd; } Ok((msg.bytes, fd_count)) } /// Retrieve the current value of the requested [socket::GetSockOpt] pub fn opt(&self, opt: O) -> NixResult { socket::getsockopt(self.fd, opt) } } impl FromRawFd for Socket { unsafe fn from_raw_fd(fd: RawFd) -> Socket { Socket { fd } } } impl AsRawFd for Socket { fn as_raw_fd(&self) -> RawFd { self.fd } } impl IntoRawFd for Socket { fn into_raw_fd(self) -> RawFd { self.fd } } impl Drop for Socket { fn drop(&mut self) { let _ = ::nix::unistd::close(self.fd); } } /* * BufferedSocket */ /// An adapter around a raw Socket that directly handles buffering and /// conversion from/to wayland messages #[derive(Debug)] pub struct BufferedSocket { socket: Socket, in_data: Buffer, in_fds: Buffer, out_data: Buffer, out_fds: Buffer, } impl BufferedSocket { /// Wrap a Socket into a Buffered Socket pub fn new(socket: Socket) -> BufferedSocket { BufferedSocket { socket, in_data: Buffer::new(2 * MAX_BYTES_OUT / 4), // Incoming buffers are twice as big in order to be in_fds: Buffer::new(2 * MAX_FDS_OUT), // able to store leftover data if needed out_data: Buffer::new(MAX_BYTES_OUT / 4), out_fds: Buffer::new(MAX_FDS_OUT), } } /// Get direct access to the underlying socket pub fn get_socket(&mut self) -> &mut Socket { &mut self.socket } /// Retrieve ownership of the underlying Socket /// /// Any leftover content in the internal buffers will be lost pub fn into_socket(self) -> Socket { self.socket } /// Flush the contents of the outgoing buffer into the socket pub fn flush(&mut self) -> NixResult<()> { { let words = self.out_data.get_contents(); if words.is_empty() { return Ok(()); } let bytes = unsafe { ::std::slice::from_raw_parts(words.as_ptr() as *const u8, words.len() * 4) }; let fds = self.out_fds.get_contents(); self.socket.send_msg(bytes, fds)?; for &fd in fds { // once the fds are sent, we can close them let _ = ::nix::unistd::close(fd); } } self.out_data.clear(); self.out_fds.clear(); Ok(()) } // internal method // // attempts to write a message in the internal out buffers, // returns true if successful // // if false is returned, it means there is not enough space // in the buffer fn attempt_write_message(&mut self, msg: &Message) -> NixResult { match msg.write_to_buffers( self.out_data.get_writable_storage(), self.out_fds.get_writable_storage(), ) { Ok((bytes_out, fds_out)) => { self.out_data.advance(bytes_out); self.out_fds.advance(fds_out); Ok(true) } Err(MessageWriteError::BufferTooSmall) => Ok(false), Err(MessageWriteError::DupFdFailed(e)) => Err(e), } } /// Write a message to the outgoing buffer /// /// This method may flush the internal buffer if necessary (if it is full). /// /// If the message is too big to fit in the buffer, the error `Error::Sys(E2BIG)` /// will be returned. pub fn write_message(&mut self, msg: &Message) -> NixResult<()> { if !self.attempt_write_message(msg)? { // the attempt failed, there is not enough space in the buffer // we need to flush it self.flush()?; if !self.attempt_write_message(msg)? { // If this fails again, this means the message is too big // to be transmitted at all return Err(::nix::Error::E2BIG); } } Ok(()) } /// Try to fill the incoming buffers of this socket, to prepare /// a new round of parsing. pub fn fill_incoming_buffers(&mut self) -> NixResult<()> { // clear the buffers if they have no content if !self.in_data.has_content() { self.in_data.clear(); } if !self.in_fds.has_content() { self.in_fds.clear(); } // receive a message let (in_bytes, in_fds) = { let words = self.in_data.get_writable_storage(); let bytes = unsafe { ::std::slice::from_raw_parts_mut(words.as_ptr() as *mut u8, words.len() * 4) }; let fds = self.in_fds.get_writable_storage(); self.socket.rcv_msg(bytes, fds)? }; if in_bytes == 0 { // the other end of the socket was closed return Err(::nix::Error::EPIPE); } // advance the storage self.in_data.advance(in_bytes / 4 + if in_bytes % 4 > 0 { 1 } else { 0 }); self.in_fds.advance(in_fds); Ok(()) } /// Read and deserialize a single message from the incoming buffers socket /// /// This method requires one closure that given an object id and an opcode, /// must provide the signature of the associated request/event, in the form of /// a `&'static [ArgumentType]`. If it returns `None`, meaning that /// the couple object/opcode does not exist, an error will be returned. /// /// There are 3 possibilities of return value: /// /// - `Ok(Ok(msg))`: no error occurred, this is the message /// - `Ok(Err(e))`: either a malformed message was encountered or we need more data, /// in the latter case you need to try calling `fill_incoming_buffers()`. /// - `Err(e)`: an I/O error occurred reading from the socked, details are in `e` /// (this can be a "wouldblock" error, which just means that no message is available /// to read) pub fn read_one_message(&mut self, mut signature: F) -> Result where F: FnMut(u32, u16) -> Option<&'static [ArgumentType]>, { let (msg, read_data, read_fd) = { let data = self.in_data.get_contents(); let fds = self.in_fds.get_contents(); if data.len() < 2 { return Err(MessageParseError::MissingData); } let object_id = data[0]; let opcode = (data[1] & 0x0000_FFFF) as u16; if let Some(sig) = signature(object_id, opcode) { match Message::from_raw(data, sig, fds) { Ok((msg, rest_data, rest_fds)) => { (msg, data.len() - rest_data.len(), fds.len() - rest_fds.len()) } // TODO: gracefully handle wayland messages split across unix messages ? Err(e) => return Err(e), } } else { // no signature found ? return Err(MessageParseError::Malformed); } }; self.in_data.offset(read_data); self.in_fds.offset(read_fd); Ok(msg) } /// Read and deserialize messages from the socket /// /// This method requires two closures: /// /// - The first one, given an object id and an opcode, must provide /// the signature of the associated request/event, in the form of /// a `&'static [ArgumentType]`. If it returns `None`, meaning that /// the couple object/opcode does not exist, the parsing will be /// prematurely interrupted and this method will return a /// `MessageParseError::Malformed` error. /// - The second closure is charged to process the parsed message. If it /// returns `false`, the iteration will be prematurely stopped. /// /// In both cases of early stopping, the remaining unused data will be left /// in the buffers, and will start to be processed at the next call of this /// method. /// /// There are 3 possibilities of return value: /// /// - `Ok(Ok(n))`: no error occurred, `n` messages where processed /// - `Ok(Err(MessageParseError::Malformed))`: a malformed message was encountered /// (this is a protocol error and is supposed to be fatal to the connection). /// - `Err(e)`: an I/O error occurred reading from the socked, details are in `e` /// (this can be a "wouldblock" error, which just means that no message is available /// to read) pub fn read_messages( &mut self, mut signature: F1, mut callback: F2, ) -> NixResult> where F1: FnMut(u32, u16) -> Option<&'static [ArgumentType]>, F2: FnMut(Message) -> bool, { // message parsing let mut dispatched = 0; loop { let mut err = None; // first parse any leftover messages loop { match self.read_one_message(&mut signature) { Ok(msg) => { let keep_going = callback(msg); dispatched += 1; if !keep_going { break; } } Err(e) => { err = Some(e); break; } } } // copy back any leftover content to the front of the buffer self.in_data.move_to_front(); self.in_fds.move_to_front(); if let Some(MessageParseError::Malformed) = err { // early stop here return Ok(Err(MessageParseError::Malformed)); } if err.is_none() && self.in_data.has_content() { // we stopped reading without error while there is content? That means // the user requested an early stopping return Ok(Ok(dispatched)); } // now, try to get more data match self.fill_incoming_buffers() { Ok(()) => (), Err(e @ ::nix::Error::EAGAIN) => { // stop looping, returning Ok() or EAGAIN depending on whether messages // were dispatched if dispatched == 0 { return Err(e); } else { break; } } Err(e) => return Err(e), } } Ok(Ok(dispatched)) } } /* * Buffer */ #[derive(Debug)] struct Buffer { storage: Vec, occupied: usize, offset: usize, } impl Buffer { fn new(size: usize) -> Buffer { Buffer { storage: vec![T::default(); size], occupied: 0, offset: 0 } } /// Check if this buffer has content to read fn has_content(&self) -> bool { self.occupied > self.offset } /// Advance the internal counter of occupied space fn advance(&mut self, bytes: usize) { self.occupied += bytes; } /// Advance the read offset of current occupied space fn offset(&mut self, bytes: usize) { self.offset += bytes; } /// Clears the contents of the buffer /// /// This only sets the counter of occupied space back to zero, /// allowing previous content to be overwritten. fn clear(&mut self) { self.occupied = 0; self.offset = 0; } /// Get the current contents of the occupied space of the buffer fn get_contents(&self) -> &[T] { &self.storage[(self.offset)..(self.occupied)] } /// Get mutable access to the unoccupied space of the buffer fn get_writable_storage(&mut self) -> &mut [T] { &mut self.storage[(self.occupied)..] } /// Move the unread contents of the buffer to the front, to ensure /// maximal write space availability fn move_to_front(&mut self) { unsafe { ::std::ptr::copy( &self.storage[self.offset] as *const T, &mut self.storage[0] as *mut T, self.occupied - self.offset, ); } self.occupied -= self.offset; self.offset = 0; } } #[cfg(test)] mod tests { use super::*; use crate::wire::{Argument, ArgumentType, Message}; use std::ffi::CString; use smallvec::smallvec; fn same_file(a: RawFd, b: RawFd) -> bool { let stat1 = ::nix::sys::stat::fstat(a).unwrap(); let stat2 = ::nix::sys::stat::fstat(b).unwrap(); stat1.st_dev == stat2.st_dev && stat1.st_ino == stat2.st_ino } // check if two messages are equal // // if arguments contain FDs, check that the fd point to // the same file, rather than are the same number. fn assert_eq_msgs(msg1: &Message, msg2: &Message) { assert_eq!(msg1.sender_id, msg2.sender_id); assert_eq!(msg1.opcode, msg2.opcode); assert_eq!(msg1.args.len(), msg2.args.len()); for (arg1, arg2) in msg1.args.iter().zip(msg2.args.iter()) { if let (&Argument::Fd(fd1), &Argument::Fd(fd2)) = (arg1, arg2) { assert!(same_file(fd1, fd2)); } else { assert_eq!(arg1, arg2); } } } #[test] fn write_read_cycle() { let msg = Message { sender_id: 42, opcode: 7, args: smallvec![ Argument::Uint(3), Argument::Fixed(-89), Argument::Str(Box::new(CString::new(&b"I like trains!"[..]).unwrap())), Argument::Array(vec![1, 2, 3, 4, 5, 6, 7, 8, 9].into()), Argument::Object(88), Argument::NewId(56), Argument::Int(-25), ], }; let (client, server) = ::std::os::unix::net::UnixStream::pair().unwrap(); let mut client = BufferedSocket::new(unsafe { Socket::from_raw_fd(client.into_raw_fd()) }); let mut server = BufferedSocket::new(unsafe { Socket::from_raw_fd(server.into_raw_fd()) }); client.write_message(&msg).unwrap(); client.flush().unwrap(); static SIGNATURE: &'static [ArgumentType] = &[ ArgumentType::Uint, ArgumentType::Fixed, ArgumentType::Str, ArgumentType::Array, ArgumentType::Object, ArgumentType::NewId, ArgumentType::Int, ]; let ret = server .read_messages( |sender_id, opcode| { if sender_id == 42 && opcode == 7 { Some(SIGNATURE) } else { None } }, |message| { assert_eq_msgs(&message, &msg); true }, ) .unwrap() .unwrap(); assert_eq!(ret, 1); } #[test] fn write_read_cycle_fd() { let msg = Message { sender_id: 42, opcode: 7, args: smallvec![ Argument::Fd(1), // stdin Argument::Fd(0), // stdout ], }; let (client, server) = ::std::os::unix::net::UnixStream::pair().unwrap(); let mut client = BufferedSocket::new(unsafe { Socket::from_raw_fd(client.into_raw_fd()) }); let mut server = BufferedSocket::new(unsafe { Socket::from_raw_fd(server.into_raw_fd()) }); client.write_message(&msg).unwrap(); client.flush().unwrap(); static SIGNATURE: &'static [ArgumentType] = &[ArgumentType::Fd, ArgumentType::Fd]; let ret = server .read_messages( |sender_id, opcode| { if sender_id == 42 && opcode == 7 { Some(SIGNATURE) } else { None } }, |message| { assert_eq_msgs(&message, &msg); true }, ) .unwrap() .unwrap(); assert_eq!(ret, 1); } #[test] fn write_read_cycle_multiple() { let messages = [ Message { sender_id: 42, opcode: 0, args: smallvec![ Argument::Int(42), Argument::Str(Box::new(CString::new(&b"I like trains"[..]).unwrap())), ], }, Message { sender_id: 42, opcode: 1, args: smallvec![ Argument::Fd(1), // stdin Argument::Fd(0), // stdout ], }, Message { sender_id: 42, opcode: 2, args: smallvec![ Argument::Uint(3), Argument::Fd(2), // stderr ], }, ]; static SIGNATURES: &'static [&'static [ArgumentType]] = &[ &[ArgumentType::Int, ArgumentType::Str], &[ArgumentType::Fd, ArgumentType::Fd], &[ArgumentType::Uint, ArgumentType::Fd], ]; let (client, server) = ::std::os::unix::net::UnixStream::pair().unwrap(); let mut client = BufferedSocket::new(unsafe { Socket::from_raw_fd(client.into_raw_fd()) }); let mut server = BufferedSocket::new(unsafe { Socket::from_raw_fd(server.into_raw_fd()) }); for msg in &messages { client.write_message(msg).unwrap(); } client.flush().unwrap(); let mut recv_msgs = Vec::new(); let ret = server .read_messages( |sender_id, opcode| { if sender_id == 42 { Some(SIGNATURES[opcode as usize]) } else { None } }, |message| { recv_msgs.push(message); true }, ) .unwrap() .unwrap(); assert_eq!(ret, 3); assert_eq!(recv_msgs.len(), 3); for (msg1, msg2) in messages.iter().zip(recv_msgs.iter()) { assert_eq_msgs(msg1, msg2); } } #[test] fn parse_with_string_len_multiple_of_4() { let msg = Message { sender_id: 2, opcode: 0, args: smallvec![ Argument::Uint(18), Argument::Str(Box::new(CString::new(&b"wl_shell"[..]).unwrap())), Argument::Uint(1), ], }; let (client, server) = ::std::os::unix::net::UnixStream::pair().unwrap(); let mut client = BufferedSocket::new(unsafe { Socket::from_raw_fd(client.into_raw_fd()) }); let mut server = BufferedSocket::new(unsafe { Socket::from_raw_fd(server.into_raw_fd()) }); client.write_message(&msg).unwrap(); client.flush().unwrap(); static SIGNATURE: &'static [ArgumentType] = &[ArgumentType::Uint, ArgumentType::Str, ArgumentType::Uint]; let ret = server .read_messages( |sender_id, opcode| { if sender_id == 2 && opcode == 0 { Some(SIGNATURE) } else { None } }, |message| { assert_eq_msgs(&message, &msg); true }, ) .unwrap() .unwrap(); assert_eq!(ret, 1); } } wayland-commons-0.29.5/src/user_data.rs000064400000000000000000000230541046102023000161410ustar 00000000000000//! Various utilities used for other implementations use once_cell::sync::OnceCell; use std::any::Any; use std::mem::ManuallyDrop; use std::thread::{self, ThreadId}; use self::list::AppendList; /// A wrapper for user data, able to store any type, and correctly /// handling access from a wrong thread #[derive(Debug)] pub struct UserData { inner: OnceCell, } #[derive(Debug)] enum UserDataInner { ThreadSafe(Box), NonThreadSafe(Box>, ThreadId), } // UserData itself is always threadsafe, as it only gives access to its // content if it is send+sync or we are on the right thread unsafe impl Send for UserData {} unsafe impl Sync for UserData {} impl UserData { /// Create a new UserData instance pub const fn new() -> UserData { UserData { inner: OnceCell::new() } } /// Sets the UserData to a given value /// /// The provided closure is called to init the UserData, /// does nothing is the UserData had already been set. pub fn set T>(&self, f: F) { self.inner.get_or_init(|| { UserDataInner::NonThreadSafe(Box::new(ManuallyDrop::new(f())), thread::current().id()) }); } /// Sets the UserData to a given threadsafe value /// /// The provided closure is called to init the UserData, /// does nothing is the UserData had already been set. pub fn set_threadsafe T>(&self, f: F) { self.inner.get_or_init(|| UserDataInner::ThreadSafe(Box::new(f()))); } /// Attempt to access the wrapped user data /// /// Will return `None` if either: /// /// - The requested type `T` does not match the type used for construction /// - This `UserData` has been created using the non-threadsafe variant and access /// is attempted from an other thread than the one it was created on pub fn get(&self) -> Option<&T> { match self.inner.get() { Some(&UserDataInner::ThreadSafe(ref val)) => ::downcast_ref::(&**val), Some(&UserDataInner::NonThreadSafe(ref val, threadid)) => { // only give access if we are on the right thread if threadid == thread::current().id() { ::downcast_ref::(&***val) } else { None } } None => None, } } } impl Drop for UserData { fn drop(&mut self) { // only drop non-Send user data if we are on the right thread, leak it otherwise if let Some(&mut UserDataInner::NonThreadSafe(ref mut val, threadid)) = self.inner.get_mut() { if threadid == thread::current().id() { unsafe { ManuallyDrop::drop(&mut **val); } } } } } /// A storage able to store several values of `UserData` /// of different types. It behaves similarly to a `TypeMap`. #[derive(Debug)] pub struct UserDataMap { list: AppendList, } impl UserDataMap { /// Create a new map pub fn new() -> UserDataMap { UserDataMap { list: AppendList::new() } } /// Attempt to access the wrapped user data of a given type /// /// Will return `None` if no value of type `T` is stored in this `UserDataMap` /// and accessible from this thread pub fn get(&self) -> Option<&T> { for user_data in &self.list { if let Some(val) = user_data.get::() { return Some(val); } } None } /// Insert a value in the map if it is not already there /// /// This is the non-threadsafe variant, the type you insert don't have to be /// threadsafe, but they will not be visible from other threads (even if they are /// actually threadsafe). /// /// If the value does not already exists, the closure is called to create it and /// this function returns `true`. If the value already exists, the closure is not /// called, and this function returns `false`. pub fn insert_if_missing T>(&self, init: F) -> bool { if self.get::().is_some() { return false; } let data = UserData::new(); data.set(init); self.list.append(data); true } /// Insert a value in the map if it is not already there /// /// This is the threadsafe variant, the type you insert must be threadsafe and will /// be visible from all threads. /// /// If the value does not already exists, the closure is called to create it and /// this function returns `true`. If the value already exists, the closure is not /// called, and this function returns `false`. pub fn insert_if_missing_threadsafe T>( &self, init: F, ) -> bool { if self.get::().is_some() { return false; } let data = UserData::new(); data.set_threadsafe(init); self.list.append(data); true } } impl Default for UserDataMap { fn default() -> UserDataMap { UserDataMap::new() } } mod list { /* * This is a lock-free append-only list, it is used as an implementation * detail of the UserDataMap. * * It was extracted from https://github.com/Diggsey/lockless under MIT license * Copyright © Diggory Blake */ use std::sync::atomic::{AtomicPtr, Ordering}; use std::{mem, ptr}; type NodePtr = Option>>; #[derive(Debug)] struct Node { value: T, next: AppendList, } #[derive(Debug)] pub struct AppendList(AtomicPtr>); impl AppendList { fn node_into_raw(ptr: NodePtr) -> *mut Node { match ptr { Some(b) => Box::into_raw(b), None => ptr::null_mut(), } } unsafe fn node_from_raw(ptr: *mut Node) -> NodePtr { if ptr.is_null() { None } else { Some(Box::from_raw(ptr)) } } fn new_internal(ptr: NodePtr) -> Self { AppendList(AtomicPtr::new(Self::node_into_raw(ptr))) } pub fn new() -> Self { Self::new_internal(None) } pub fn append(&self, value: T) { self.append_list(AppendList::new_internal(Some(Box::new(Node { value, next: AppendList::new(), })))); } unsafe fn append_ptr(&self, p: *mut Node) { loop { match self.0.compare_exchange_weak( ptr::null_mut(), p, Ordering::AcqRel, Ordering::Acquire, ) { Ok(_) => return, Err(head) => { if !head.is_null() { return (*head).next.append_ptr(p); } } } } } pub fn append_list(&self, other: AppendList) { let p = other.0.load(Ordering::Acquire); mem::forget(other); unsafe { self.append_ptr(p) }; } pub fn iter(&self) -> AppendListIterator { AppendListIterator(&self.0) } pub fn iter_mut(&mut self) -> AppendListMutIterator { AppendListMutIterator(&mut self.0) } } impl<'a, T> IntoIterator for &'a AppendList { type Item = &'a T; type IntoIter = AppendListIterator<'a, T>; fn into_iter(self) -> AppendListIterator<'a, T> { self.iter() } } impl<'a, T> IntoIterator for &'a mut AppendList { type Item = &'a mut T; type IntoIter = AppendListMutIterator<'a, T>; fn into_iter(self) -> AppendListMutIterator<'a, T> { self.iter_mut() } } impl Drop for AppendList { fn drop(&mut self) { unsafe { Self::node_from_raw(mem::replace(self.0.get_mut(), ptr::null_mut())) }; } } #[derive(Debug)] pub struct AppendListIterator<'a, T: 'a>(&'a AtomicPtr>); impl<'a, T: 'a> Iterator for AppendListIterator<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { let p = self.0.load(Ordering::Acquire); if p.is_null() { None } else { unsafe { self.0 = &(*p).next.0; Some(&(*p).value) } } } } #[derive(Debug)] pub struct AppendListMutIterator<'a, T: 'a>(&'a mut AtomicPtr>); impl<'a, T: 'a> Iterator for AppendListMutIterator<'a, T> { type Item = &'a mut T; fn next(&mut self) -> Option<&'a mut T> { let p = self.0.load(Ordering::Acquire); if p.is_null() { None } else { unsafe { self.0 = &mut (*p).next.0; Some(&mut (*p).value) } } } } } #[cfg(test)] mod tests { use super::UserDataMap; #[test] fn insert_twice() { let map = UserDataMap::new(); assert_eq!(map.get::(), None); assert!(map.insert_if_missing(|| 42usize)); assert!(!map.insert_if_missing(|| 43usize)); assert_eq!(map.get::(), Some(&42)); } } wayland-commons-0.29.5/src/wire.rs000064400000000000000000000374071046102023000151470ustar 00000000000000//! Types and routines used to manipulate arguments from the wire format use std::ffi::{CStr, CString}; use std::os::unix::io::RawFd; use std::ptr; use nix::{Error as NixError, Result as NixResult}; use smallvec::SmallVec; // The value of 4 is chosen for the following reasons: // - almost all messages have 4 arguments or less // - there are some potentially spammy events that have 3/4 arguments (wl_touch.move has 4 for example) // // This brings the size of Message to 11*usize (instead of 4*usize with a regular vec), but eliminates // almost all allocations that may occur during the processing of messages, both client-side and server-side. const INLINE_ARGS: usize = 4; /// Wire metadata of a given message #[derive(Copy, Clone, Debug)] pub struct MessageDesc { /// Name of this message pub name: &'static str, /// Signature of the message pub signature: &'static [ArgumentType], /// Minimum required version of the interface pub since: u32, /// Whether this message is a destructor pub destructor: bool, } /// Enum of possible argument types as recognized by the wire #[derive(Copy, Clone, PartialEq, Debug)] pub enum ArgumentType { /// i32 Int, /// u32 Uint, /// fixed point, 1/256 precision Fixed, /// CString Str, /// id of a wayland object Object, /// id of a newly created wayland object NewId, /// Vec Array, /// RawFd Fd, } /// Enum of possible argument as recognized by the wire, including values #[derive(Clone, PartialEq, Debug)] #[allow(clippy::box_collection)] pub enum Argument { /// i32 Int(i32), /// u32 Uint(u32), /// fixed point, 1/256 precision Fixed(i32), /// CString /// /// The value is boxed to reduce the stack size of Argument. The performance /// impact is negligible as `string` arguments are pretty rare in the protocol. Str(Box), /// id of a wayland object Object(u32), /// id of a newly created wayland object NewId(u32), /// Vec /// /// The value is boxed to reduce the stack size of Argument. The performance /// impact is negligible as `array` arguments are pretty rare in the protocol. Array(Box>), /// RawFd Fd(RawFd), } impl Argument { /// Retrieve the type of a given argument instance pub fn get_type(&self) -> ArgumentType { match *self { Argument::Int(_) => ArgumentType::Int, Argument::Uint(_) => ArgumentType::Uint, Argument::Fixed(_) => ArgumentType::Fixed, Argument::Str(_) => ArgumentType::Str, Argument::Object(_) => ArgumentType::Object, Argument::NewId(_) => ArgumentType::NewId, Argument::Array(_) => ArgumentType::Array, Argument::Fd(_) => ArgumentType::Fd, } } } impl std::fmt::Display for Argument { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Argument::Int(value) => write!(f, "{}", value), Argument::Uint(value) => write!(f, "{}", value), Argument::Fixed(value) => write!(f, "{}", value), Argument::Str(value) => write!(f, "{:?}", value), Argument::Object(value) => write!(f, "{}", value), Argument::NewId(value) => write!(f, "{}", value), Argument::Array(value) => write!(f, "{:?}", value), Argument::Fd(value) => write!(f, "{}", value), } } } /// A wire message #[derive(Debug, Clone, PartialEq)] pub struct Message { /// ID of the object sending this message pub sender_id: u32, /// Opcode of the message pub opcode: u16, /// Arguments of the message pub args: SmallVec<[Argument; INLINE_ARGS]>, } /// Error generated when trying to serialize a message into buffers #[derive(Debug, Clone)] pub enum MessageWriteError { /// The buffer is too small to hold the message contents BufferTooSmall, /// The message contains a FD that could not be dup-ed DupFdFailed(::nix::Error), } impl std::error::Error for MessageWriteError {} impl std::fmt::Display for MessageWriteError { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { match *self { MessageWriteError::BufferTooSmall => { f.write_str("The provided buffer is too small to hold message content.") } MessageWriteError::DupFdFailed(_) => { f.write_str("The message contains a file descriptor that could not be dup()-ed.") } } } } /// Error generated when trying to deserialize a message from buffers #[derive(Debug, Clone)] pub enum MessageParseError { /// The message references a FD but the buffer FD is empty MissingFD, /// More data is needed to deserialize the message MissingData, /// The message is malformed and cannot be parsed Malformed, } impl std::error::Error for MessageParseError {} impl std::fmt::Display for MessageParseError { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { match *self { MessageParseError::MissingFD => { f.write_str("The message references a FD but the buffer FD is empty.") } MessageParseError::MissingData => { f.write_str("More data is needed to deserialize the message") } MessageParseError::Malformed => { f.write_str("The message is malformed and cannot be parsed") } } } } impl Message { /// Serialize the contents of this message into provided buffers /// /// Returns the number of elements written in each buffer /// /// Any serialized Fd will be `dup()`-ed in the process pub fn write_to_buffers( &self, payload: &mut [u32], mut fds: &mut [RawFd], ) -> Result<(usize, usize), MessageWriteError> { let orig_payload_len = payload.len(); let orig_fds_len = fds.len(); // Helper function to write a u32 or a RawFd to its buffer fn write_buf(u: T, payload: &mut [T]) -> Result<&mut [T], MessageWriteError> { if let Some((head, tail)) = payload.split_first_mut() { *head = u; Ok(tail) } else { Err(MessageWriteError::BufferTooSmall) } } // Helper function to write byte arrays in payload fn write_array_to_payload<'a>( array: &[u8], payload: &'a mut [u32], ) -> Result<&'a mut [u32], MessageWriteError> { let array_len = array.len(); let word_len = array_len / 4 + if array_len % 4 != 0 { 1 } else { 0 }; // need enough space to store the whole array with padding and a size header if payload.len() < 1 + word_len { return Err(MessageWriteError::BufferTooSmall); } // size header payload[0] = array_len as u32; let (buffer_slice, rest) = payload[1..].split_at_mut(word_len); unsafe { ptr::copy(array.as_ptr(), buffer_slice.as_mut_ptr() as *mut u8, array_len); } Ok(rest) } let free_size = payload.len(); if free_size < 2 { return Err(MessageWriteError::BufferTooSmall); } let (header, mut payload) = payload.split_at_mut(2); // we store all fds we dup-ed in this, which will auto-close // them on drop, if any of the `?` early-returns let mut pending_fds = FdStore::new(); // write the contents in the buffer for arg in &self.args { // Just to make the borrow checker happy let old_payload = payload; match *arg { Argument::Int(i) => payload = write_buf(i as u32, old_payload)?, Argument::Uint(u) => payload = write_buf(u, old_payload)?, Argument::Fixed(f) => payload = write_buf(f as u32, old_payload)?, Argument::Str(ref s) => { payload = write_array_to_payload(s.as_bytes_with_nul(), old_payload)?; } Argument::Object(o) => payload = write_buf(o, old_payload)?, Argument::NewId(n) => payload = write_buf(n, old_payload)?, Argument::Array(ref a) => { payload = write_array_to_payload(a, old_payload)?; } Argument::Fd(fd) => { let old_fds = fds; let dup_fd = dup_fd_cloexec(fd).map_err(MessageWriteError::DupFdFailed)?; pending_fds.push(dup_fd); fds = write_buf(dup_fd, old_fds)?; payload = old_payload; } } } // we reached here, all writing was successful // no FD needs to be closed pending_fds.clear(); let wrote_size = (free_size - payload.len()) * 4; header[0] = self.sender_id; header[1] = ((wrote_size as u32) << 16) | u32::from(self.opcode); Ok((orig_payload_len - payload.len(), orig_fds_len - fds.len())) } /// Attempts to parse a single wayland message with the given signature. /// /// If the buffers contains several messages, only the first one will be parsed, /// and the unused tail of the buffers is returned. If a single message was present, /// the returned slices should thus be empty. /// /// Errors if the message is malformed. pub fn from_raw<'a, 'b>( raw: &'a [u32], signature: &[ArgumentType], fds: &'b [RawFd], ) -> Result<(Message, &'a [u32], &'b [RawFd]), MessageParseError> { // helper function to read arrays fn read_array_from_payload( array_len: usize, payload: &[u32], ) -> Result<(&[u8], &[u32]), MessageParseError> { let word_len = array_len / 4 + if array_len % 4 != 0 { 1 } else { 0 }; if word_len > payload.len() { return Err(MessageParseError::MissingData); } let (array_contents, rest) = payload.split_at(word_len); let array = unsafe { ::std::slice::from_raw_parts(array_contents.as_ptr() as *const u8, array_len) }; Ok((array, rest)) } if raw.len() < 2 { return Err(MessageParseError::MissingData); } let sender_id = raw[0]; let word_2 = raw[1]; let opcode = (word_2 & 0x0000_FFFF) as u16; let len = (word_2 >> 16) as usize / 4; if len < 2 || len > raw.len() { return Err(MessageParseError::Malformed); } let (mut payload, rest) = raw.split_at(len); payload = &payload[2..]; let mut fds = fds; let arguments = signature .iter() .map(|argtype| { if let ArgumentType::Fd = *argtype { // don't consume input but fd if let Some((&front, tail)) = fds.split_first() { fds = tail; Ok(Argument::Fd(front)) } else { Err(MessageParseError::MissingFD) } } else if let Some((&front, mut tail)) = payload.split_first() { let arg = match *argtype { ArgumentType::Int => Ok(Argument::Int(front as i32)), ArgumentType::Uint => Ok(Argument::Uint(front)), ArgumentType::Fixed => Ok(Argument::Fixed(front as i32)), ArgumentType::Str => read_array_from_payload(front as usize, tail) .and_then(|(v, rest)| { tail = rest; match CStr::from_bytes_with_nul(v) { Ok(s) => Ok(Argument::Str(Box::new(s.into()))), Err(_) => Err(MessageParseError::Malformed), } }), ArgumentType::Object => Ok(Argument::Object(front)), ArgumentType::NewId => Ok(Argument::NewId(front)), ArgumentType::Array => { read_array_from_payload(front as usize, tail).map(|(v, rest)| { tail = rest; Argument::Array(Box::new(v.into())) }) } ArgumentType::Fd => unreachable!(), }; payload = tail; arg } else { Err(MessageParseError::MissingData) } }) .collect::, MessageParseError>>()?; let msg = Message { sender_id, opcode, args: arguments }; Ok((msg, rest, fds)) } } /// Duplicate a `RawFd` and set the CLOEXEC flag on the copy pub fn dup_fd_cloexec(fd: RawFd) -> NixResult { use nix::fcntl; match fcntl::fcntl(fd, fcntl::FcntlArg::F_DUPFD_CLOEXEC(0)) { Ok(newfd) => Ok(newfd), Err(NixError::EINVAL) => { // F_DUPFD_CLOEXEC is not recognized, kernel too old, fallback // to setting CLOEXEC manually let newfd = fcntl::fcntl(fd, fcntl::FcntlArg::F_DUPFD(0))?; let flags = fcntl::fcntl(newfd, fcntl::FcntlArg::F_GETFD); let result = flags .map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC) .and_then(|f| fcntl::fcntl(newfd, fcntl::FcntlArg::F_SETFD(f))); match result { Ok(_) => { // setting the O_CLOEXEC worked Ok(newfd) } Err(e) => { // something went wrong in F_GETFD or F_SETFD let _ = ::nix::unistd::close(newfd); Err(e) } } } Err(e) => Err(e), } } /* * utility struct that closes every FD it contains on drop */ struct FdStore { fds: Vec, } impl FdStore { fn new() -> FdStore { FdStore { fds: Vec::new() } } fn push(&mut self, fd: RawFd) { self.fds.push(fd); } fn clear(&mut self) { self.fds.clear(); } } impl Drop for FdStore { fn drop(&mut self) { use nix::unistd::close; for fd in self.fds.drain(..) { // not much can be done if we can't close that anyway... let _ = close(fd); } } } #[cfg(test)] mod tests { use super::*; use smallvec::smallvec; #[test] fn into_from_raw_cycle() { let mut bytes_buffer = vec![0; 1024]; let mut fd_buffer = vec![0; 10]; let msg = Message { sender_id: 42, opcode: 7, args: smallvec![ Argument::Uint(3), Argument::Fixed(-89), Argument::Str(Box::new(CString::new(&b"I like trains!"[..]).unwrap())), Argument::Array(vec![1, 2, 3, 4, 5, 6, 7, 8, 9].into()), Argument::Object(88), Argument::NewId(56), Argument::Int(-25), ], }; // write the message to the buffers msg.write_to_buffers(&mut bytes_buffer[..], &mut fd_buffer[..]).unwrap(); // read them back let (rebuilt, _, _) = Message::from_raw( &bytes_buffer[..], &[ ArgumentType::Uint, ArgumentType::Fixed, ArgumentType::Str, ArgumentType::Array, ArgumentType::Object, ArgumentType::NewId, ArgumentType::Int, ], &fd_buffer[..], ) .unwrap(); assert_eq!(rebuilt, msg); } }