diff --git a/lan-mouse-gtk/resources/fingerprint_window.ui b/lan-mouse-gtk/resources/fingerprint_window.ui
new file mode 100644
index 0000000..f042b74
--- /dev/null
+++ b/lan-mouse-gtk/resources/fingerprint_window.ui
@@ -0,0 +1,68 @@
+
+
+
+
+
+ True
+ 880
+ 880
+ 240
+ Add Public Key Fingerprint
+
+
+
+
+
diff --git a/lan-mouse-gtk/resources/resources.gresource.xml b/lan-mouse-gtk/resources/resources.gresource.xml
index b5d9209..bec7393 100644
--- a/lan-mouse-gtk/resources/resources.gresource.xml
+++ b/lan-mouse-gtk/resources/resources.gresource.xml
@@ -2,6 +2,7 @@
window.ui
+ fingerprint_window.ui
client_row.ui
diff --git a/lan-mouse-gtk/src/fingerprint_window.rs b/lan-mouse-gtk/src/fingerprint_window.rs
new file mode 100644
index 0000000..6f51ad3
--- /dev/null
+++ b/lan-mouse-gtk/src/fingerprint_window.rs
@@ -0,0 +1,24 @@
+mod imp;
+
+use adw::prelude::*;
+use adw::subclass::prelude::*;
+use glib::{clone, Object};
+use gtk::{
+ gio,
+ glib::{self, closure_local},
+ ListBox, NoSelection,
+};
+
+glib::wrapper! {
+ pub struct FingerprintWindow(ObjectSubclass)
+ @extends adw::Window, gtk::Window, gtk::Widget,
+ @implements gio::ActionGroup, gio::ActionMap, gtk::Accessible, gtk::Buildable,
+ gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager;
+}
+
+impl FingerprintWindow {
+ pub(crate) fn new() -> Self {
+ let window: Self = Object::builder().build();
+ window
+ }
+}
diff --git a/lan-mouse-gtk/src/fingerprint_window/imp.rs b/lan-mouse-gtk/src/fingerprint_window/imp.rs
new file mode 100644
index 0000000..ad87a3c
--- /dev/null
+++ b/lan-mouse-gtk/src/fingerprint_window/imp.rs
@@ -0,0 +1,45 @@
+use adw::subclass::prelude::*;
+use glib::subclass::InitializingObject;
+use gtk::{glib, template_callbacks, CompositeTemplate, Entry};
+
+#[derive(CompositeTemplate, Default)]
+#[template(resource = "/de/feschber/LanMouse/fingerprint_window.ui")]
+pub struct FingerprintWindow {
+ // #[template_child]
+ // pub fingerprint_entry: TemplateChild,
+}
+
+#[glib::object_subclass]
+impl ObjectSubclass for FingerprintWindow {
+ const NAME: &'static str = "FingerprintWindow";
+ const ABSTRACT: bool = false;
+
+ type Type = super::FingerprintWindow;
+ type ParentType = adw::Window;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.bind_template();
+ klass.bind_template_callbacks();
+ }
+
+ fn instance_init(obj: &InitializingObject) {
+ obj.init_template();
+ }
+}
+
+#[template_callbacks]
+impl FingerprintWindow {
+ // #[template_callback]
+ // fn handle_confirm() {}
+}
+
+impl ObjectImpl for FingerprintWindow {
+ fn constructed(&self) {
+ self.parent_constructed();
+ }
+}
+
+impl WidgetImpl for FingerprintWindow {}
+impl WindowImpl for FingerprintWindow {}
+impl ApplicationWindowImpl for FingerprintWindow {}
+impl AdwWindowImpl for FingerprintWindow {}
diff --git a/lan-mouse-gtk/src/lib.rs b/lan-mouse-gtk/src/lib.rs
index c2ec581..78045ae 100644
--- a/lan-mouse-gtk/src/lib.rs
+++ b/lan-mouse-gtk/src/lib.rs
@@ -1,5 +1,6 @@
mod client_object;
mod client_row;
+mod fingerprint_window;
mod window;
use std::{env, process, str};
diff --git a/lan-mouse-gtk/src/window.rs b/lan-mouse-gtk/src/window.rs
index 269a46d..d9afa3e 100644
--- a/lan-mouse-gtk/src/window.rs
+++ b/lan-mouse-gtk/src/window.rs
@@ -6,7 +6,7 @@ use glib::{clone, Object};
use gtk::{
gio,
glib::{self, closure_local},
- ListBox, NoSelection,
+ ListBox, NoSelection, Widget,
};
use lan_mouse_ipc::{
@@ -14,6 +14,8 @@ use lan_mouse_ipc::{
DEFAULT_PORT,
};
+use crate::fingerprint_window::FingerprintWindow;
+
use super::{client_object::ClientObject, client_row::ClientRow};
glib::wrapper! {
@@ -286,6 +288,16 @@ impl Window {
self.request(FrontendRequest::Delete(client.handle()));
}
+ pub fn open_fingerprint_dialog(&self) {
+ let window = FingerprintWindow::new();
+ window.set_transient_for(Some(self));
+ window.present();
+ }
+
+ pub fn request_fingerprint_add(&self, fp: String) {
+ self.request(FrontendRequest::FingerprintAdd(fp));
+ }
+
pub fn request(&self, request: FrontendRequest) {
let mut requester = self.imp().frontend_request_writer.borrow_mut();
let requester = requester.as_mut().unwrap();
diff --git a/lan-mouse-gtk/src/window/imp.rs b/lan-mouse-gtk/src/window/imp.rs
index fb67873..6a76ad1 100644
--- a/lan-mouse-gtk/src/window/imp.rs
+++ b/lan-mouse-gtk/src/window/imp.rs
@@ -120,7 +120,7 @@ impl Window {
#[template_callback]
fn handle_add_cert_fingerprint(&self, _button: &Button) {
- log::info!("TODO: impl add certificate fingerprint");
+ self.obj().open_fingerprint_dialog();
}
pub fn set_port(&self, port: u16) {
diff --git a/lan-mouse-ipc/src/lib.rs b/lan-mouse-ipc/src/lib.rs
index cdc2dd1..892f846 100644
--- a/lan-mouse-ipc/src/lib.rs
+++ b/lan-mouse-ipc/src/lib.rs
@@ -65,6 +65,17 @@ pub enum Position {
Bottom,
}
+impl Position {
+ pub fn opposite(&self) -> Self {
+ match self {
+ Position::Left => Position::Right,
+ Position::Right => Position::Left,
+ Position::Top => Position::Bottom,
+ Position::Bottom => Position::Top,
+ }
+ }
+}
+
#[derive(Debug, Error)]
#[error("not a valid position: {pos}")]
pub struct PositionParseError {
@@ -218,6 +229,10 @@ pub enum FrontendRequest {
EnableEmulation,
/// synchronize all state
Sync,
+ /// authorize fingerprint
+ FingerprintAdd(String),
+ /// remove fingerprint
+ FingerprintRemove(String),
}
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
diff --git a/lan-mouse-proto/src/lib.rs b/lan-mouse-proto/src/lib.rs
index e490136..2e342d3 100644
--- a/lan-mouse-proto/src/lib.rs
+++ b/lan-mouse-proto/src/lib.rs
@@ -48,7 +48,7 @@ impl Display for Position {
/// main lan-mouse protocol event type
#[derive(Clone, Copy, Debug)]
pub enum ProtoEvent {
- /// notify a client that the cursor entered its region
+ /// notify a client that the cursor entered its region at the given position
/// [`ProtoEvent::Ack`] with the same serial is used for synchronization between devices
Enter(Position),
/// notify a client that the cursor left its region
diff --git a/src/capture.rs b/src/capture.rs
index 7703373..e0dd6ee 100644
--- a/src/capture.rs
+++ b/src/capture.rs
@@ -47,9 +47,9 @@ impl Capture {
}
}
- pub(crate) fn create(&self, handle: CaptureHandle, pos: Position) {
+ pub(crate) fn create(&self, handle: CaptureHandle, pos: lan_mouse_ipc::Position) {
self.tx
- .send(CaptureRequest::Create(handle, pos))
+ .send(CaptureRequest::Create(handle, to_capture_pos(pos)))
.expect("channel closed");
}
@@ -100,11 +100,16 @@ async fn do_capture(
};
server.set_capture_status(Status::Enabled);
- let clients = server.active_clients();
- let clients = clients
- .iter()
- .copied()
- .map(|handle| (handle, server.get_pos(handle).expect("no such client")));
+ let clients = server.client_manager.active_clients();
+ let clients = clients.iter().copied().map(|handle| {
+ (
+ handle,
+ server
+ .client_manager
+ .get_pos(handle)
+ .expect("no such client"),
+ )
+ });
/* create barriers for active clients */
for (handle, pos) in clients {
@@ -201,7 +206,7 @@ async fn handle_capture_event(
return release_capture(capture, server).await;
}
- if capture.keys_pressed(&server.release_bind) {
+ if capture.keys_pressed(&server.config.release_bind) {
log::info!("releasing capture: release-bind pressed");
return release_capture(capture, server).await;
}
@@ -214,11 +219,16 @@ async fn handle_capture_event(
spawn_hook_command(server, handle);
}
+ let pos = match server.client_manager.get_pos(handle) {
+ Some(pos) => to_proto_pos(pos.opposite()),
+ None => return release_capture(capture, server).await,
+ };
+
let event = match event {
- CaptureEvent::Begin => ProtoEvent::Enter(lan_mouse_proto::Position::Left),
+ CaptureEvent::Begin => ProtoEvent::Enter(pos),
CaptureEvent::Input(e) => match state {
// connection not acknowledged, repeat `Enter` event
- State::WaitingForAck => ProtoEvent::Enter(lan_mouse_proto::Position::Left),
+ State::WaitingForAck => ProtoEvent::Enter(pos),
_ => ProtoEvent::Input(e),
},
};
@@ -245,13 +255,17 @@ fn to_capture_pos(pos: lan_mouse_ipc::Position) -> input_capture::Position {
}
}
+fn to_proto_pos(pos: lan_mouse_ipc::Position) -> lan_mouse_proto::Position {
+ match pos {
+ lan_mouse_ipc::Position::Left => lan_mouse_proto::Position::Left,
+ lan_mouse_ipc::Position::Right => lan_mouse_proto::Position::Right,
+ lan_mouse_ipc::Position::Top => lan_mouse_proto::Position::Top,
+ lan_mouse_ipc::Position::Bottom => lan_mouse_proto::Position::Bottom,
+ }
+}
+
fn spawn_hook_command(server: &Server, handle: ClientHandle) {
- let Some(cmd) = server
- .client_manager
- .borrow()
- .get(handle)
- .and_then(|(c, _)| c.cmd.clone())
- else {
+ let Some(cmd) = server.client_manager.get_enter_cmd(handle) else {
return;
};
tokio::task::spawn_local(async move {
diff --git a/src/client.rs b/src/client.rs
index 79ebd00..debf3c5 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -1,18 +1,63 @@
-use std::net::SocketAddr;
+use std::{
+ cell::RefCell,
+ collections::HashSet,
+ net::{IpAddr, SocketAddr},
+ rc::Rc,
+};
use slab::Slab;
use lan_mouse_ipc::{ClientConfig, ClientHandle, ClientState, Position};
-#[derive(Default)]
+#[derive(Clone, Default)]
pub struct ClientManager {
- clients: Slab<(ClientConfig, ClientState)>,
+ clients: Rc>>,
}
impl ClientManager {
/// add a new client to this manager
- pub fn add_client(&mut self) -> ClientHandle {
- self.clients.insert(Default::default()) as ClientHandle
+ pub fn add_client(&self) -> ClientHandle {
+ self.clients.borrow_mut().insert(Default::default()) as ClientHandle
+ }
+
+ /// set the config of the given client
+ pub fn set_config(&self, handle: ClientHandle, config: ClientConfig) {
+ if let Some((c, _)) = self.clients.borrow_mut().get_mut(handle as usize) {
+ *c = config;
+ }
+ }
+
+ /// set the state of the given client
+ pub fn set_state(&self, handle: ClientHandle, state: ClientState) {
+ if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) {
+ *s = state;
+ }
+ }
+
+ /// activate the given client
+ /// returns, whether the client was activated
+ pub fn activate_client(&self, handle: ClientHandle) -> bool {
+ let mut clients = self.clients.borrow_mut();
+ match clients.get_mut(handle as usize) {
+ Some((_, s)) if s.active == false => {
+ s.active = true;
+ true
+ }
+ _ => false,
+ }
+ }
+
+ /// deactivate the given client
+ /// returns, whether the client was deactivated
+ pub fn deactivate_client(&self, handle: ClientHandle) -> bool {
+ let mut clients = self.clients.borrow_mut();
+ match clients.get_mut(handle as usize) {
+ Some((_, s)) if s.active => {
+ s.active = false;
+ true
+ }
+ _ => false,
+ }
}
/// find a client by its address
@@ -20,6 +65,7 @@ impl ClientManager {
// since there shouldn't be more than a handful of clients at any given
// time this is likely faster than using a HashMap
self.clients
+ .borrow()
.iter()
.find_map(|(k, (_, s))| {
if s.active && s.ips.contains(&addr.ip()) {
@@ -31,8 +77,10 @@ impl ClientManager {
.map(|p| p as ClientHandle)
}
- pub fn find_client(&self, pos: Position) -> Option {
+ /// get the client at the given position
+ pub fn client_at(&self, pos: Position) -> Option {
self.clients
+ .borrow()
.iter()
.find_map(|(k, (c, s))| {
if s.active && c.pos == pos {
@@ -44,31 +92,162 @@ impl ClientManager {
.map(|p| p as ClientHandle)
}
+ pub(crate) fn get_hostname(&self, handle: ClientHandle) -> Option {
+ self.clients
+ .borrow_mut()
+ .get_mut(handle as usize)
+ .and_then(|(c, _)| c.hostname.clone())
+ }
+
+ /// get the position of the corresponding client
+ pub(crate) fn get_pos(&self, handle: ClientHandle) -> Option {
+ self.clients
+ .borrow()
+ .get(handle as usize)
+ .map(|(c, _)| c.pos)
+ }
+
/// remove a client from the list
- pub fn remove_client(&mut self, client: ClientHandle) -> Option<(ClientConfig, ClientState)> {
+ pub fn remove_client(&self, client: ClientHandle) -> Option<(ClientConfig, ClientState)> {
// remove id from occupied ids
- self.clients.try_remove(client as usize)
+ self.clients.borrow_mut().try_remove(client as usize)
}
- // returns an immutable reference to the client state corresponding to `client`
- pub fn get(&self, handle: ClientHandle) -> Option<&(ClientConfig, ClientState)> {
- self.clients.get(handle as usize)
+ /// get the config & state of the given client
+ pub fn get_state(&self, handle: ClientHandle) -> Option<(ClientConfig, ClientState)> {
+ self.clients.borrow().get(handle as usize).cloned()
}
- /// returns a mutable reference to the client state corresponding to `client`
- pub fn get_mut(&mut self, handle: ClientHandle) -> Option<&mut (ClientConfig, ClientState)> {
- self.clients.get_mut(handle as usize)
+ /// get the current config & state of all clients
+ pub fn get_client_states(&self) -> Vec<(ClientHandle, ClientConfig, ClientState)> {
+ self.clients
+ .borrow()
+ .iter()
+ .map(|(k, v)| (k as ClientHandle, v.0.clone(), v.1.clone()))
+ .collect()
}
- pub fn get_client_states(
- &self,
- ) -> impl Iterator- {
- self.clients.iter().map(|(k, v)| (k as ClientHandle, v))
+ /// update the fix ips of the client
+ pub fn set_fix_ips(&self, handle: ClientHandle, fix_ips: Vec) {
+ if let Some((c, _)) = self.clients.borrow_mut().get_mut(handle as usize) {
+ c.fix_ips = fix_ips
+ }
+ self.update_ips(handle);
}
- pub fn get_client_states_mut(
- &mut self,
- ) -> impl Iterator
- {
- self.clients.iter_mut().map(|(k, v)| (k as ClientHandle, v))
+ /// update the dns-ips of the client
+ pub fn set_dns_ips(&self, handle: ClientHandle, dns_ips: Vec) {
+ if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) {
+ s.dns_ips = dns_ips
+ }
+ self.update_ips(handle);
+ }
+
+ fn update_ips(&self, handle: ClientHandle) {
+ if let Some((c, s)) = self.clients.borrow_mut().get_mut(handle as usize) {
+ s.ips = c
+ .fix_ips
+ .iter()
+ .cloned()
+ .chain(s.dns_ips.iter().cloned())
+ .collect::>();
+ }
+ }
+
+ /// update the hostname of the given client
+ /// this automatically clears the active ip address and ips from dns
+ pub fn set_hostname(&self, handle: ClientHandle, hostname: Option) -> bool {
+ let mut clients = self.clients.borrow_mut();
+ let Some((c, s)) = clients.get_mut(handle as usize) else {
+ return false;
+ };
+
+ // hostname changed
+ if c.hostname != hostname {
+ c.hostname = hostname;
+ s.active_addr = None;
+ s.dns_ips.clear();
+ drop(clients);
+ self.update_ips(handle);
+ true
+ } else {
+ false
+ }
+ }
+
+ /// update the port of the client
+ pub(crate) fn set_port(&self, handle: ClientHandle, port: u16) {
+ match self.clients.borrow_mut().get_mut(handle as usize) {
+ Some((c, s)) if c.port != port => {
+ c.port = port;
+ s.active_addr = s.active_addr.map(|a| SocketAddr::new(a.ip(), port));
+ }
+ _ => {}
+ };
+ }
+
+ /// update the position of the client
+ /// returns true, if a change in capture position is required (pos changed & client is active)
+ pub(crate) fn set_pos(&self, handle: ClientHandle, pos: Position) -> bool {
+ match self.clients.borrow_mut().get_mut(handle as usize) {
+ Some((c, s)) if c.pos != pos => {
+ log::info!("update pos {handle} {} -> {}", c.pos, pos);
+ c.pos = pos;
+ s.active
+ }
+ _ => false,
+ }
+ }
+
+ /// set resolving status of the client
+ pub(crate) fn set_resolving(&self, handle: ClientHandle, status: bool) {
+ if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) {
+ s.resolving = status;
+ }
+ }
+
+ /// get the enter hook command
+ pub(crate) fn get_enter_cmd(&self, handle: ClientHandle) -> Option {
+ self.clients
+ .borrow()
+ .get(handle as usize)
+ .and_then(|(c, _)| c.cmd.clone())
+ }
+
+ /// returns all clients that are currently active
+ pub(crate) fn active_clients(&self) -> Vec {
+ self.clients
+ .borrow()
+ .iter()
+ .filter(|(_, (_, s))| s.active)
+ .map(|(h, _)| h as ClientHandle)
+ .collect()
+ }
+
+ pub(crate) fn set_active_addr(&self, handle: u64, addr: Option) {
+ if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) {
+ s.active_addr = addr;
+ }
+ }
+
+ pub(crate) fn active_addr(&self, handle: u64) -> Option {
+ self.clients
+ .borrow()
+ .get(handle as usize)
+ .and_then(|(_, s)| s.active_addr)
+ }
+
+ pub(crate) fn get_port(&self, handle: u64) -> Option {
+ self.clients
+ .borrow()
+ .get(handle as usize)
+ .map(|(c, _)| c.port)
+ }
+
+ pub(crate) fn get_ips(&self, handle: u64) -> Option> {
+ self.clients
+ .borrow()
+ .get(handle as usize)
+ .map(|(_, s)| s.ips.clone())
}
}
diff --git a/src/connect.rs b/src/connect.rs
index 9e26f0b..ba48569 100644
--- a/src/connect.rs
+++ b/src/connect.rs
@@ -95,7 +95,7 @@ impl LanMouseConnection {
) -> Result<(), LanMouseConnectionError> {
let (buf, len): ([u8; MAX_EVENT_SIZE], usize) = event.into();
let buf = &buf[..len];
- if let Some(addr) = self.server.active_addr(handle) {
+ if let Some(addr) = self.server.client_manager.active_addr(handle) {
let conn = {
let conns = self.conns.lock().await;
conns.get(&addr).cloned()
@@ -138,8 +138,11 @@ async fn connect_to_handle(
) -> Result<(), LanMouseConnectionError> {
log::info!("client {handle} connecting ...");
// sending did not work, figure out active conn.
- if let Some(addrs) = server.get_ips(handle) {
- let port = server.get_port(handle).unwrap_or(DEFAULT_PORT);
+ if let Some(addrs) = server.client_manager.get_ips(handle) {
+ let port = server
+ .client_manager
+ .get_port(handle)
+ .unwrap_or(DEFAULT_PORT);
let addrs = addrs
.into_iter()
.map(|a| SocketAddr::new(a, port))
@@ -154,7 +157,7 @@ async fn connect_to_handle(
}
};
log::info!("client ({handle}) connected @ {addr}");
- server.set_active_addr(handle, Some(addr));
+ server.client_manager.set_active_addr(handle, Some(addr));
conns.lock().await.insert(addr, conn.clone());
connecting.lock().await.remove(&handle);
@@ -193,7 +196,7 @@ async fn ping_pong(
tokio::time::sleep(Duration::from_millis(500)).await;
- if server.active_addr(handle).is_none() {
+ if server.client_manager.active_addr(handle).is_none() {
log::warn!("no active addr");
disconnect(&server, handle, addr, &conns).await;
}
@@ -212,7 +215,7 @@ async fn receive_loop(
while let Ok(_) = conn.recv(&mut buf).await {
if let Ok(event) = buf.try_into() {
match event {
- ProtoEvent::Pong => server.set_active_addr(handle, Some(addr)),
+ ProtoEvent::Pong => server.client_manager.set_active_addr(handle, Some(addr)),
event => tx.send((handle, event)).expect("channel closed"),
}
}
@@ -229,7 +232,7 @@ async fn disconnect(
) {
log::warn!("client ({handle}) @ {addr} connection closed");
conns.lock().await.remove(&addr);
- server.set_active_addr(handle, None);
+ server.client_manager.set_active_addr(handle, None);
let active: Vec = conns.lock().await.keys().copied().collect();
log::info!("active connections: {active:?}");
}
diff --git a/src/dns.rs b/src/dns.rs
index bea583f..3c7f7da 100644
--- a/src/dns.rs
+++ b/src/dns.rs
@@ -39,7 +39,7 @@ impl DnsResolver {
let handle = rx.recv().await.expect("channel closed");
/* update resolving status */
- let hostname = match server.get_hostname(handle) {
+ let hostname = match server.client_manager.get_hostname(handle) {
Some(hostname) => hostname,
None => continue,
};
diff --git a/src/server.rs b/src/server.rs
index 92cbe0d..5b6b3e9 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -16,7 +16,7 @@ use lan_mouse_ipc::{
use log;
use std::{
cell::{Cell, RefCell},
- collections::{HashSet, VecDeque},
+ collections::{HashMap, HashSet, VecDeque},
io,
net::{IpAddr, SocketAddr},
rc::Rc,
@@ -42,16 +42,17 @@ pub struct ReleaseToken;
#[derive(Clone)]
pub struct Server {
active: Rc
>>,
- pub(crate) client_manager: Rc>,
+ authorized_keys: Rc>>,
+ known_hosts: Rc>>,
+ pub(crate) client_manager: ClientManager,
port: Rc>,
- pub(crate) release_bind: Vec,
notifies: Rc,
pub(crate) config: Rc,
pending_frontend_events: Rc>>,
capture_status: Rc>,
pub(crate) emulation_status: Rc| >,
pub(crate) should_release: Rc>>,
- incoming_conns: Rc>>,
+ incoming_conns: Rc>>,
}
#[derive(Default)]
@@ -65,44 +66,43 @@ struct Notifies {
impl Server {
pub fn new(config: Config) -> Self {
- let client_manager = Rc::new(RefCell::new(ClientManager::default()));
+ let client_manager = ClientManager::default();
let port = Rc::new(Cell::new(config.port));
- for config_client in config.get_clients() {
- let client = ClientConfig {
- hostname: config_client.hostname,
- fix_ips: config_client.ips.into_iter().collect(),
- port: config_client.port,
- pos: config_client.pos,
- cmd: config_client.enter_hook,
+ for client in config.get_clients() {
+ let config = ClientConfig {
+ hostname: client.hostname,
+ fix_ips: client.ips.into_iter().collect(),
+ port: client.port,
+ pos: client.pos,
+ cmd: client.enter_hook,
};
let state = ClientState {
- active: config_client.active,
- ips: HashSet::from_iter(client.fix_ips.iter().cloned()),
+ active: client.active,
+ ips: HashSet::from_iter(config.fix_ips.iter().cloned()),
..Default::default()
};
- let mut client_manager = client_manager.borrow_mut();
let handle = client_manager.add_client();
- let c = client_manager.get_mut(handle).expect("invalid handle");
- *c = (client, state);
+ client_manager.set_config(handle, config);
+ client_manager.set_state(handle, state);
}
// task notification tokens
let notifies = Rc::new(Notifies::default());
- let release_bind = config.release_bind.clone();
let config = Rc::new(config);
Self {
active: Rc::new(Cell::new(None)),
+ authorized_keys: Default::default(),
+ known_hosts: Default::default(),
config,
client_manager,
port,
- release_bind,
notifies,
pending_frontend_events: Rc::new(RefCell::new(VecDeque::new())),
capture_status: Default::default(),
emulation_status: Default::default(),
- incoming_conns: Rc::new(RefCell::new(Vec::new())),
+ incoming_conns: Rc::new(RefCell::new(HashMap::new())),
should_release: Default::default(),
}
}
@@ -129,7 +129,7 @@ impl Server {
// create dns resolver
let resolver = DnsResolver::new(self.clone())?;
- for handle in self.active_clients() {
+ for handle in self.client_manager.active_clients() {
resolver.resolve(handle);
}
@@ -221,15 +221,6 @@ impl Server {
self.notify_frontend(FrontendEvent::Changed(handle));
}
- pub(crate) fn active_clients(&self) -> Vec {
- self.client_manager
- .borrow()
- .get_client_states()
- .filter(|(_, (_, s))| s.active)
- .map(|(h, _)| h)
- .collect()
- }
-
fn handle_request(&self, capture: &Capture, event: FrontendRequest, dns: &DnsResolver) -> bool {
log::debug!("frontend: {event:?}");
match event {
@@ -267,183 +258,109 @@ impl Server {
self.notify_frontend(FrontendEvent::CaptureStatus(self.capture_status.get()));
self.notify_frontend(FrontendEvent::PortChanged(self.port.get(), None));
}
+ FrontendRequest::FingerprintAdd(key) => {
+ self.add_authorized_key(key);
+ }
+ FrontendRequest::FingerprintRemove(key) => {
+ self.remove_authorized_key(key);
+ }
};
false
}
+ fn add_authorized_key(&self, key: String) {
+ self.authorized_keys.borrow_mut().insert(key);
+ }
+
+ fn remove_authorized_key(&self, key: String) {
+ self.authorized_keys.borrow_mut().remove(&key);
+ }
+
fn enumerate(&self) {
- let clients = self
- .client_manager
- .borrow()
- .get_client_states()
- .map(|(h, (c, s))| (h, c.clone(), s.clone()))
- .collect();
+ let clients = self.client_manager.get_client_states();
self.notify_frontend(FrontendEvent::Enumerate(clients));
}
fn add_client(&self) -> ClientHandle {
- let handle = self.client_manager.borrow_mut().add_client();
+ let handle = self.client_manager.add_client();
log::info!("added client {handle}");
- let (c, s) = self.client_manager.borrow().get(handle).unwrap().clone();
+ let (c, s) = self.client_manager.get_state(handle).unwrap();
self.notify_frontend(FrontendEvent::Created(handle, c, s));
handle
}
fn deactivate_client(&self, capture: &Capture, handle: ClientHandle) {
log::debug!("deactivating client {handle}");
- match self.client_manager.borrow_mut().get_mut(handle) {
- None => return,
- Some((_, s)) if !s.active => return,
- Some((_, s)) => s.active = false,
- };
-
- capture.destroy(handle);
- self.client_updated(handle);
- log::info!("deactivated client {handle}");
+ if self.client_manager.deactivate_client(handle) {
+ capture.destroy(handle);
+ self.client_updated(handle);
+ log::info!("deactivated client {handle}");
+ }
}
fn activate_client(&self, capture: &Capture, handle: ClientHandle) {
log::debug!("activating client");
/* deactivate potential other client at this position */
- let pos = match self.client_manager.borrow().get(handle) {
- None => return,
- Some((_, s)) if s.active => return,
- Some((client, _)) => client.pos,
+ let Some(pos) = self.client_manager.get_pos(handle) else {
+ return;
};
- let other = self.client_manager.borrow_mut().find_client(pos);
- if let Some(other) = other {
- self.deactivate_client(capture, other);
+ if let Some(other) = self.client_manager.client_at(pos) {
+ if other != handle {
+ self.deactivate_client(capture, other);
+ }
}
/* activate the client */
- if let Some((_, s)) = self.client_manager.borrow_mut().get_mut(handle) {
- s.active = true;
- } else {
- return;
- };
-
- /* notify capture and frontends */
- capture.create(handle, to_capture_pos(pos));
- self.client_updated(handle);
- log::info!("activated client {handle} ({pos})");
+ if self.client_manager.activate_client(handle) {
+ /* notify capture and frontends */
+ capture.create(handle, pos);
+ self.client_updated(handle);
+ log::info!("activated client {handle} ({pos})");
+ }
}
fn remove_client(&self, capture: &Capture, handle: ClientHandle) {
- let Some(active) = self
+ if let Some(true) = self
.client_manager
- .borrow_mut()
.remove_client(handle)
.map(|(_, s)| s.active)
- else {
- return;
- };
-
- if active {
+ {
capture.destroy(handle);
}
}
fn update_fix_ips(&self, handle: ClientHandle, fix_ips: Vec) {
- if let Some((c, _)) = self.client_manager.borrow_mut().get_mut(handle) {
- c.fix_ips = fix_ips;
- };
- self.update_ips(handle);
+ self.client_manager.set_fix_ips(handle, fix_ips);
self.client_updated(handle);
}
pub(crate) fn update_dns_ips(&self, handle: ClientHandle, dns_ips: Vec) {
- if let Some((_, s)) = self.client_manager.borrow_mut().get_mut(handle) {
- s.dns_ips = dns_ips;
- };
- self.update_ips(handle);
+ self.client_manager.set_dns_ips(handle, dns_ips);
self.client_updated(handle);
}
- fn update_ips(&self, handle: ClientHandle) {
- if let Some((c, s)) = self.client_manager.borrow_mut().get_mut(handle) {
- s.ips = c
- .fix_ips
- .iter()
- .cloned()
- .chain(s.dns_ips.iter().cloned())
- .collect::>();
- }
- }
-
- pub(crate) fn get_ips(&self, handle: ClientHandle) -> Option> {
- if let Some((_, s)) = self.client_manager.borrow().get(handle) {
- Some(s.ips.iter().copied().collect())
- } else {
- None
- }
- }
-
- pub(crate) fn get_port(&self, handle: ClientHandle) -> Option {
- if let Some((c, _)) = self.client_manager.borrow().get(handle) {
- Some(c.port)
- } else {
- None
- }
- }
-
fn update_hostname(&self, handle: ClientHandle, hostname: Option, dns: &DnsResolver) {
- let mut client_manager = self.client_manager.borrow_mut();
- let Some((c, s)) = client_manager.get_mut(handle) else {
- return;
- };
-
- // hostname changed
- if c.hostname != hostname {
- c.hostname = hostname;
- s.active_addr = None;
- s.dns_ips.clear();
- drop(client_manager);
- self.update_ips(handle);
+ if self.client_manager.set_hostname(handle, hostname) {
dns.resolve(handle);
+ self.client_updated(handle);
}
- self.client_updated(handle);
}
fn update_port(&self, handle: ClientHandle, port: u16) {
- let mut client_manager = self.client_manager.borrow_mut();
- let Some((c, s)) = client_manager.get_mut(handle) else {
- return;
- };
-
- if c.port != port {
- c.port = port;
- s.active_addr = s.active_addr.map(|a| SocketAddr::new(a.ip(), port));
- }
+ self.client_manager.set_port(handle, port);
}
fn update_pos(&self, handle: ClientHandle, capture: &Capture, pos: Position) {
- let (changed, active) = {
- let mut client_manager = self.client_manager.borrow_mut();
- let Some((c, s)) = client_manager.get_mut(handle) else {
- return;
- };
-
- let changed = c.pos != pos;
- if changed {
- log::info!("update pos {handle} {} -> {}", c.pos, pos);
- }
- c.pos = pos;
- (changed, s.active)
- };
-
// update state in event input emulator & input capture
- if changed {
+ if self.client_manager.set_pos(handle, pos) {
self.deactivate_client(capture, handle);
- if active {
- self.activate_client(capture, handle);
- }
+ self.activate_client(capture, handle);
}
}
fn broadcast_client(&self, handle: ClientHandle) {
- let client = self.client_manager.borrow().get(handle).cloned();
- let event = if let Some((config, state)) = client {
+ let event = if let Some((config, state)) = self.client_manager.get_state(handle) {
FrontendEvent::State(handle, config, state)
} else {
FrontendEvent::NoSuchClient(handle)
@@ -464,36 +381,10 @@ impl Server {
}
pub(crate) fn set_resolving(&self, handle: ClientHandle, status: bool) {
- if let Some((_, s)) = self.client_manager.borrow_mut().get_mut(handle) {
- s.resolving = status;
- }
+ self.client_manager.set_resolving(handle, status);
self.client_updated(handle);
}
- pub(crate) fn get_hostname(&self, handle: ClientHandle) -> Option {
- self.client_manager
- .borrow_mut()
- .get_mut(handle)
- .and_then(|(c, _)| c.hostname.clone())
- }
-
- pub(crate) fn get_pos(&self, handle: ClientHandle) -> Option {
- self.client_manager.borrow().get(handle).map(|(c, _)| c.pos)
- }
-
- pub(crate) fn set_active_addr(&self, handle: ClientHandle, addr: Option) {
- if let Some((_, s)) = self.client_manager.borrow_mut().get_mut(handle) {
- s.active_addr = addr;
- }
- }
-
- pub(crate) fn active_addr(&self, handle: ClientHandle) -> Option {
- self.client_manager
- .borrow()
- .get(handle)
- .and_then(|(_, s)| s.active_addr)
- }
-
pub(crate) fn release_capture(&self) {
self.should_release.replace(Some(ReleaseToken));
}
@@ -507,15 +398,6 @@ impl Server {
}
pub(crate) fn register_incoming(&self, addr: SocketAddr, pos: Position) {
- self.incoming_conns.borrow_mut().push((addr, pos));
- }
-}
-
-fn to_capture_pos(pos: Position) -> input_capture::Position {
- match pos {
- Position::Left => input_capture::Position::Left,
- Position::Right => input_capture::Position::Right,
- Position::Top => input_capture::Position::Top,
- Position::Bottom => input_capture::Position::Bottom,
+ self.incoming_conns.borrow_mut().insert(addr, pos);
}
}
| | | |