From 7369c5f813e69e409d67764335a3c923eef35d9c Mon Sep 17 00:00:00 2001 From: ProtoShark Date: Thu, 3 Apr 2025 13:38:12 -0700 Subject: [PATCH] Create and map shared memory pool with libc --- Cargo.lock | 9 +++++++ Cargo.toml | 1 + README.md | 1 + src/main.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++--- src/shm.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 README.md create mode 100644 src/shm.rs diff --git a/Cargo.lock b/Cargo.lock index 9a2927d..8ec32c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,12 @@ version = 4 [[package]] name = "ChloroStart-rs" version = "0.1.0" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" diff --git a/Cargo.toml b/Cargo.toml index f0aa9b2..5936432 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2024" [dependencies] +libc = "0.2" diff --git a/README.md b/README.md new file mode 100644 index 0000000..bf3a167 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +A wayland launcher built from scratch in rust diff --git a/src/main.rs b/src/main.rs index 9e76307..9655da5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,19 @@ -use std::{env, error::Error, io::{Read, Write}, os::unix::net::UnixStream, u32}; +#![feature(unix_socket_ancillary_data)] +use std::{env, error::Error, io::{Read, Write}, os::unix::net::{UnixStream, SocketAncillary, AncillaryData}, u32}; + +use shm::shm::ShmPool; +mod shm; struct WlState { socket: UnixStream, current_id: u32, registry_id: Option, - shm_id: Option + shm_id: Option, + shm_pool: Option } struct WlHeader { - object: u32,30334241 + object: u32, opcode: u16, size: u16 } @@ -171,6 +176,63 @@ fn wl_shm_format(event: &Vec) { println!("Received pixel format: {:x}", event.read_u32(&mut offset)); } +fn wl_shm_create_pool(wl_state: &mut WlState) -> Result<(), String> { + wl_state.current_id += 1; + wl_state.shm_pool = Some(match ShmPool::new(4096, wl_state.current_id) { + Ok(val) => val, + Err(err) => { + return Err(err.to_string()); + } + }); + + let object = match wl_state.shm_id { + Some(val) => val, + None => { + return Err("error in wl_shm_create_pool: shm_id not set!".to_string()); + } + }; + const OPCODE: u16 = 0; + const REQ_SIZE: u16 = 16; + let id = wl_state.shm_pool.as_ref().unwrap().id; + let fds = [wl_state.shm_pool.as_ref().unwrap().fd]; + let shm_size = wl_state.shm_pool.as_ref().unwrap().size; + + let mut request = vec![0u8; REQ_SIZE as usize]; + let mut offset: usize = 0; + + // Request header + request.write_u32(&object, &mut offset); + request.write_u16(&OPCODE, &mut offset); + request.write_u16(&REQ_SIZE, &mut offset); + + // Id, size of shm pool + request.write_u32(&id, &mut offset); + request.write_u32(&(shm_size as u32), &mut offset); + + println!("{:?}", request); + + let mut ancillary_buf = [0u8; 32]; + let mut ancillary = SocketAncillary::new(&mut ancillary_buf[..]); + assert!(ancillary.add_fds(&fds[..])); + + match wl_state.socket.send_vectored_with_ancillary(&[std::io::IoSlice::new(&request)], &mut ancillary) { + Ok(bytes) => { + assert!(bytes == REQ_SIZE as usize); + } + Err(err) => { + return Err(err.to_string()); + } + }; + + Ok(()) +} + +fn wl_shm_pool_resize(event: &Vec, wl_state: &mut WlState) -> std::io::Result<()> { + let mut offset: usize = 0; + let size = event.read_u32(&mut offset); + wl_state.shm_pool.as_mut().unwrap().resize(size as usize) +} + fn wl_registry_global(event: &Vec, wl_state: &mut WlState) -> Result<(), Box> { let mut offset: usize = 0; @@ -195,6 +257,7 @@ fn wl_registry_global(event: &Vec, wl_state: &mut WlState) -> Result<(), Box &wl_state.current_id.clone() )?; wl_state.shm_id = Some(wl_state.current_id); + wl_shm_create_pool(wl_state)?; } Ok(()) @@ -215,6 +278,7 @@ fn main() -> Result<(), Box> { current_id: 1, registry_id: None, shm_id: None, + shm_pool: None, }; wl_display_get_registry(&mut wl_state)?; @@ -243,6 +307,9 @@ fn main() -> Result<(), Box> { else if wl_state.shm_id.is_some() && header.object == wl_state.shm_id.unwrap() && header.opcode == 0 { // wl_shm::format wl_shm_format(&event); } + else if wl_state.shm_pool.is_some() && header.object == wl_state.shm_pool.as_ref().unwrap().id && header.opcode == 2 { + wl_shm_pool_resize(&event, &mut wl_state)?; + } else { println!( "Received event:\n\tObject: {}\n\tOpcode: {}\n\tSize: {}", diff --git a/src/shm.rs b/src/shm.rs new file mode 100644 index 0000000..4ecd3e8 --- /dev/null +++ b/src/shm.rs @@ -0,0 +1,62 @@ +pub mod shm { + + use libc::{c_void, ftruncate, mmap, munmap, shm_open, shm_unlink, MAP_FAILED, MAP_SHARED, O_CREAT, O_EXCL, O_RDWR, PROT_READ}; + + #[derive(Clone)] + pub struct ShmPool { + pub fd: i32, + pub id: u32, + pub addr: *mut c_void, + pub size: usize, + } + + impl ShmPool { + pub fn new(size: usize, id: u32) -> std::io::Result { + let shm_path: *const i8 = b"/chlorostart\0".as_ptr() as *const i8; + let fd = unsafe { shm_open(shm_path, O_RDWR | O_EXCL | O_CREAT, 0o600) }; + if fd == -1 { + eprint!("shm_open in ShmPool::new() failed: "); + return Err(std::io::Error::last_os_error()) + } + if unsafe { shm_unlink(shm_path) } == -1 { + eprint!("shm_unlink in ShmPool::new() failed: "); + return Err(std::io::Error::last_os_error()) + } + if unsafe { ftruncate(fd, size as i64) } == -1 { + eprint!("ftruncate in ShmPool::new() failed: "); + return Err(std::io::Error::last_os_error()) + } + let addr = unsafe { + mmap(std::ptr::null_mut(), size, PROT_READ | PROT_READ, MAP_SHARED, fd, 0) + }; + + if addr == MAP_FAILED { + eprint!("mmap in ShmPool::new() failed: "); + return Err(std::io::Error::last_os_error()) + } + + Ok(ShmPool { + fd, + id, + addr, + size + }) + } + + pub fn resize(&mut self, size: usize) -> std::io::Result<()> { + if unsafe { ftruncate(self.fd, size as i64) } == -1 { + return Err(std::io::Error::last_os_error()) + }; + self.size = size; + + Ok(()) + } + } + + impl Drop for ShmPool { + fn drop(&mut self) { + unsafe { munmap(self.addr, self.size); } + } + } + +}