mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-18 18:50:56 +03:00
impl emulation stuff
This commit is contained in:
@@ -1,116 +0,0 @@
|
||||
use local_channel::mpsc::{Receiver, Sender};
|
||||
use std::{cell::RefCell, collections::HashMap, io, net::SocketAddr, rc::Rc, sync::Arc};
|
||||
use webrtc_dtls::{
|
||||
config::{Config, ExtendedMasterSecretType},
|
||||
conn::DTLSConn,
|
||||
crypto::Certificate,
|
||||
listener::listen,
|
||||
};
|
||||
use webrtc_util::{conn::Listener, Conn};
|
||||
|
||||
use thiserror::Error;
|
||||
use tokio::{
|
||||
net::UdpSocket,
|
||||
task::{spawn_local, JoinHandle},
|
||||
};
|
||||
|
||||
use crate::crypto;
|
||||
|
||||
use super::Server;
|
||||
use lan_mouse_proto::{ProtoEvent, ProtocolError};
|
||||
|
||||
pub(crate) async fn new(
|
||||
server: Server,
|
||||
udp_recv_tx: Sender<Result<(ProtoEvent, SocketAddr), NetworkError>>,
|
||||
udp_send_rx: Receiver<(ProtoEvent, SocketAddr)>,
|
||||
) -> io::Result<JoinHandle<()>> {
|
||||
// bind the udp socket
|
||||
let listen_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), server.port.get());
|
||||
|
||||
Ok(spawn_local(async move {
|
||||
let sender_rx = Rc::new(RefCell::new(udp_send_rx));
|
||||
let udp_receiver = spawn_local(listen_dtls(listen_addr, udp_recv_tx.clone()));
|
||||
let udp_sender = spawn_local(udp_sender(sender_rx.clone()));
|
||||
log::info!("starting sender + receiver");
|
||||
tokio::select! {
|
||||
e = udp_receiver => panic!("{e:?}"), /* channel closed */
|
||||
_ = udp_sender => {}, /* channel closed */
|
||||
_ = server.cancelled() => {}, /* cancellation requested */
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
async fn listen_dtls(
|
||||
listen_addr: SocketAddr,
|
||||
udp_recv_tx: Sender<Result<(ProtoEvent, SocketAddr), NetworkError>>,
|
||||
) -> Result<(), NetworkError> {
|
||||
let certificate = Certificate::generate_self_signed(vec!["localhost".to_owned()]).unwrap();
|
||||
let cfg = Config {
|
||||
certificates: vec![certificate],
|
||||
extended_master_secret: ExtendedMasterSecretType::Require,
|
||||
..Default::default()
|
||||
};
|
||||
let listener = Arc::new(listen(listen_addr, cfg).await?);
|
||||
loop {
|
||||
while let Ok((conn, addr)) = listener.accept().await {
|
||||
let udp_recv_tx = udp_recv_tx.clone();
|
||||
spawn_local(async move {
|
||||
loop {
|
||||
let mut buf = [0u8; lan_mouse_proto::MAX_EVENT_SIZE];
|
||||
let event: Result<_, NetworkError> = match conn.recv(&mut buf).await {
|
||||
Ok(_len) => match ProtoEvent::try_from(buf) {
|
||||
Ok(e) => Ok((e, addr)),
|
||||
Err(e) => Err(e.into()),
|
||||
},
|
||||
Err(e) => Err(e.into()),
|
||||
};
|
||||
udp_recv_tx.send(event).expect("channel closed");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn udp_sender(rx: Rc<RefCell<Receiver<(ProtoEvent, SocketAddr)>>>) {
|
||||
let mut connection_pool: HashMap<SocketAddr, DTLSConn> = HashMap::new();
|
||||
loop {
|
||||
log::error!("waiting for event to send ...");
|
||||
let (event, addr) = rx.borrow_mut().recv().await.expect("channel closed");
|
||||
let addr = SocketAddr::new(addr.ip(), 4242);
|
||||
if !connection_pool.contains_key(&addr) {
|
||||
let socket = Arc::new(UdpSocket::bind("0.0.0.0:0").await.unwrap());
|
||||
socket.connect(addr).await.unwrap();
|
||||
let certificate =
|
||||
Certificate::generate_self_signed(vec!["localhost".to_owned()]).unwrap();
|
||||
let config = Config {
|
||||
certificates: vec![certificate],
|
||||
insecure_skip_verify: true,
|
||||
extended_master_secret: ExtendedMasterSecretType::Require,
|
||||
..Default::default()
|
||||
};
|
||||
log::error!("connecting to {addr}");
|
||||
let conn = DTLSConn::new(socket, config, true, None).await.unwrap();
|
||||
log::error!("connected {addr}!");
|
||||
connection_pool.insert(addr, conn);
|
||||
};
|
||||
let conn = connection_pool.get(&addr).unwrap();
|
||||
let (data, len): ([u8; lan_mouse_proto::MAX_EVENT_SIZE], usize) = event.into();
|
||||
conn.send(&data[..len]).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum NetworkError {
|
||||
#[error(transparent)]
|
||||
Protocol(#[from] ProtocolError),
|
||||
#[error("network error: `{0}`")]
|
||||
Io(#[from] io::Error),
|
||||
#[error(transparent)]
|
||||
Crypt(#[from] crypto::Error),
|
||||
#[error(transparent)]
|
||||
Rustls(#[from] rustls::Error),
|
||||
#[error(transparent)]
|
||||
WebrtcDtls(#[from] webrtc_dtls::Error),
|
||||
#[error(transparent)]
|
||||
WebrtcUtil(#[from] webrtc_util::Error),
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
use std::{net::SocketAddr, time::Duration};
|
||||
|
||||
use lan_mouse_proto::ProtoEvent;
|
||||
use local_channel::mpsc::Sender;
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
use lan_mouse_ipc::ClientHandle;
|
||||
|
||||
use super::{capture_task::CaptureRequest, emulation_task::EmulationRequest, Server, State};
|
||||
|
||||
const MAX_RESPONSE_TIME: Duration = Duration::from_millis(500);
|
||||
|
||||
pub(crate) fn new(
|
||||
server: Server,
|
||||
sender_ch: Sender<(ProtoEvent, SocketAddr)>,
|
||||
emulate_notify: Sender<EmulationRequest>,
|
||||
capture_notify: Sender<CaptureRequest>,
|
||||
) -> JoinHandle<()> {
|
||||
// timer task
|
||||
tokio::task::spawn_local(async move {
|
||||
tokio::select! {
|
||||
_ = server.notifies.cancel.cancelled() => {}
|
||||
_ = ping_task(&server, sender_ch, emulate_notify, capture_notify) => {}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async fn ping_task(
|
||||
server: &Server,
|
||||
sender_ch: Sender<(ProtoEvent, SocketAddr)>,
|
||||
emulate_notify: Sender<EmulationRequest>,
|
||||
capture_notify: Sender<CaptureRequest>,
|
||||
) {
|
||||
loop {
|
||||
// wait for wake up signal
|
||||
server.ping_timer_notified().await;
|
||||
loop {
|
||||
let receiving = server.state.get() == State::Receiving;
|
||||
let (ping_clients, ping_addrs) = {
|
||||
let mut client_manager = server.client_manager.borrow_mut();
|
||||
|
||||
let ping_clients: Vec<ClientHandle> = if receiving {
|
||||
// if receiving we care about clients with pressed keys
|
||||
client_manager
|
||||
.get_client_states()
|
||||
.filter(|(_, (_, s))| s.has_pressed_keys)
|
||||
.map(|(h, _)| h)
|
||||
.collect()
|
||||
} else {
|
||||
// if sending we care about the active client
|
||||
server.active_client.get().iter().cloned().collect()
|
||||
};
|
||||
|
||||
// get relevant socket addrs for clients
|
||||
let ping_addrs: Vec<SocketAddr> = {
|
||||
ping_clients
|
||||
.iter()
|
||||
.flat_map(|&h| client_manager.get(h))
|
||||
.flat_map(|(c, s)| {
|
||||
if s.alive && s.active_addr.is_some() {
|
||||
vec![s.active_addr.unwrap()]
|
||||
} else {
|
||||
s.ips
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|ip| SocketAddr::new(ip, c.port))
|
||||
.collect()
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
||||
// reset alive
|
||||
for (_, (_, s)) in client_manager.get_client_states_mut() {
|
||||
s.alive = false;
|
||||
}
|
||||
|
||||
(ping_clients, ping_addrs)
|
||||
};
|
||||
|
||||
if receiving && ping_clients.is_empty() {
|
||||
// receiving and no client has pressed keys
|
||||
// -> no need to keep pinging
|
||||
break;
|
||||
}
|
||||
|
||||
// ping clients
|
||||
for addr in ping_addrs {
|
||||
if sender_ch.send((ProtoEvent::Ping, addr)).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// give clients time to resond
|
||||
if receiving {
|
||||
log::trace!(
|
||||
"waiting {MAX_RESPONSE_TIME:?} for response from client with pressed keys ..."
|
||||
);
|
||||
} else {
|
||||
log::trace!(
|
||||
"state: {:?} => waiting {MAX_RESPONSE_TIME:?} for client to respond ...",
|
||||
server.state.get()
|
||||
);
|
||||
}
|
||||
|
||||
tokio::time::sleep(MAX_RESPONSE_TIME).await;
|
||||
|
||||
// when anything is received from a client,
|
||||
// the alive flag gets set
|
||||
let unresponsive_clients: Vec<_> = {
|
||||
let client_manager = server.client_manager.borrow();
|
||||
ping_clients
|
||||
.iter()
|
||||
.filter_map(|&h| match client_manager.get(h) {
|
||||
Some((_, s)) if !s.alive => Some(h),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
||||
// we may not be receiving anymore but we should respond
|
||||
// to the original state and not the "new" one
|
||||
if receiving {
|
||||
for h in unresponsive_clients {
|
||||
log::warn!("device not responding, releasing keys!");
|
||||
let _ = emulate_notify.send(EmulationRequest::ReleaseKeys(h));
|
||||
}
|
||||
} else {
|
||||
// release pointer if the active client has not responded
|
||||
if !unresponsive_clients.is_empty() {
|
||||
log::warn!("client not responding, releasing pointer!");
|
||||
server.state.replace(State::Receiving);
|
||||
let _ = capture_notify.send(CaptureRequest::Release);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user