diff --git a/lan-mouse-ipc/src/lib.rs b/lan-mouse-ipc/src/lib.rs index 4736b0d..6ffa34c 100644 --- a/lan-mouse-ipc/src/lib.rs +++ b/lan-mouse-ipc/src/lib.rs @@ -161,7 +161,7 @@ pub struct ClientState { /// This should generally be the socket address where data /// was last received from. pub active_addr: Option, - /// tracks whether or not the client is responding to pings + /// tracks whether or not the client is available for emulation pub alive: bool, /// ips from dns pub dns_ips: Vec, @@ -239,7 +239,7 @@ pub enum FrontendRequest { RemoveAuthorizedKey(String), } -#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, Serialize, Deserialize)] pub enum Status { #[default] Disabled, diff --git a/lan-mouse-proto/src/lib.rs b/lan-mouse-proto/src/lib.rs index 2e342d3..41f2efb 100644 --- a/lan-mouse-proto/src/lib.rs +++ b/lan-mouse-proto/src/lib.rs @@ -61,8 +61,8 @@ pub enum ProtoEvent { /// Ping event for tracking unresponsive clients. /// A client has to respond with [`ProtoEvent::Pong`]. Ping, - /// Response to [`ProtoEvent::Ping`] - Pong, + /// Response to [`ProtoEvent::Ping`], true if emulation is enabled / available + Pong(bool), } impl Display for ProtoEvent { @@ -73,7 +73,13 @@ impl Display for ProtoEvent { ProtoEvent::Ack(s) => write!(f, "Ack({s})"), ProtoEvent::Input(e) => write!(f, "{e}"), ProtoEvent::Ping => write!(f, "ping"), - ProtoEvent::Pong => write!(f, "pong"), + ProtoEvent::Pong(alive) => { + write!( + f, + "pong: {}", + if *alive { "alive" } else { "not available" } + ) + } } } } @@ -110,7 +116,7 @@ impl ProtoEvent { }, }, ProtoEvent::Ping => EventType::Ping, - ProtoEvent::Pong => EventType::Pong, + ProtoEvent::Pong(_) => EventType::Pong, ProtoEvent::Enter(_) => EventType::Enter, ProtoEvent::Leave(_) => EventType::Leave, ProtoEvent::Ack(_) => EventType::Ack, @@ -164,7 +170,7 @@ impl TryFrom<[u8; MAX_EVENT_SIZE]> for ProtoEvent { }, ))), EventType::Ping => Ok(Self::Ping), - EventType::Pong => Ok(Self::Pong), + EventType::Pong => Ok(Self::Pong(decode_u8(&mut buf)? != 0)), EventType::Enter => Ok(Self::Enter(decode_u8(&mut buf)?.try_into()?)), EventType::Leave => Ok(Self::Leave(decode_u32(&mut buf)?)), EventType::Ack => Ok(Self::Ack(decode_u32(&mut buf)?)), @@ -228,7 +234,7 @@ impl From for ([u8; MAX_EVENT_SIZE], usize) { }, }, ProtoEvent::Ping => {} - ProtoEvent::Pong => {} + ProtoEvent::Pong(alive) => encode_u8(buf, len, alive as u8), ProtoEvent::Enter(pos) => encode_u8(buf, len, pos as u8), ProtoEvent::Leave(serial) => encode_u32(buf, len, serial), ProtoEvent::Ack(serial) => encode_u32(buf, len, serial), diff --git a/src/client.rs b/src/client.rs index debf3c5..60aac85 100644 --- a/src/client.rs +++ b/src/client.rs @@ -224,27 +224,41 @@ impl ClientManager { .collect() } - pub(crate) fn set_active_addr(&self, handle: u64, addr: Option) { + pub(crate) fn set_active_addr(&self, handle: ClientHandle, 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 { + pub(crate) fn set_alive(&self, handle: ClientHandle, alive: bool) { + if let Some((_, s)) = self.clients.borrow_mut().get_mut(handle as usize) { + s.alive = alive; + } + } + + pub(crate) fn active_addr(&self, handle: ClientHandle) -> Option { self.clients .borrow() .get(handle as usize) .and_then(|(_, s)| s.active_addr) } - pub(crate) fn get_port(&self, handle: u64) -> Option { + pub(crate) fn alive(&self, handle: ClientHandle) -> bool { + self.clients + .borrow() + .get(handle as usize) + .map(|(_, s)| s.alive) + .unwrap_or(false) + } + + pub(crate) fn get_port(&self, handle: ClientHandle) -> Option { self.clients .borrow() .get(handle as usize) .map(|(c, _)| c.port) } - pub(crate) fn get_ips(&self, handle: u64) -> Option> { + pub(crate) fn get_ips(&self, handle: ClientHandle) -> Option> { self.clients .borrow() .get(handle as usize) diff --git a/src/connect.rs b/src/connect.rs index 35a62a4..a867f31 100644 --- a/src/connect.rs +++ b/src/connect.rs @@ -33,6 +33,8 @@ pub(crate) enum LanMouseConnectionError { Webrtc(#[from] webrtc_util::Error), #[error("not connected")] NotConnected, + #[error("emulation is disabled on the target device")] + TargetEmulationDisabled, } async fn connect( @@ -104,6 +106,9 @@ impl LanMouseConnection { conns.get(&addr).cloned() }; if let Some(conn) = conn { + if !self.server.client_manager.alive(handle) { + return Err(LanMouseConnectionError::TargetEmulationDisabled); + } log::trace!("{event} >->->->->- {addr}"); match conn.send(buf).await { Ok(_) => return Ok(()), @@ -220,7 +225,10 @@ async fn receive_loop( while let Ok(_) = conn.recv(&mut buf).await { if let Ok(event) = buf.try_into() { match event { - ProtoEvent::Pong => server.client_manager.set_active_addr(handle, Some(addr)), + ProtoEvent::Pong(b) => { + server.client_manager.set_active_addr(handle, Some(addr)); + server.client_manager.set_alive(handle, b); + } event => tx.send((handle, event)).expect("channel closed"), } } diff --git a/src/emulation.rs b/src/emulation.rs index 74105df..f2cd896 100644 --- a/src/emulation.rs +++ b/src/emulation.rs @@ -55,7 +55,7 @@ impl Emulation { listener.reply(addr, ProtoEvent::Ack(0)).await; } ProtoEvent::Input(event) => emulation_proxy.consume(event, addr), - ProtoEvent::Ping => listener.reply(addr, ProtoEvent::Pong).await, + ProtoEvent::Ping => listener.reply(addr, ProtoEvent::Pong(server.emulation_status.get() == Status::Enabled)).await, _ => {} } }