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)]
21pub(crate) struct 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(
164        &mut self,
165        id: InnerGlobalId,
166        clients: &mut ClientStore<D>,
167    ) -> Option<Global<D>> {
168        // disable the global if not already disabled
169        self.disable_global(id.clone(), clients);
170        // now remove it if the id is still valid
171        if let Some(place) = self.globals.get_mut(id.id as usize - 1) {
172            if place.as_ref().map(|g| g.id == id).unwrap_or(false) {
173                place.take()
174            } else {
175                None
176            }
177        } else {
178            None
179        }
180    }
181
182    pub(crate) fn new_registry(
183        &mut self,
184        registry: InnerObjectId,
185        client: &mut Client<D>,
186    ) -> Result<(), InvalidId> {
187        self.send_all_globals_to(registry.clone(), client)?;
188        self.known_registries.push(registry);
189        Ok(())
190    }
191
192    pub(crate) fn send_all_globals_to(
193        &self,
194        registry: InnerObjectId,
195        client: &mut Client<D>,
196    ) -> Result<(), InvalidId> {
197        for global in self.globals.iter().flat_map(|opt| opt.as_ref()) {
198            if !global.disabled
199                && global.handler.can_view(
200                    ClientId { id: client.id.clone() },
201                    &client.data,
202                    GlobalId { id: global.id.clone() },
203                )
204            {
205                // fail the whole send on error, there is no point in trying further on a failing client
206                send_global_to(client, global, ObjectId { id: registry.clone() })?;
207            }
208        }
209        Ok(())
210    }
211
212    pub(crate) fn send_global_to_all(
213        &self,
214        global_id: InnerGlobalId,
215        clients: &mut ClientStore<D>,
216    ) -> Result<(), InvalidId> {
217        let global = self.get_global(global_id)?;
218        if global.disabled {
219            return Err(InvalidId);
220        }
221        for registry in self.known_registries.iter().cloned() {
222            if let Ok(client) = clients.get_client_mut(registry.client_id.clone()) {
223                if !global.disabled
224                    && global.handler.can_view(
225                        ClientId { id: client.id.clone() },
226                        &client.data,
227                        GlobalId { id: global.id.clone() },
228                    )
229                {
230                    // don't fail the whole send for a single erroring client
231                    let _ = send_global_to(client, global, ObjectId { id: registry.clone() });
232                }
233            }
234        }
235        Ok(())
236    }
237}
238
239#[inline]
240fn send_global_to<D>(
241    client: &mut Client<D>,
242    global: &Global<D>,
243    registry: ObjectId,
244) -> Result<(), InvalidId> {
245    client.send_event(
246        message!(
247            registry,
248            0, // wl_registry.global
249            [
250                Argument::Uint(global.id.id),
251                Argument::Str(Some(Box::new(CString::new(global.interface.name).unwrap()))),
252                Argument::Uint(global.version),
253            ],
254        ),
255        // This is not a destructor event
256        None,
257    )
258}
259
260#[inline]
261fn send_global_remove_to<D>(
262    client: &mut Client<D>,
263    global: &Global<D>,
264    registry: ObjectId,
265) -> Result<(), InvalidId> {
266    client.send_event(
267        message!(
268            registry,
269            1, // wl_registry.global_remove
270            [Argument::Uint(global.id.id)],
271        ),
272        // This is not a destructor event
273        None,
274    )
275}