From 5222f54eee6bc7e6b6e57f083f65196ad45d85c6 Mon Sep 17 00:00:00 2001 From: Ferdinand Schober Date: Mon, 30 Jan 2023 19:15:58 +0100 Subject: [PATCH] major refactor every instance of lan-mouse can now simultaneously send and receive events --- DOC.md | 30 +++ TODO | 2 + config.toml | 17 +- src/bin/client.rs | 147 ----------- src/client.rs | 57 +++++ src/config.rs | 2 +- src/dns.rs | 14 +- src/event.rs | 154 ++++++++++++ src/event/consumer.rs | 197 +++++++++++++++ src/{bin/server.rs => event/producer.rs} | 188 +++++++++----- src/event/server.rs | 119 +++++++++ src/lib.rs | 4 +- src/main.rs | 88 +++++++ src/protocol.rs | 302 ----------------------- src/request.rs | 130 ++++++++++ 15 files changed, 923 insertions(+), 528 deletions(-) create mode 100644 TODO delete mode 100644 src/bin/client.rs create mode 100644 src/client.rs create mode 100644 src/event.rs create mode 100644 src/event/consumer.rs rename src/{bin/server.rs => event/producer.rs} (67%) create mode 100644 src/event/server.rs create mode 100644 src/main.rs delete mode 100644 src/protocol.rs create mode 100644 src/request.rs diff --git a/DOC.md b/DOC.md index 461c61a..3aa93b7 100644 --- a/DOC.md +++ b/DOC.md @@ -51,3 +51,33 @@ sequenceDiagram Bob-->>-Alice: Ack (Keyboard Layout) ``` +## Problems +The general Idea is to have a bidirectional connection by default, meaning +any connected device can not only receive events but also send events back. + +This way when connecting e.g. a PC to a Laptop, either device can be used +to control the other. + +It needs to be ensured, that whenever a device is controlled the controlled +device does not transmit the events back to the original sender. +Otherwise events are multiplied and either one of the instances crashes. + +To keep the implementation of input backends simple this needs to be handled +on the server level. + +## Device State - Active and Inactive +To solve this problem, each device can be in exactly two states: + +Events can only be sent to active clients. +Events can only be received from inactive clients. + +Active denotes that a particular device is controlled by the local pc. + +Any event received from an active device is ignored unless it is a state change request. +In this case the device is marked as inactive and no further events are sent to the device. + +The received events are then processed until a further state change to active +is requested (when the corresponding layer surface is entered). + +**In short:** The invariance "each client either sends or receives events" must +always be true. diff --git a/TODO b/TODO new file mode 100644 index 0000000..c9ea4e5 --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +remove handle_to_addr / addr_to_handle functions from client_manager +instead mirror state in event server diff --git a/config.toml b/config.toml index deffd33..4f56ad4 100644 --- a/config.toml +++ b/config.toml @@ -1,10 +1,13 @@ port = 42069 -[client.left] -host_name = "rubinium" -ip = "192.168.2.182" -port = 42069 -[client.right] -host_name = "rubinium" -ip = "192.168.2.182" +# [client.right] +# host_name = "localhost" +# port = 42068 + +[client.left] +host_name = "Osmium" port = 42069 + +# [client.right] +# host_name = "Osmium" +# port = 42069 diff --git a/src/bin/client.rs b/src/bin/client.rs deleted file mode 100644 index 6d735e6..0000000 --- a/src/bin/client.rs +++ /dev/null @@ -1,147 +0,0 @@ -use lan_mouse::{ - config::Config, - protocol::{self, DataRequest}, -}; -use std::{ - io::{BufWriter, Write}, - os::unix::prelude::AsRawFd, -}; - -use wayland_protocols_wlr::virtual_pointer::v1::client::{ - zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1 as VpManager, - zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1 as Vp, -}; - -use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::{ - zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1 as VkManager, - zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1 as Vk, -}; - -use wayland_client::{ - delegate_noop, - globals::{registry_queue_init, GlobalListContents}, - protocol::{wl_keyboard, wl_pointer, wl_registry, wl_seat}, - Connection, Dispatch, EventQueue, QueueHandle, -}; - -use tempfile; - -// App State, implements Dispatch event handlers -struct App; - -fn main() { - let config = Config::new("config.toml").unwrap(); - let conn = Connection::connect_to_env().unwrap(); - let (globals, queue) = registry_queue_init::(&conn).unwrap(); - let qh = queue.handle(); - - let vpm: VpManager = globals.bind(&qh, 1..=1, ()).unwrap(); - let vkm: VkManager = globals.bind(&qh, 1..=1, ()).unwrap(); - let seat: wl_seat::WlSeat = globals.bind(&qh, 7..=8, ()).unwrap(); - - let pointer: Vp = vpm.create_virtual_pointer(None, &qh, ()); - let keyboard: Vk = vkm.create_virtual_keyboard(&seat, &qh, ()); - let connection = protocol::Connection::new(config); - let data = loop { - match connection.receive_data(DataRequest::KeyMap) { - Some(data) => break data, - None => {} - } - }; - // TODO use shm_open - let f = tempfile::tempfile().unwrap(); - let mut buf = BufWriter::new(&f); - buf.write_all(&data[..]).unwrap(); - buf.flush().unwrap(); - keyboard.keymap(1, f.as_raw_fd(), data.len() as u32); - loop { - receive_event(&connection, &pointer, &keyboard, &queue).unwrap(); - } -} - -/// main loop handling udp packets -fn receive_event( - connection: &protocol::Connection, - pointer: &Vp, - keyboard: &Vk, - q: &EventQueue, -) -> std::io::Result<()> { - let event = if let Some(event) = connection.receive_event() { - event - } else { - return Ok(()); - }; - match event { - protocol::Event::Pointer(e) => match e { - wl_pointer::Event::Motion { - time, - surface_x, - surface_y, - } => { - pointer.motion(time, surface_x, surface_y); - pointer.frame(); - } - wl_pointer::Event::Button { - serial: _, - time: t, - button: b, - state: s, - } => { - pointer.button(t, b, s.into_result().unwrap()); - pointer.frame(); - } - wl_pointer::Event::Axis { - time: t, - axis: a, - value: v, - } => { - pointer.axis(t, a.into_result().unwrap(), v); - pointer.frame(); - } - wl_pointer::Event::Frame => { - pointer.frame(); - } - _ => todo!(), - }, - protocol::Event::Keyboard(e) => match e { - wl_keyboard::Event::Key { - serial: _, - time: t, - key: k, - state: s, - } => { - keyboard.key(t, k, u32::from(s)); - } - wl_keyboard::Event::Modifiers { - serial: _, - mods_depressed, - mods_latched, - mods_locked, - group, - } => { - keyboard.modifiers(mods_depressed, mods_latched, mods_locked, group); - } - _ => todo!(), - }, - } - q.flush().unwrap(); - Ok(()) -} - -delegate_noop!(App: Vp); -delegate_noop!(App: Vk); -delegate_noop!(App: VpManager); -delegate_noop!(App: VkManager); -delegate_noop!(App: wl_seat::WlSeat); - -impl Dispatch for App { - fn event( - _: &mut App, - _: &wl_registry::WlRegistry, - _: wl_registry::Event, - _: &GlobalListContents, - _: &Connection, - _: &QueueHandle, - ) { - } -} diff --git a/src/client.rs b/src/client.rs new file mode 100644 index 0000000..896faab --- /dev/null +++ b/src/client.rs @@ -0,0 +1,57 @@ +use std::net::SocketAddr; + +#[derive(Eq, Hash, PartialEq, Clone, Copy)] +pub enum Position { + Left, Right, Top, Bottom, +} + +#[derive(Clone, Copy)] +pub struct Client { + pub addr: SocketAddr, + pub pos: Position, + pub handle: ClientHandle, +} + +impl Client { + pub fn handle(&self) -> ClientHandle { + return self.handle; + } +} + +pub enum ClientEvent { + Create(Client), + Destroy(Client), +} + +pub struct ClientManager { + next_id: u32, + clients: Vec, +} + +pub type ClientHandle = u32; + +impl ClientManager { + + fn new_id(&mut self) -> ClientHandle { + self.next_id += 1; + self.next_id + } + + pub fn new() -> Self { + ClientManager { + next_id: 0, + clients: Vec::new(), + } + } + + pub fn add_client(&mut self, addr: SocketAddr, pos: Position) { + let handle = self.new_id(); + let client = Client { addr, pos, handle }; + self.clients.push(client); + } + + pub fn get_clients(&self) -> Vec { + self.clients.clone() + } +} + diff --git a/src/config.rs b/src/config.rs index c7b3c8f..13f6f7d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,7 +17,7 @@ pub struct Clients { pub bottom: Option, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] pub struct Client { pub host_name: Option, pub ip: Option, diff --git a/src/dns.rs b/src/dns.rs index aa37bea..b26ea9a 100644 --- a/src/dns.rs +++ b/src/dns.rs @@ -10,14 +10,6 @@ struct DnsError { host: String, } -impl Error for InvalidConfigError {} - -impl Display for InvalidConfigError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "No hostname specified!") - } -} - impl Error for DnsError {} impl Display for DnsError { @@ -26,11 +18,7 @@ impl Display for DnsError { } } -pub fn resolve(host: &Option) -> Result> { - let host = match host { - Some(host) => host, - None => return Err(InvalidConfigError.into()), - }; +pub fn resolve(host: &String) -> Result> { let response = Resolver::from_system_conf()?.lookup_ip(host)?; match response.iter().next() { Some(ip) => Ok(ip), diff --git a/src/event.rs b/src/event.rs new file mode 100644 index 0000000..c7cfcca --- /dev/null +++ b/src/event.rs @@ -0,0 +1,154 @@ +pub mod producer; +pub mod consumer; +pub mod server; + +/* + * TODO: currently the wayland events are encoded + * directly with no generalized event format +*/ +use wayland_client::{protocol::{wl_pointer, wl_keyboard}, WEnum}; + +pub trait Encode { + fn encode(&self) -> Vec; +} + +pub trait Decode { + fn decode(buf: Vec) -> Self; +} + +impl Encode for wl_pointer::Event { + fn encode(&self) -> Vec { + let mut buf = Vec::new(); + match *self { + Self::Motion { + time: t, + surface_x: x, + surface_y: y, + } => { + buf.push(0u8); + buf.extend_from_slice(t.to_ne_bytes().as_ref()); + buf.extend_from_slice(x.to_ne_bytes().as_ref()); + buf.extend_from_slice(y.to_ne_bytes().as_ref()); + } + Self::Button { + serial: _, + time: t, + button: b, + state: s, + } => { + buf.push(1u8); + buf.extend_from_slice(t.to_ne_bytes().as_ref()); + buf.extend_from_slice(b.to_ne_bytes().as_ref()); + buf.push(u32::from(s) as u8); + } + Self::Axis { + time: t, + axis: a, + value: v, + } => { + buf.push(2u8); + buf.extend_from_slice(t.to_ne_bytes().as_ref()); + buf.push(u32::from(a) as u8); + buf.extend_from_slice(v.to_ne_bytes().as_ref()); + } + Self::Frame {} => { + buf.push(3u8); + } + _ => todo!(), + } + buf + } +} + +impl Encode for wl_keyboard::Event { + fn encode(&self) -> Vec { + let mut buf = Vec::new(); + match self { + Self::Key { + serial: _, + time: t, + key: k, + state: s, + } => { + buf.push(4u8); + buf.extend_from_slice(t.to_ne_bytes().as_ref()); + buf.extend_from_slice(k.to_ne_bytes().as_ref()); + buf.push(u32::from(*s) as u8); + } + Self::Modifiers { + serial: _, + mods_depressed, + mods_latched, + mods_locked, + group, + } => { + buf.push(5u8); + buf.extend_from_slice(mods_depressed.to_ne_bytes().as_ref()); + buf.extend_from_slice(mods_latched.to_ne_bytes().as_ref()); + buf.extend_from_slice(mods_locked.to_ne_bytes().as_ref()); + buf.extend_from_slice(group.to_ne_bytes().as_ref()); + } + _ => todo!(), + } + buf + } +} + +pub enum Event { + Pointer(wl_pointer::Event), + Keyboard(wl_keyboard::Event), + Release(), +} + +impl Encode for Event { + fn encode(&self) -> Vec { + match self { + Event::Pointer(p) => p.encode(), + Event::Keyboard(k) => k.encode(), + Event::Release() => vec![6u8], + } + } +} + +unsafe impl Send for Event {} +unsafe impl Sync for Event {} + +impl Decode for Event { + fn decode(buf: Vec) -> Self { + match buf[0] { + 0 => Self::Pointer(wl_pointer::Event::Motion { + time: u32::from_ne_bytes(buf[1..5].try_into().unwrap()), + surface_x: f64::from_ne_bytes(buf[5..13].try_into().unwrap()), + surface_y: f64::from_ne_bytes(buf[13..21].try_into().unwrap()), + }), + 1 => Self::Pointer(wl_pointer::Event::Button { + serial: 0, + time: (u32::from_ne_bytes(buf[1..5].try_into().unwrap())), + button: (u32::from_ne_bytes(buf[5..9].try_into().unwrap())), + state: (WEnum::Value(wl_pointer::ButtonState::try_from(buf[9] as u32).unwrap())), + }), + 2 => Self::Pointer(wl_pointer::Event::Axis { + time: (u32::from_ne_bytes(buf[1..5].try_into().unwrap())), + axis: (WEnum::Value(wl_pointer::Axis::try_from(buf[5] as u32).unwrap())), + value: (f64::from_ne_bytes(buf[6..14].try_into().unwrap())), + }), + 3 => Self::Pointer(wl_pointer::Event::Frame {}), + 4 => Self::Keyboard(wl_keyboard::Event::Key { + serial: 0, + time: u32::from_ne_bytes(buf[1..5].try_into().unwrap()), + key: u32::from_ne_bytes(buf[5..9].try_into().unwrap()), + state: WEnum::Value(wl_keyboard::KeyState::try_from(buf[9] as u32).unwrap()), + }), + 5 => Self::Keyboard(wl_keyboard::Event::Modifiers { + serial: 0, + mods_depressed: u32::from_ne_bytes(buf[1..5].try_into().unwrap()), + mods_latched: u32::from_ne_bytes(buf[5..9].try_into().unwrap()), + mods_locked: u32::from_ne_bytes(buf[9..13].try_into().unwrap()), + group: u32::from_ne_bytes(buf[13..17].try_into().unwrap()), + }), + 6 => Self::Release(), + _ => panic!("protocol violation"), + } + } +} + diff --git a/src/event/consumer.rs b/src/event/consumer.rs new file mode 100644 index 0000000..32356cb --- /dev/null +++ b/src/event/consumer.rs @@ -0,0 +1,197 @@ +use crate::client::{Client, ClientHandle}; +use crate::request::{self, Request}; +use std::collections::HashMap; +use std::time::Duration; +use std::{io, thread}; +use std::sync::mpsc::Receiver; +use std::{ + io::{BufWriter, Write}, + os::unix::prelude::AsRawFd, +}; + +use wayland_protocols_wlr::virtual_pointer::v1::client::{ + zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1 as VpManager, + zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1 as Vp, +}; + +use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::{ + zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1 as VkManager, + zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1 as Vk, +}; + +use wayland_client::{ + delegate_noop, + globals::{registry_queue_init, GlobalListContents}, + protocol::{wl_keyboard, wl_pointer, wl_registry, wl_seat}, + Connection, Dispatch, EventQueue, QueueHandle, +}; + +use tempfile; + +use super::Event; + +// App State, implements Dispatch event handlers +struct App { + input_for_client: HashMap, + seat: wl_seat::WlSeat, + event_rx: Receiver<(Event, ClientHandle)>, + vpm: VpManager, + vkm: VkManager, + queue: EventQueue, + qh: QueueHandle, +} + +pub fn run(event_rx: Receiver<(Event, ClientHandle)>, clients: Vec) { + let mut app = App::new(event_rx, clients); + app.run(); +} + +impl App { + pub fn new(event_rx: Receiver<(Event, ClientHandle)>, clients: Vec) -> Self { + let conn = Connection::connect_to_env().unwrap(); + let (globals, queue) = registry_queue_init::(&conn).unwrap(); + let qh = queue.handle(); + + let vpm: VpManager = globals.bind(&qh, 1..=1, ()).expect("zwlr_virtual_pointer_manager_v1 protocol is required to emulate mouse input"); + let vkm: VkManager = globals.bind(&qh, 1..=1, ()).expect("zwp_virtual_keyboard_manager_v1 protocol is required to emulate keyboard input"); + let input_for_client: HashMap = HashMap::new(); + let seat: wl_seat::WlSeat = globals.bind(&qh, 7..=8, ()).unwrap(); + let mut app = App { input_for_client, seat, event_rx, vpm, vkm, queue, qh }; + for client in clients { + app.add_client(client); + } + app + } + + pub fn run(&mut self) { + loop { + let (event, client) = self.event_rx.recv().unwrap(); + if let Some(virtual_input) = self.input_for_client.get(&client) { + virtual_input.consume_event(event).unwrap(); + if let Err(e) = self.queue.flush() { + eprintln!("{}", e); + } + } + } + } + + fn add_client(&mut self, client: Client) { + + // create virtual input devices + let pointer: Vp = self.vpm.create_virtual_pointer(None, &self.qh, ()); + let keyboard: Vk = self.vkm.create_virtual_keyboard(&self.seat, &self.qh, ()); + + // receive keymap from device + eprintln!("connecting to {}", client.addr); + + let data = loop { + match request::request_data(client.addr, Request::KeyMap) { + Some(data) => break data, + None => { + eprint!("."); + io::stderr().flush().unwrap(); + thread::sleep(Duration::from_millis(500)); + } + } + }; + + // TODO use shm_open + let f = tempfile::tempfile().unwrap(); + let mut buf = BufWriter::new(&f); + buf.write_all(&data[..]).unwrap(); + buf.flush().unwrap(); + keyboard.keymap(1, f.as_raw_fd(), data.len() as u32); + + let vinput = VirtualInput { pointer, keyboard }; + + self.input_for_client.insert(client.handle, vinput); + } + +} + +struct VirtualInput { + pointer: Vp, + keyboard: Vk, +} + +impl VirtualInput { +/// main loop handling udp packets + fn consume_event(&self, event: Event) -> std::io::Result<()> { + match event { + Event::Pointer(e) => match e { + wl_pointer::Event::Motion { + time, + surface_x, + surface_y, + } => { + self.pointer.motion(time, surface_x, surface_y); + self.pointer.frame(); + } + wl_pointer::Event::Button { + serial: _, + time: t, + button: b, + state: s, + } => { + self.pointer.button(t, b, s.into_result().unwrap()); + self.pointer.frame(); + } + wl_pointer::Event::Axis { + time: t, + axis: a, + value: v, + } => { + self.pointer.axis(t, a.into_result().unwrap(), v); + self.pointer.frame(); + } + wl_pointer::Event::Frame => { + self.pointer.frame(); + } + _ => todo!(), + }, + Event::Keyboard(e) => match e { + wl_keyboard::Event::Key { + serial: _, + time: t, + key: k, + state: s, + } => { + self.keyboard.key(t, k, u32::from(s)); + } + wl_keyboard::Event::Modifiers { + serial: _, + mods_depressed, + mods_latched, + mods_locked, + group, + } => { + self.keyboard.modifiers(mods_depressed, mods_latched, mods_locked, group); + } + _ => todo!(), + }, + Event::Release() => { + self.keyboard.modifiers(77, 0, 0, 0); + self.keyboard.modifiers(0, 0, 0, 0); + } + } + Ok(()) + } +} + +delegate_noop!(App: Vp); +delegate_noop!(App: Vk); +delegate_noop!(App: VpManager); +delegate_noop!(App: VkManager); +delegate_noop!(App: wl_seat::WlSeat); + +impl Dispatch for App { + fn event( + _: &mut App, + _: &wl_registry::WlRegistry, + _: wl_registry::Event, + _: &GlobalListContents, + _: &Connection, + _: &QueueHandle, + ) { + } +} diff --git a/src/bin/server.rs b/src/event/producer.rs similarity index 67% rename from src/bin/server.rs rename to src/event/producer.rs index 7f34255..c7c71a4 100644 --- a/src/bin/server.rs +++ b/src/event/producer.rs @@ -1,10 +1,11 @@ -use lan_mouse::protocol; +use crate::{request, client::{ClientHandle, Position, Client}}; + use memmap::Mmap; use std::{ fs::File, io::{BufWriter, Write}, - os::unix::prelude::{AsRawFd, FromRawFd}, + os::unix::prelude::{AsRawFd, FromRawFd}, sync::mpsc::SyncSender, rc::Rc, }; use wayland_protocols::wp::{ @@ -39,6 +40,8 @@ use wayland_client::{ use tempfile; +use super::Event; + struct Globals { compositor: wl_compositor::WlCompositor, pointer_constraints: ZwpPointerConstraintsV1, @@ -51,19 +54,15 @@ struct Globals { struct App { running: bool, - windows: Windows, pointer_lock: Option, rel_pointer: Option, shortcut_inhibitor: Option, - connection: protocol::Connection, + client_for_window: Vec<(Rc, ClientHandle)>, + focused: Option<(Rc, ClientHandle)>, g: Globals, -} - -struct Windows { - _left: Option, - right: Option, - _top: Option, - _bottom: Option, + tx: SyncSender<(Event, ClientHandle)>, + server: request::Server, + qh: QueueHandle, } struct Window { @@ -73,34 +72,40 @@ struct Window { } impl Window { - fn new(g: &Globals, qh: QueueHandle) -> Window { + fn new(g: &Globals, qh: &QueueHandle, pos: Position) -> Window { let (width, height) = (1, 1440); let mut file = tempfile::tempfile().unwrap(); draw(&mut file, (width, height)); let pool = g .shm - .create_pool(file.as_raw_fd(), (width * height * 4) as i32, &qh, ()); + .create_pool(file.as_raw_fd(), (width * height * 4) as i32, qh, ()); let buffer = pool.create_buffer( 0, width as i32, height as i32, (width * 4) as i32, wl_shm::Format::Argb8888, - &qh, + qh, (), ); - let surface = g.compositor.create_surface(&qh, ()); + let surface = g.compositor.create_surface(qh, ()); let layer_surface = g.layer_shell.get_layer_surface( &surface, None, Layer::Top, "LAN Mouse Sharing".into(), - &qh, + qh, (), ); + let anchor = match pos { + Position::Left => Anchor::Left, + Position::Right => Anchor::Right, + Position::Top => Anchor::Top, + Position::Bottom => Anchor::Bottom, + }; - layer_surface.set_anchor(Anchor::Right); + layer_surface.set_anchor(anchor); layer_surface.set_size(1, 1440); layer_surface.set_exclusive_zone(0); layer_surface.set_margin(0, 0, 0, 0); @@ -114,9 +119,11 @@ impl Window { } } -fn main() { - let config = lan_mouse::config::Config::new("config.toml").unwrap(); - let connection = protocol::Connection::new(config); +pub fn run( + tx: SyncSender<(Event, ClientHandle)>, + server: request::Server, + clients: Vec, +) { let conn = Connection::connect_to_env().expect("could not connect to wayland compositor"); let (g, mut queue) = registry_queue_init::(&conn).expect("failed to initialize wl_registry"); let qh = queue.handle(); @@ -129,7 +136,7 @@ fn main() { .expect("wl_shm v1 not supported"); let layer_shell: ZwlrLayerShellV1 = g .bind(&qh, 3..=4, ()) - .expect("zwlr_layer_shell_v1 >= v3 not supported"); + .expect("zwlr_layer_shell_v1 >= v3 not supported - required to display a surface at the edge of the screen"); let seat: wl_seat::WlSeat = g .bind(&qh, 7..=8, ()) .expect("wl_seat >= v7 not supported"); @@ -153,23 +160,25 @@ fn main() { shortcut_inhibit_manager, }; - let windows: Windows = Windows { - _left: None, - right: Some(Window::new(&g, qh)), - _top: None, - _bottom: None, - }; + let client_for_window = Vec::new(); let mut app = App { running: true, g, - windows, pointer_lock: None, rel_pointer: None, shortcut_inhibitor: None, - connection, + client_for_window, + focused: None, + tx, + server, + qh, }; + for client in clients { + app.add_client(client.handle, client.pos); + } + while app.running { queue.blocking_dispatch(&mut app).unwrap(); } @@ -185,15 +194,27 @@ fn draw(f: &mut File, (width, height): (u32, u32)) { } impl App { - fn grab(&mut self, pointer: &wl_pointer::WlPointer, serial: u32, qh: &QueueHandle) { + + fn grab( + &mut self, + surface: &wl_surface::WlSurface, + pointer: &wl_pointer::WlPointer, + serial: u32, + qh: &QueueHandle + ) { + let (window, _) = self.focused.as_ref().unwrap(); + + // hide the cursor pointer.set_cursor(serial, None, 0, 0); - let layer_surface = &self.windows.right.as_ref().unwrap().layer_surface; - layer_surface.set_keyboard_interactivity(KeyboardInteractivity::Exclusive); - let surface = &self.windows.right.as_ref().unwrap().surface; - surface.commit(); + + // capture input + window.layer_surface.set_keyboard_interactivity(KeyboardInteractivity::Exclusive); + window.surface.commit(); + + // lock pointer if self.pointer_lock.is_none() { self.pointer_lock = Some(self.g.pointer_constraints.lock_pointer( - &surface, + surface, pointer, None, Lifetime::Oneshot, @@ -201,6 +222,8 @@ impl App { (), )); } + + // request relative input if self.rel_pointer.is_none() { self.rel_pointer = Some(self.g.relative_pointer_manager.get_relative_pointer( pointer, @@ -208,9 +231,11 @@ impl App { (), )); } + + // capture modifier keys if self.shortcut_inhibitor.is_none() { self.shortcut_inhibitor = Some(self.g.shortcut_inhibit_manager.inhibit_shortcuts( - &surface, + surface, &self.g.seat, qh, (), @@ -219,23 +244,36 @@ impl App { } fn ungrab(&mut self) { - let layer_surface = &self.windows.right.as_ref().unwrap().layer_surface; - layer_surface.set_keyboard_interactivity(KeyboardInteractivity::None); - let surface = &self.windows.right.as_ref().unwrap().surface; - surface.commit(); + // get focused client + let (window, _client) = self.focused.as_ref().unwrap(); + + // ungrab surface + window.layer_surface.set_keyboard_interactivity(KeyboardInteractivity::None); + window.surface.commit(); + + // release pointer if let Some(pointer_lock) = &self.pointer_lock { pointer_lock.destroy(); self.pointer_lock = None; } + + // destroy relative input if let Some(rel_pointer) = &self.rel_pointer { rel_pointer.destroy(); self.rel_pointer = None; } + + // release shortcut inhibitor if let Some(shortcut_inhibitor) = &self.shortcut_inhibitor { shortcut_inhibitor.destroy(); self.shortcut_inhibitor = None; } } + + fn add_client(&mut self, client: ClientHandle, pos: Position) { + let window = Rc::new(Window::new(&self.g, &self.qh, pos)); + self.client_for_window.push((window, client)); + } } impl Dispatch for App { @@ -273,23 +311,40 @@ impl Dispatch for App { match event { wl_pointer::Event::Enter { serial, - surface: _, + surface, surface_x: _, surface_y: _, } => { - app.grab(pointer, serial, qh); + // get client corresponding to the focused surface + + { + let (window, client) = app.client_for_window + .iter() + .find(|(w,_c)| w.surface == surface) + .unwrap(); + app.focused = Some((window.clone(), *client)); + app.grab(&surface, pointer, serial.clone(), qh); + } + let (_, client) = app.client_for_window + .iter() + .find(|(w,_c)| w.surface == surface) + .unwrap(); + app.tx.send((Event::Release(), *client)).unwrap(); } wl_pointer::Event::Leave { .. } => { app.ungrab(); } wl_pointer::Event::Button { .. } => { - app.connection.send_event(event); + let (_, client) = app.focused.as_ref().unwrap(); + app.tx.send((Event::Pointer(event), *client)).unwrap(); } wl_pointer::Event::Axis { .. } => { - app.connection.send_event(event); + let (_, client) = app.focused.as_ref().unwrap(); + app.tx.send((Event::Pointer(event), *client)).unwrap(); } wl_pointer::Event::Frame { .. } => { - app.connection.send_event(event); + let (_, client) = app.focused.as_ref().unwrap(); + app.tx.send((Event::Pointer(event), *client)).unwrap(); } _ => {} } @@ -305,12 +360,20 @@ impl Dispatch for App { _: &Connection, _: &QueueHandle, ) { + let (_window, client) = match &app.focused { + Some(focused) => (Some(&focused.0), Some(&focused.1)), + None => (None, None), + }; match event { wl_keyboard::Event::Key { .. } => { - app.connection.send_event(event); + if let Some(client) = client { + app.tx.send((Event::Keyboard(event), *client)).unwrap(); + } } wl_keyboard::Event::Modifiers { mods_depressed, .. } => { - app.connection.send_event(event); + if let Some(client) = client { + app.tx.send((Event::Keyboard(event), *client)).unwrap(); + } if mods_depressed == 77 { // ctrl shift super alt app.ungrab(); @@ -322,8 +385,7 @@ impl Dispatch for App { size: _, } => { let mmap = unsafe { Mmap::map(&File::from_raw_fd(fd.as_raw_fd())).unwrap() }; - app.connection - .offer_data(protocol::DataRequest::KeyMap, mmap); + app.server.offer_data(request::Request::KeyMap, mmap); } _ => (), } @@ -348,12 +410,18 @@ impl Dispatch for App { dy_unaccel: surface_y, } = event { - let time = (((utime_hi as u64) << 32 | utime_lo as u64) / 1000) as u32; - app.connection.send_event(wl_pointer::Event::Motion { - time, - surface_x, - surface_y, - }); + if let Some((_window, client)) = &app.focused { + let time = (((utime_hi as u64) << 32 | utime_lo as u64) / 1000) as u32; + app.tx.send(( + Event::Pointer(wl_pointer::Event::Motion { + time, + surface_x, + surface_y, + }), + *client, + )).unwrap(); + + } } } } @@ -368,10 +436,16 @@ impl Dispatch for App { _: &QueueHandle, ) { if let zwlr_layer_surface_v1::Event::Configure { serial, .. } = event { - let surface = &app.windows.right.as_ref().unwrap().surface; + let (window, _client) = app.client_for_window + .iter() + .find(|(w,_c)| &w.layer_surface == layer_surface) + .unwrap(); + // client corresponding to the layer_surface + let surface = &window.surface; + let buffer = &window.buffer; surface.commit(); layer_surface.ack_configure(serial); - surface.attach(Some(&app.windows.right.as_ref().unwrap().buffer), 0, 0); + surface.attach(Some(&buffer), 0, 0); surface.commit(); } } diff --git a/src/event/server.rs b/src/event/server.rs new file mode 100644 index 0000000..3eeb3e2 --- /dev/null +++ b/src/event/server.rs @@ -0,0 +1,119 @@ +use std::{ + net::{UdpSocket, SocketAddr}, + error::Error, + sync::{mpsc::{SyncSender, Receiver}, atomic::{AtomicBool, Ordering}, Arc}, + thread::{self, JoinHandle}, collections::HashMap, +}; + +use crate::client::{ClientHandle, ClientManager}; + +use super::{Event, Encode, Decode}; + +pub struct Server { + listen_addr: SocketAddr, + sending: Arc, +} + +impl Server { + pub fn new(port: u16) -> Self { + let listen_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), port); + let sending = Arc::new(AtomicBool::new(false)); + Server { listen_addr, sending } + } + + pub fn run(self, client_manager: &mut ClientManager, produce_rx: Receiver<(Event, ClientHandle)>, consume_tx: SyncSender<(Event, ClientHandle)>) -> Result<(JoinHandle<()>, JoinHandle<()>), Box> { + let udp_socket = UdpSocket::bind(self.listen_addr)?; + let rx = udp_socket.try_clone().unwrap(); + let tx = udp_socket; + + let sending = self.sending.clone(); + + let mut client_for_socket = HashMap::new(); + for client in client_manager.get_clients() { + println!("{}: {}", client.handle, client.addr); + client_for_socket.insert(client.addr, client.handle); + } + let receiver = thread::Builder::new().name("event receiver".into()).spawn(move || { + loop { + let (event, addr) = match Server::receive_event(&rx) { + Some(e) => e, + None => { continue }, + }; + + let client_handle = match client_for_socket.get(&addr) { + Some(c) => *c, + None => { + println!("Allow connection from {:?}? [Y/n]", addr); + continue + }, + }; + + // There is a race condition between loading this + // value and handling the event: + // In the meantime a event could be produced, which + // should theoretically disable receiving of events. + // + // This is however not a huge problem, as some + // events that make it through are not a large problem + if sending.load(Ordering::Acquire) { + // ignore received events when in sending state + // if release event is received, switch state to receiving + if let Event::Release() = event { + sending.store(false, Ordering::Release); + consume_tx.send((event, client_handle)).expect("event consumer unavailable"); + } + } else { + if let Event::Release() = event { + sending.store(false, Ordering::Release); + } + // we retrieve all events + consume_tx.send((event, client_handle)).expect("event consumer unavailable"); + } + } + }).unwrap(); + + let sending = self.sending.clone(); + + let mut socket_for_client = HashMap::new(); + for client in client_manager.get_clients() { + socket_for_client.insert(client.handle, client.addr); + } + let sender = thread::Builder::new().name("event sender".into()).spawn(move || { + loop { + let (event, client_handle) = produce_rx.recv().expect("event producer unavailable"); + let addr = match socket_for_client.get(&client_handle) { + Some(addr) => addr, + None => continue, + }; + + if sending.load(Ordering::Acquire) { + Server::send_event(&tx, event, *addr); + } else { + // only accept enter event + if let Event::Release() = event { + // set state to sending, to ignore incoming events + // and enable sending of events + sending.store(true, Ordering::Release); + Server::send_event(&tx, event, *addr); + } + } + } + }).unwrap(); + Ok((receiver, sender)) + } + + fn send_event(tx: &UdpSocket, e: E, addr: SocketAddr) { + if let Err(e) = tx.send_to(&e.encode(), addr) { + eprintln!("{}", e); + } + } + + fn receive_event(rx: &UdpSocket) -> Option<(Event, SocketAddr)> { + let mut buf = vec![0u8; 21]; + if let Ok((_amt, src)) = rx.recv_from(&mut buf) { + Some((Event::decode(buf), src)) + } else { + None + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 75ade56..ae9b9bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ pub mod config; pub mod dns; -pub mod protocol; +pub mod event; +pub mod request; +pub mod client; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..4d0ad55 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,88 @@ +use std::{sync::mpsc, thread, net::SocketAddr}; + +use lan_mouse::{ + event::{self, producer, consumer}, + config, + request, + client::{ClientManager, Position}, dns, +}; + +fn add_client(client_manager: &mut ClientManager, client: &config::Client, pos: Position) { + let ip = match client.ip { + Some(ip) => ip, + None => match &client.host_name { + Some(host_name) => match dns::resolve(host_name) { + Ok(ip) => ip, + Err(e) => panic!("{}", e), + }, + None => panic!("neither ip nor hostname specified"), + } + }; + let addr = SocketAddr::new(ip, client.port.unwrap_or(42069)); + client_manager.add_client(addr, pos); +} + +pub fn main() { + // parse config file + let config = config::Config::new("config.toml").unwrap(); + + // port or default + let port = config.port.unwrap_or(42069); + + // event channel for producing events + let (produce_tx, produce_rx) = mpsc::sync_channel(128); + + // event channel for consuming events + let (consume_tx, consume_rx) = mpsc::sync_channel(128); + + let mut client_manager = ClientManager::new(); + + // add clients from config + for client in vec![ + &config.client.left, + &config.client.right, + &config.client.top, + &config.client.bottom, + ] { + if let Some(client) = client { + let pos = match client { + client if Some(client) == config.client.left.as_ref() => Position::Left, + client if Some(client) == config.client.right.as_ref() => Position::Right, + client if Some(client) == config.client.top.as_ref() => Position::Top, + client if Some(client) == config.client.bottom.as_ref() => Position::Bottom, + _ => panic!(), + }; + add_client(&mut client_manager, client, pos); + } + } + + // start receiving client connection requests + let (request_server, request_thread) = request::Server::listen(port).unwrap(); + + let clients = client_manager.get_clients(); + // start producing and consuming events + let event_producer = thread::Builder::new() + .name("event producer".into()) + .spawn(|| { + producer::run(produce_tx, request_server, clients); + }).unwrap(); + + let clients = client_manager.get_clients(); + let event_consumer = thread::Builder::new() + .name("event consumer".into()) + .spawn(|| { + consumer::run(consume_rx, clients); + }).unwrap(); + + // start sending and receiving events + let event_server = event::server::Server::new(port); + let (receiver, sender) = event_server.run(&mut client_manager, produce_rx, consume_tx).unwrap(); + + request_thread.join().unwrap(); + + receiver.join().unwrap(); + sender.join().unwrap(); + + event_producer.join().unwrap(); + event_consumer.join().unwrap(); +} diff --git a/src/protocol.rs b/src/protocol.rs deleted file mode 100644 index b81d6a2..0000000 --- a/src/protocol.rs +++ /dev/null @@ -1,302 +0,0 @@ -use crate::config::{self, Config}; -use crate::dns; -use memmap::Mmap; -use std::{ - collections::HashMap, - io::prelude::*, - net::TcpListener, - process::exit, - sync::{Arc, RwLock}, - thread, -}; - -use wayland_client::{ - protocol::{wl_keyboard, wl_pointer}, - WEnum, -}; - -use std::net::{SocketAddr, TcpStream, UdpSocket}; - -trait Resolve { - fn resolve(&self) -> Option; -} - -impl Resolve for Option { - fn resolve(&self) -> Option { - let client = match self { - Some(client) => client, - None => return None, - }; - let ip = match client.ip { - Some(ip) => ip, - None => dns::resolve(&client.host_name).unwrap(), - }; - Some(SocketAddr::new(ip, client.port.unwrap_or(42069))) - } -} - -struct ClientAddrs { - left: Option, - right: Option, - _top: Option, - _bottom: Option, -} - -pub struct Connection { - udp_socket: UdpSocket, - client: ClientAddrs, - offer_data: Arc>>, -} - -pub trait Encode { - fn encode(&self) -> Vec; -} - -pub trait Decode { - fn decode(buf: Vec) -> Self; -} - -impl Encode for wl_pointer::Event { - fn encode(&self) -> Vec { - let mut buf = Vec::new(); - match *self { - Self::Motion { - time: t, - surface_x: x, - surface_y: y, - } => { - buf.push(0u8); - buf.extend_from_slice(t.to_ne_bytes().as_ref()); - buf.extend_from_slice(x.to_ne_bytes().as_ref()); - buf.extend_from_slice(y.to_ne_bytes().as_ref()); - } - Self::Button { - serial: _, - time: t, - button: b, - state: s, - } => { - buf.push(1u8); - buf.extend_from_slice(t.to_ne_bytes().as_ref()); - buf.extend_from_slice(b.to_ne_bytes().as_ref()); - buf.push(u32::from(s) as u8); - } - Self::Axis { - time: t, - axis: a, - value: v, - } => { - buf.push(2u8); - buf.extend_from_slice(t.to_ne_bytes().as_ref()); - buf.push(u32::from(a) as u8); - buf.extend_from_slice(v.to_ne_bytes().as_ref()); - } - Self::Frame {} => { - buf.push(3u8); - } - _ => todo!(), - } - buf - } -} - -impl Encode for wl_keyboard::Event { - fn encode(&self) -> Vec { - let mut buf = Vec::new(); - match self { - Self::Key { - serial: _, - time: t, - key: k, - state: s, - } => { - buf.push(4u8); - buf.extend_from_slice(t.to_ne_bytes().as_ref()); - buf.extend_from_slice(k.to_ne_bytes().as_ref()); - buf.push(u32::from(*s) as u8); - } - Self::Modifiers { - serial: _, - mods_depressed, - mods_latched, - mods_locked, - group, - } => { - buf.push(5u8); - buf.extend_from_slice(mods_depressed.to_ne_bytes().as_ref()); - buf.extend_from_slice(mods_latched.to_ne_bytes().as_ref()); - buf.extend_from_slice(mods_locked.to_ne_bytes().as_ref()); - buf.extend_from_slice(group.to_ne_bytes().as_ref()); - } - _ => todo!(), - } - buf - } -} - -pub enum Event { - Pointer(wl_pointer::Event), - Keyboard(wl_keyboard::Event), -} - -impl Decode for Event { - fn decode(buf: Vec) -> Self { - match buf[0] { - 0 => Self::Pointer(wl_pointer::Event::Motion { - time: u32::from_ne_bytes(buf[1..5].try_into().unwrap()), - surface_x: f64::from_ne_bytes(buf[5..13].try_into().unwrap()), - surface_y: f64::from_ne_bytes(buf[13..21].try_into().unwrap()), - }), - 1 => Self::Pointer(wl_pointer::Event::Button { - serial: 0, - time: (u32::from_ne_bytes(buf[1..5].try_into().unwrap())), - button: (u32::from_ne_bytes(buf[5..9].try_into().unwrap())), - state: (WEnum::Value(wl_pointer::ButtonState::try_from(buf[9] as u32).unwrap())), - }), - 2 => Self::Pointer(wl_pointer::Event::Axis { - time: (u32::from_ne_bytes(buf[1..5].try_into().unwrap())), - axis: (WEnum::Value(wl_pointer::Axis::try_from(buf[5] as u32).unwrap())), - value: (f64::from_ne_bytes(buf[6..14].try_into().unwrap())), - }), - 3 => Self::Pointer(wl_pointer::Event::Frame {}), - 4 => Self::Keyboard(wl_keyboard::Event::Key { - serial: 0, - time: u32::from_ne_bytes(buf[1..5].try_into().unwrap()), - key: u32::from_ne_bytes(buf[5..9].try_into().unwrap()), - state: WEnum::Value(wl_keyboard::KeyState::try_from(buf[9] as u32).unwrap()), - }), - 5 => Self::Keyboard(wl_keyboard::Event::Modifiers { - serial: 0, - mods_depressed: u32::from_ne_bytes(buf[1..5].try_into().unwrap()), - mods_latched: u32::from_ne_bytes(buf[5..9].try_into().unwrap()), - mods_locked: u32::from_ne_bytes(buf[9..13].try_into().unwrap()), - group: u32::from_ne_bytes(buf[13..17].try_into().unwrap()), - }), - _ => panic!("protocol violation"), - } - } -} - -#[derive(PartialEq, Eq, Hash)] -pub enum DataRequest { - KeyMap, -} - -impl From for DataRequest { - fn from(idx: u32) -> Self { - match idx { - 0 => Self::KeyMap, - _ => panic!("invalid enum value"), - } - } -} - -impl From<[u8; 4]> for DataRequest { - fn from(buf: [u8; 4]) -> Self { - DataRequest::from(u32::from_ne_bytes(buf)) - } -} - -impl From for u32 { - fn from(d: DataRequest) -> Self { - match d { - DataRequest::KeyMap => 0, - } - } -} - -fn handle_request(data: &Arc>>, mut stream: TcpStream) { - let mut buf = [0u8; 4]; - stream.read_exact(&mut buf).unwrap(); - match DataRequest::from(buf) { - DataRequest::KeyMap => { - let data = data.read().unwrap(); - let buf = data.get(&DataRequest::KeyMap); - match buf { - None => { - stream.write(&0u32.to_ne_bytes()).unwrap(); - } - Some(buf) => { - stream.write(&buf[..].len().to_ne_bytes()).unwrap(); - stream.write(&buf[..]).unwrap(); - } - } - stream.flush().unwrap(); - } - } -} - -impl Connection { - pub fn new(config: Config) -> Connection { - let clients = ClientAddrs { - left: config.client.left.resolve(), - right: config.client.right.resolve(), - _top: config.client.top.resolve(), - _bottom: config.client.bottom.resolve(), - }; - let data: Arc>> = Arc::new(RwLock::new(HashMap::new())); - let thread_data = data.clone(); - let port = config.port.unwrap_or(42069); - let listen_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), port); - thread::spawn(move || { - let sock = TcpListener::bind(listen_addr).unwrap(); - for stream in sock.incoming() { - if let Ok(stream) = stream { - handle_request(&thread_data, stream); - } - } - }); - let sock = UdpSocket::bind(listen_addr); - let sock = match sock { - Ok(sock) => sock, - Err(e) => match e.kind() { - std::io::ErrorKind::AddrInUse => { - eprintln!("Server already running on port {}", port); - exit(1); - } - _ => panic!("{}", e), - }, - }; - let c = Connection { - udp_socket: sock, - client: clients, - offer_data: data, - }; - c - } - - pub fn offer_data(&self, req: DataRequest, d: Mmap) { - self.offer_data.write().unwrap().insert(req, d); - } - - pub fn receive_data(&self, req: DataRequest) -> Option> { - let mut sock = TcpStream::connect(self.client.left.unwrap()).unwrap(); - sock.write(&u32::from(req).to_ne_bytes()).unwrap(); - sock.flush().unwrap(); - let mut buf = [0u8; 8]; - sock.read_exact(&mut buf[..]).unwrap(); - let len = usize::from_ne_bytes(buf); - if len == 0 { - return None; - } - let mut data: Vec = vec![0u8; len]; - sock.read_exact(&mut data[..]).unwrap(); - Some(data) - } - - pub fn send_event(&self, e: E) { - // TODO check which client - if let Some(addr) = self.client.right { - self.udp_socket.send_to(&e.encode(), addr).unwrap(); - } - } - - pub fn receive_event(&self) -> Option { - let mut buf = vec![0u8; 21]; - if let Ok((_amt, _src)) = self.udp_socket.recv_from(&mut buf) { - Some(Event::decode(buf)) - } else { - None - } - } -} diff --git a/src/request.rs b/src/request.rs new file mode 100644 index 0000000..b90cbb8 --- /dev/null +++ b/src/request.rs @@ -0,0 +1,130 @@ +use std::{ + net::{TcpListener, SocketAddr, TcpStream}, + io::prelude::*, + collections::HashMap, sync::{RwLock, Arc}, + error::Error, + thread::{self, JoinHandle}, +}; + +use memmap::Mmap; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub enum Request { + KeyMap, + Connect, +} + +impl TryFrom<[u8; 4]> for Request { + fn try_from(buf: [u8; 4]) -> Result { + let val = u32::from_ne_bytes(buf); + match val { + x if x == Request::KeyMap as u32 => Ok(Self::KeyMap), + x if x == Request::Connect as u32 => Ok(Self::Connect), + _ => Err("Bad Request"), + } + } + + type Error = &'static str; +} + +#[derive(Clone)] +pub struct Server { + data: Arc>>, +} + +impl Server { + fn handle_request(&self, mut stream: TcpStream) { + let mut buf = [0u8; 4]; + stream.read_exact(&mut buf).unwrap(); + match Request::try_from(buf) { + Ok(Request::KeyMap) => { + let data = self.data.read().unwrap(); + let buf = data.get(&Request::KeyMap); + match buf { + None => { + stream.write(&0u32.to_ne_bytes()).unwrap(); + } + Some(buf) => { + stream.write(&buf[..].len().to_ne_bytes()).unwrap(); + stream.write(&buf[..]).unwrap(); + } + } + stream.flush().unwrap(); + } + Ok(Request::Connect) => todo!(), + Err(msg) => eprintln!("{}", msg), + } + } + + pub fn listen(port: u16) -> Result<(Server, JoinHandle<()>), Box> { + let data: Arc>> = Arc::new(RwLock::new(HashMap::new())); + let listen_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), port); + let server = Server { data }; + let server_copy = server.clone(); + let thread = thread::spawn(move || { + let listen_socket = TcpListener::bind(listen_addr).unwrap(); + for stream in listen_socket.incoming() { + match stream { + Ok(stream) => { + server.handle_request(stream); + } + Err(e) => { + eprintln!("{}", e); + } + } + } + }); + Ok((server_copy, thread)) + } + + pub fn offer_data(&self, req: Request, d: Mmap) { + self.data.write().unwrap().insert(req, d); + } + +} + +pub fn request_data(addr: SocketAddr, req: Request) -> Option> { + // connect to server + let mut sock = match TcpStream::connect(addr) { + Ok(sock) => sock, + Err(e) => { + eprintln!("{}", e); + return None; + } + }; + + // write the request to the socket + // convert to u32 + let req: u32 = req as u32; + if let Err(e) = sock.write(&req.to_ne_bytes()) { + eprintln!("{}", e); + return None; + } + if let Err(e) = sock.flush() { + eprintln!("{}", e); + return None; + } + + // read the response = (len, data) - len 0 means no data / bad request + // read len + let mut buf = [0u8; 8]; + if let Err(e) = sock.read_exact(&mut buf[..]) { + eprintln!("{}", e); + return None; + } + let len = usize::from_ne_bytes(buf); + + // check for bad request + if len == 0 { + return None; + } + + // read the data + let mut data: Vec = vec![0u8; len]; + if let Err(e) = sock.read_exact(&mut data[..]) { + eprintln!("{}", e); + return None; + } + Some(data) +} +