veridian_kernel/desktop/wayland/
protocol.rs1#![allow(dead_code)]
14
15use alloc::{vec, vec::Vec};
16
17use crate::error::KernelError;
18
19const HEADER_SIZE: usize = 8;
25
26const MAX_MESSAGE_SIZE: usize = 65536;
28
29pub const WL_DISPLAY_ID: u32 = 1;
33
34pub const WL_DISPLAY_SYNC: u16 = 0;
37pub const WL_DISPLAY_GET_REGISTRY: u16 = 1;
39
40pub const WL_DISPLAY_ERROR: u16 = 0;
43pub const WL_DISPLAY_DELETE_ID: u16 = 1;
45
46pub const WL_REGISTRY_GLOBAL: u16 = 0;
49pub const WL_REGISTRY_GLOBAL_REMOVE: u16 = 1;
51
52pub const WL_REGISTRY_BIND: u16 = 0;
55
56pub const WL_COMPOSITOR_CREATE_SURFACE: u16 = 0;
59pub const WL_COMPOSITOR_CREATE_REGION: u16 = 1;
61
62pub const WL_SHM_CREATE_POOL: u16 = 0;
65
66pub const WL_SHM_FORMAT: u16 = 0;
69
70pub const WL_SHM_POOL_CREATE_BUFFER: u16 = 0;
73pub const WL_SHM_POOL_DESTROY: u16 = 2;
75
76pub const WL_SURFACE_DESTROY: u16 = 0;
79pub const WL_SURFACE_ATTACH: u16 = 1;
81pub const WL_SURFACE_DAMAGE: u16 = 2;
83pub const WL_SURFACE_FRAME: u16 = 3;
85pub const WL_SURFACE_COMMIT: u16 = 6;
87
88pub const WL_SURFACE_ENTER: u16 = 0;
91
92pub const WL_SHM_FORMAT_ARGB8888: u32 = 0;
95pub const WL_SHM_FORMAT_XRGB8888: u32 = 1;
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
104pub enum WaylandError {
105 MessageTooShort,
107 SizeMismatch { declared: usize, available: usize },
109 InvalidString,
111 InvalidArgument,
113 UnknownObject { id: u32 },
115 UnknownOpcode { object_id: u32, opcode: u16 },
117 MissingNewId,
119}
120
121impl From<WaylandError> for KernelError {
122 fn from(e: WaylandError) -> Self {
123 match e {
124 WaylandError::MessageTooShort => KernelError::InvalidArgument {
125 name: "wayland_message",
126 value: "too short",
127 },
128 WaylandError::SizeMismatch { .. } => KernelError::InvalidArgument {
129 name: "wayland_message_size",
130 value: "mismatch",
131 },
132 WaylandError::InvalidString => KernelError::InvalidArgument {
133 name: "wayland_string",
134 value: "invalid encoding",
135 },
136 WaylandError::InvalidArgument => KernelError::InvalidArgument {
137 name: "wayland_argument",
138 value: "invalid",
139 },
140 WaylandError::UnknownObject { id } => KernelError::NotFound {
141 resource: "wayland_object",
142 id: id as u64,
143 },
144 WaylandError::UnknownOpcode { .. } => KernelError::OperationNotSupported {
145 operation: "wayland opcode",
146 },
147 WaylandError::MissingNewId => KernelError::InvalidArgument {
148 name: "wayland_new_id",
149 value: "missing",
150 },
151 }
152 }
153}
154
155#[repr(C)]
161#[derive(Debug, Clone, Copy)]
162pub struct MessageHeader {
163 pub object_id: u32,
165 pub size_opcode: u32,
167}
168
169impl MessageHeader {
170 pub fn opcode(&self) -> u16 {
172 (self.size_opcode & 0xFFFF) as u16
173 }
174
175 pub fn size(&self) -> u16 {
177 ((self.size_opcode >> 16) & 0xFFFF) as u16
178 }
179
180 pub fn encode(opcode: u16, size: u16) -> u32 {
182 ((size as u32) << 16) | (opcode as u32)
183 }
184}
185
186#[derive(Debug, Clone)]
192pub enum Argument {
193 Int(i32),
195 Uint(u32),
197 Fixed(i32),
199 String(Vec<u8>),
201 Object(u32),
203 NewId(u32),
205 Array(Vec<u8>),
207 Fd(i32),
209}
210
211#[derive(Debug, Clone)]
217pub struct WaylandMessage {
218 pub object_id: u32,
220 pub opcode: u16,
222 pub args: Vec<Argument>,
224}
225
226impl WaylandMessage {
227 pub fn new(object_id: u32, opcode: u16, args: Vec<Argument>) -> Self {
229 Self {
230 object_id,
231 opcode,
232 args,
233 }
234 }
235}
236
237fn read_u32(data: &[u8], offset: usize) -> Option<u32> {
244 if offset + 4 > data.len() {
245 return None;
246 }
247 Some(u32::from_ne_bytes([
248 data[offset],
249 data[offset + 1],
250 data[offset + 2],
251 data[offset + 3],
252 ]))
253}
254
255fn read_i32(data: &[u8], offset: usize) -> Option<i32> {
257 read_u32(data, offset).map(|v| v as i32)
258}
259
260fn align4(n: usize) -> usize {
262 (n + 3) & !3
263}
264
265pub fn parse_message(data: &[u8]) -> Result<(WaylandMessage, usize), WaylandError> {
274 if data.len() < HEADER_SIZE {
275 return Err(WaylandError::MessageTooShort);
276 }
277
278 let object_id = read_u32(data, 0).ok_or(WaylandError::MessageTooShort)?;
279 let size_opcode = read_u32(data, 4).ok_or(WaylandError::MessageTooShort)?;
280
281 let header = MessageHeader {
282 object_id,
283 size_opcode,
284 };
285 let total_size = header.size() as usize;
286 let opcode = header.opcode();
287
288 if total_size < HEADER_SIZE || total_size > data.len() {
289 return Err(WaylandError::SizeMismatch {
290 declared: total_size,
291 available: data.len(),
292 });
293 }
294
295 let payload = &data[HEADER_SIZE..total_size];
297
298 let msg = WaylandMessage {
299 object_id,
300 opcode,
301 args: Vec::new(),
302 };
303
304 let mut args = Vec::new();
308 let mut off = 0;
309 while off + 4 <= payload.len() {
310 let word = read_u32(payload, off).ok_or(WaylandError::InvalidArgument)?;
311 args.push(Argument::Uint(word));
312 off += 4;
313 }
314
315 Ok((
316 WaylandMessage {
317 object_id: msg.object_id,
318 opcode: msg.opcode,
319 args,
320 },
321 total_size,
322 ))
323}
324
325pub fn parse_args(payload: &[u8], signature: &[u8]) -> Result<Vec<Argument>, WaylandError> {
332 let mut args = Vec::new();
333 let mut off: usize = 0;
334
335 for &ch in signature {
336 match ch {
337 b'i' => {
338 let v = read_i32(payload, off).ok_or(WaylandError::InvalidArgument)?;
339 args.push(Argument::Int(v));
340 off += 4;
341 }
342 b'u' => {
343 let v = read_u32(payload, off).ok_or(WaylandError::InvalidArgument)?;
344 args.push(Argument::Uint(v));
345 off += 4;
346 }
347 b'f' => {
348 let v = read_i32(payload, off).ok_or(WaylandError::InvalidArgument)?;
349 args.push(Argument::Fixed(v));
350 off += 4;
351 }
352 b's' => {
353 let len = read_u32(payload, off).ok_or(WaylandError::InvalidArgument)? as usize;
354 off += 4;
355 if off + len > payload.len() {
356 return Err(WaylandError::InvalidArgument);
357 }
358 let bytes = if len > 0 && payload[off + len - 1] == 0 {
360 payload[off..off + len - 1].to_vec()
361 } else if len == 0 {
362 Vec::new()
363 } else {
364 return Err(WaylandError::InvalidString);
365 };
366 args.push(Argument::String(bytes));
367 off += align4(len);
368 }
369 b'o' => {
370 let v = read_u32(payload, off).ok_or(WaylandError::InvalidArgument)?;
371 args.push(Argument::Object(v));
372 off += 4;
373 }
374 b'n' => {
375 let v = read_u32(payload, off).ok_or(WaylandError::InvalidArgument)?;
376 args.push(Argument::NewId(v));
377 off += 4;
378 }
379 b'a' => {
380 let len = read_u32(payload, off).ok_or(WaylandError::InvalidArgument)? as usize;
381 off += 4;
382 if off + len > payload.len() {
383 return Err(WaylandError::InvalidArgument);
384 }
385 let bytes = payload[off..off + len].to_vec();
386 args.push(Argument::Array(bytes));
387 off += align4(len);
388 }
389 b'h' => {
390 let v = read_i32(payload, off).ok_or(WaylandError::InvalidArgument)?;
391 args.push(Argument::Fd(v));
392 off += 4;
393 }
394 _ => return Err(WaylandError::InvalidArgument),
395 }
396 }
397 Ok(args)
398}
399
400pub fn serialize_message(msg: &WaylandMessage) -> Vec<u8> {
406 let mut arg_bytes = Vec::new();
408 for arg in &msg.args {
409 serialize_arg(&mut arg_bytes, arg);
410 }
411
412 let total_size = (HEADER_SIZE + arg_bytes.len()) as u16;
413
414 let mut out = Vec::with_capacity(total_size as usize);
415
416 out.extend_from_slice(&msg.object_id.to_ne_bytes());
418 let size_opcode = MessageHeader::encode(msg.opcode, total_size);
420 out.extend_from_slice(&size_opcode.to_ne_bytes());
421 out.extend_from_slice(&arg_bytes);
423
424 out
425}
426
427fn serialize_arg(buf: &mut Vec<u8>, arg: &Argument) {
429 match arg {
430 Argument::Int(v) => buf.extend_from_slice(&v.to_ne_bytes()),
431 Argument::Uint(v) => buf.extend_from_slice(&v.to_ne_bytes()),
432 Argument::Fixed(v) => buf.extend_from_slice(&v.to_ne_bytes()),
433 Argument::String(bytes) => {
434 let len_with_nul = bytes.len() + 1;
436 buf.extend_from_slice(&(len_with_nul as u32).to_ne_bytes());
437 buf.extend_from_slice(bytes);
438 buf.push(0); let padded = align4(len_with_nul);
441 for _ in len_with_nul..padded {
442 buf.push(0);
443 }
444 }
445 Argument::Object(v) => buf.extend_from_slice(&v.to_ne_bytes()),
446 Argument::NewId(v) => buf.extend_from_slice(&v.to_ne_bytes()),
447 Argument::Array(bytes) => {
448 buf.extend_from_slice(&(bytes.len() as u32).to_ne_bytes());
449 buf.extend_from_slice(bytes);
450 let padded = align4(bytes.len());
451 for _ in bytes.len()..padded {
452 buf.push(0);
453 }
454 }
455 Argument::Fd(v) => buf.extend_from_slice(&v.to_ne_bytes()),
456 }
457}
458
459pub fn build_display_error(object_id: u32, code: u32, message: &[u8]) -> Vec<u8> {
465 let msg = WaylandMessage::new(
466 WL_DISPLAY_ID,
467 WL_DISPLAY_ERROR,
468 vec![
469 Argument::Object(object_id),
470 Argument::Uint(code),
471 Argument::String(message.to_vec()),
472 ],
473 );
474 serialize_message(&msg)
475}
476
477pub fn build_display_delete_id(id: u32) -> Vec<u8> {
479 let msg = WaylandMessage::new(
480 WL_DISPLAY_ID,
481 WL_DISPLAY_DELETE_ID,
482 vec![Argument::Uint(id)],
483 );
484 serialize_message(&msg)
485}
486
487pub fn build_registry_global(
489 registry_id: u32,
490 name: u32,
491 interface: &[u8],
492 version: u32,
493) -> Vec<u8> {
494 let msg = WaylandMessage::new(
495 registry_id,
496 WL_REGISTRY_GLOBAL,
497 vec![
498 Argument::Uint(name),
499 Argument::String(interface.to_vec()),
500 Argument::Uint(version),
501 ],
502 );
503 serialize_message(&msg)
504}
505
506pub fn build_shm_format(shm_id: u32, format: u32) -> Vec<u8> {
508 let msg = WaylandMessage::new(shm_id, WL_SHM_FORMAT, vec![Argument::Uint(format)]);
509 serialize_message(&msg)
510}
511
512pub fn build_callback_done(callback_id: u32, serial: u32) -> Vec<u8> {
514 let msg = WaylandMessage::new(callback_id, 0, vec![Argument::Uint(serial)]);
515 serialize_message(&msg)
516}
517
518#[cfg(test)]
519mod tests {
520 use super::*;
521
522 #[test]
523 fn test_header_encode_decode() {
524 let opcode: u16 = 3;
525 let size: u16 = 24;
526 let combined = MessageHeader::encode(opcode, size);
527 let header = MessageHeader {
528 object_id: 7,
529 size_opcode: combined,
530 };
531 assert_eq!(header.opcode(), opcode);
532 assert_eq!(header.size(), size);
533 }
534
535 #[test]
536 fn test_roundtrip_simple_message() {
537 let msg = WaylandMessage::new(5, 2, vec![Argument::Uint(42), Argument::Int(-1)]);
538 let bytes = serialize_message(&msg);
539 let (parsed, consumed) = parse_message(&bytes).unwrap();
540 assert_eq!(consumed, bytes.len());
541 assert_eq!(parsed.object_id, 5);
542 assert_eq!(parsed.opcode, 2);
543 assert_eq!(parsed.args.len(), 2);
545 }
546
547 #[test]
548 fn test_parse_too_short() {
549 let data = [0u8; 4];
550 assert_eq!(
551 parse_message(&data).unwrap_err(),
552 WaylandError::MessageTooShort
553 );
554 }
555
556 #[test]
557 fn test_serialize_string_alignment() {
558 let msg = WaylandMessage::new(1, 0, vec![Argument::String(b"hi".to_vec())]);
559 let bytes = serialize_message(&msg);
560 assert_eq!(bytes.len(), 16);
562 }
563
564 #[test]
565 fn test_parse_args_string() {
566 let mut payload = Vec::new();
568 payload.extend_from_slice(&4u32.to_ne_bytes());
570 payload.extend_from_slice(b"abc\0");
571 let args = parse_args(&payload, b"s").unwrap();
572 assert_eq!(args.len(), 1);
573 if let Argument::String(s) = &args[0] {
574 assert_eq!(s, b"abc");
575 } else {
576 panic!("expected String argument");
577 }
578 }
579}