wayland_backend/rs/server_impl/
registry.rs

1use std::{
2    ffi::{CStr, CString},
3    sync::Arc,
4};
5
6use crate::protocol::{Argument, Interface};
7use crate::types::server::{GlobalInfo, InvalidId};
8
9use super::{
10    client::{Client, ClientStore},
11    handle::PendingDestructor,
12    ClientId, GlobalHandler, GlobalId, InnerGlobalId, InnerObjectId, ObjectId,
13};
14
15/*
16    GlobalId.id is the global protocol name (starting at 1), hence
17    we must subtract 1 to it before indexing the vec
18*/
19
20#[derive(Debug)]
21struct Global<D: 'static> {
22    id: InnerGlobalId,
23    interface: &'static Interface,
24    version: u32,
25    handler: Arc<dyn GlobalHandler<D>>,
26    disabled: bool,
27}
28
29#[derive(Debug)]
30
31pub struct Registry<D: 'static> {
32    globals: Vec<Option<Global<D>>>,
33    known_registries: Vec<InnerObjectId>,
34    last_serial: u32,
35}
36
37impl<D> Registry<D> {
38    pub(crate) fn new() -> Self {
39        Self { globals: Vec::new(), known_registries: Vec::new(), last_serial: 0 }
40    }
41
42    fn next_serial(&mut self) -> u32 {
43        self.last_serial = self.last_serial.wrapping_add(1);
44        self.last_serial
45    }
46
47    pub(crate) fn create_global(
48        &mut self,
49        interface: &'static Interface,
50        version: u32,
51        handler: Arc<dyn GlobalHandler<D>>,
52        clients: &mut ClientStore<D>,
53    ) -> InnerGlobalId {
54        if version > interface.version {
55            panic!(
56                "Cannot create global {} version {}: maximum supported version is {}",
57                interface.name, version, interface.version
58            );
59        }
60        let serial = self.next_serial();
61        let (id, place) = match self.globals.iter_mut().enumerate().find(|(_, g)| g.is_none()) {
62            Some((id, place)) => (id, place),
63            None => {
64                self.globals.push(None);
65                (self.globals.len() - 1, self.globals.last_mut().unwrap())
66            }
67        };
68
69        let id = InnerGlobalId { id: id as u32 + 1, serial };
70
71        *place = Some(Global { id: id.clone(), interface, version, handler, disabled: false });
72
73        self.send_global_to_all(id.clone(), clients).unwrap();
74
75        id
76    }
77
78    fn get_global(&self, id: InnerGlobalId) -> Result<&Global<D>, InvalidId> {
79        self.globals
80            .get(id.id as usize - 1)
81            .and_then(|o| o.as_ref())
82            .filter(|o| o.id == id)
83            .ok_or(InvalidId)
84    }
85
86    pub(crate) fn get_info(&self, id: InnerGlobalId) -> Result<GlobalInfo, InvalidId> {
87        let global = self.get_global(id)?;
88        Ok(GlobalInfo {
89            interface: global.interface,
90            version: global.version,
91            disabled: global.disabled,
92        })
93    }
94
95    pub(crate) fn get_handler(
96        &self,
97        id: InnerGlobalId,
98    ) -> Result<Arc<dyn GlobalHandler<D>>, InvalidId> {
99        let global = self.get_global(id)?;
100        Ok(global.handler.clone())
101    }
102
103    pub(crate) fn check_bind(
104        &self,
105        client: &Client<D>,
106        name: u32,
107        interface_name: &CStr,
108        version: u32,
109    ) -> Option<(&'static Interface, InnerGlobalId, Arc<dyn GlobalHandler<D>>)> {
110        if name == 0 || version == 0 {
111            return None;
112        }
113        let target_global = self.globals.get((name - 1) as usize).and_then(|o| o.as_ref())?;
114        if target_global.interface.name.as_bytes() != interface_name.to_bytes() {
115            return None;
116        }
117        if target_global.version < version {
118            return None;
119        }
120        if !target_global.handler.can_view(
121            ClientId { id: client.id.clone() },
122            &client.data,
123            GlobalId { id: target_global.id.clone() },
124        ) {
125            return None;
126        }
127
128        Some((target_global.interface, target_global.id.clone(), target_global.handler.clone()))
129    }
130
131    pub(crate) fn cleanup(
132        &mut self,
133        dead_clients: &[Client<D>],
134        pending_destructors: &[PendingDestructor<D>],
135    ) {
136        // Remote registries with client id matching any dead clients, or object
137        // id matching pending destructors.
138        self.known_registries.retain(|obj_id| {
139            !dead_clients.iter().any(|cid| cid.id == obj_id.client_id)
140                && !pending_destructors.iter().any(|(_, _, id)| id == obj_id)
141        })
142    }
143
144    pub(crate) fn disable_global(&mut self, id: InnerGlobalId, clients: &mut ClientStore<D>) {
145        let global = match self.globals.get_mut(id.id as usize - 1) {
146            Some(&mut Some(ref mut g)) if g.id == id => g,
147            _ => return,
148        };
149
150        // Do nothing if the global is already disabled
151        if !global.disabled {
152            global.disabled = true;
153            // send the global_remove
154            for registry in self.known_registries.iter().cloned() {
155                if let Ok(client) = clients.get_client_mut(registry.client_id.clone()) {
156                    let _ =
157                        send_global_remove_to(client, global, ObjectId { id: registry.clone() });
158                }
159            }
160        }
161    }
162
163    pub(crate) fn remove_global(&mut self, id: InnerGlobalId, clients: &mut ClientStore<D>) {
164        // disable the global if not already disabled
165        self.disable_global(id.clone(), clients);
166        // now remove it if the id is still valid
167        if let Some(place) = self.globals.get_mut(id.id as usize - 1) {
168            if place.as_ref().map(|g| g.id == id).unwrap_or(false) {
169                *place = None;
170            }
171        }
172    }
173
174    pub(crate) fn new_registry(
175        &mut self,
176        registry: InnerObjectId,
177        client: &mut Client<D>,
178    ) -> Result<(), InvalidId> {
179        self.send_all_globals_to(registry.clone(), client)?;
180        self.known_registries.push(registry);
181        Ok(())
182    }
183
184    pub(crate) fn send_all_globals_to(
185        &self,
186        registry: InnerObjectId,
187        client: &mut Client<D>,
188    ) -> Result<(), InvalidId> {
189        for global in self.globals.iter().flat_map(|opt| opt.as_ref()) {
190            if !global.disabled
191                && global.handler.can_view(
192                    ClientId { id: client.id.clone() },
193                    &client.data,
194                    GlobalId { id: global.id.clone() },
195                )
196            {
197                // fail the whole send on error, there is no point in trying further on a failing client
198                send_global_to(client, global, ObjectId { id: registry.clone() })?;
199            }
200        }
201        Ok(())
202    }
203
204    pub(crate) fn send_global_to_all(
205        &self,
206        global_id: InnerGlobalId,
207        clients: &mut ClientStore<D>,
208    ) -> Result<(), InvalidId> {
209        let global = self.get_global(global_id)?;
210        if global.disabled {
211            return Err(InvalidId);
212        }
213        for registry in self.known_registries.iter().cloned() {
214            if let Ok(client) = clients.get_client_mut(registry.client_id.clone()) {
215                if !global.disabled
216                    && global.handler.can_view(
217                        ClientId { id: client.id.clone() },
218                        &client.data,
219                        GlobalId { id: global.id.clone() },
220                    )
221                {
222                    // don't fail the whole send for a single erroring client
223                    let _ = send_global_to(client, global, ObjectId { id: registry.clone() });
224                }
225            }
226        }
227        Ok(())
228    }
229}
230
231#[inline]
232fn send_global_to<D>(
233    client: &mut Client<D>,
234    global: &Global<D>,
235    registry: ObjectId,
236) -> Result<(), InvalidId> {
237    client.send_event(
238        message!(
239            registry,
240            0, // wl_registry.global
241            [
242                Argument::Uint(global.id.id),
243                Argument::Str(Some(Box::new(CString::new(global.interface.name).unwrap()))),
244                Argument::Uint(global.version),
245            ],
246        ),
247        // This is not a destructor event
248        None,
249    )
250}
251
252#[inline]
253fn send_global_remove_to<D>(
254    client: &mut Client<D>,
255    global: &Global<D>,
256    registry: ObjectId,
257) -> Result<(), InvalidId> {
258    client.send_event(
259        message!(
260            registry,
261            1, // wl_registry.global_remove
262            [Argument::Uint(global.id.id)],
263        ),
264        // This is not a destructor event
265        None,
266    )
267}