lan_discovery_WOL: lan discovery almost done
Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
parent
7e0f7be95c
commit
cbb34fb021
@ -37,6 +37,7 @@ fn new_socket(addr: SocketAddr, reuse: bool, buf_size: usize) -> Result<Socket,
|
|||||||
addr,
|
addr,
|
||||||
socket.recv_buffer_size()
|
socket.recv_buffer_size()
|
||||||
);
|
);
|
||||||
|
socket.set_nonblocking(true)?;
|
||||||
socket.bind(&addr.into())?;
|
socket.bind(&addr.into())?;
|
||||||
Ok(socket)
|
Ok(socket)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
use crate::{
|
use crate::server::{check_zombie, new as new_server, ServerPtr};
|
||||||
ipc::get_id,
|
|
||||||
server::{check_zombie, new as new_server, ServerPtr},
|
|
||||||
};
|
|
||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
allow_err,
|
allow_err,
|
||||||
anyhow::bail,
|
anyhow::bail,
|
||||||
@ -13,6 +10,7 @@ use hbb_common::{
|
|||||||
sleep, socket_client,
|
sleep, socket_client,
|
||||||
tokio::{
|
tokio::{
|
||||||
self, select,
|
self, select,
|
||||||
|
sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
||||||
time::{interval, Duration},
|
time::{interval, Duration},
|
||||||
},
|
},
|
||||||
udp::FramedSocket,
|
udp::FramedSocket,
|
||||||
@ -20,6 +18,7 @@ use hbb_common::{
|
|||||||
};
|
};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs, UdpSocket},
|
net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs, UdpSocket},
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
@ -548,14 +547,20 @@ pub fn get_broadcast_port() -> u16 {
|
|||||||
(RENDEZVOUS_PORT + 3) as _
|
(RENDEZVOUS_PORT + 3) as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||||
pub struct DiscoveryPeer {
|
pub struct DiscoveryPeer {
|
||||||
id: String,
|
id: String,
|
||||||
mac: String,
|
mac_ips: HashMap<String, String>,
|
||||||
ip: String,
|
|
||||||
username: String,
|
username: String,
|
||||||
hostname: String,
|
hostname: String,
|
||||||
platform: String,
|
platform: String,
|
||||||
|
online: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiscoveryPeer {
|
||||||
|
fn is_same_peer(&self, other: &DiscoveryPeer) -> bool {
|
||||||
|
self.id == other.id && self.username == other.username
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mac(ip: &IpAddr) -> String {
|
pub fn get_mac(ip: &IpAddr) -> String {
|
||||||
@ -690,9 +695,9 @@ fn send_query() -> ResultType<Vec<UdpSocket>> {
|
|||||||
fn wait_response(
|
fn wait_response(
|
||||||
socket: UdpSocket,
|
socket: UdpSocket,
|
||||||
timeout: Option<std::time::Duration>,
|
timeout: Option<std::time::Duration>,
|
||||||
) -> ResultType<Vec<DiscoveryPeer>> {
|
tx: UnboundedSender<DiscoveryPeer>,
|
||||||
|
) -> ResultType<()> {
|
||||||
let mut last_recv_time = Instant::now();
|
let mut last_recv_time = Instant::now();
|
||||||
let mut peers = Vec::new();
|
|
||||||
|
|
||||||
socket.set_read_timeout(timeout)?;
|
socket.set_read_timeout(timeout)?;
|
||||||
loop {
|
loop {
|
||||||
@ -709,20 +714,18 @@ fn wait_response(
|
|||||||
"".to_owned()
|
"".to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_self = if !mac.is_empty() {
|
if mac != p.mac {
|
||||||
p.mac == mac
|
allow_err!(tx.send(DiscoveryPeer {
|
||||||
} else {
|
|
||||||
p.id == get_id()
|
|
||||||
};
|
|
||||||
if !is_self {
|
|
||||||
peers.push(DiscoveryPeer {
|
|
||||||
id: p.id.clone(),
|
id: p.id.clone(),
|
||||||
mac: p.mac.clone(),
|
mac_ips: HashMap::from([(
|
||||||
ip: addr.to_string(),
|
p.mac.clone(),
|
||||||
|
addr.ip().to_string()
|
||||||
|
)]),
|
||||||
username: p.username.clone(),
|
username: p.username.clone(),
|
||||||
hostname: p.hostname.clone(),
|
hostname: p.hostname.clone(),
|
||||||
platform: p.platform.clone(),
|
platform: p.platform.clone(),
|
||||||
});
|
online: true,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -734,40 +737,83 @@ fn wait_response(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(peers)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn discover() -> ResultType<()> {
|
fn spawn_wait_responses(sockets: Vec<UdpSocket>) -> UnboundedReceiver<DiscoveryPeer> {
|
||||||
let sockets = send_query()?;
|
let (tx, rx) = unbounded_channel::<_>();
|
||||||
let mut join_handles = Vec::new();
|
|
||||||
for socket in sockets {
|
for socket in sockets {
|
||||||
let handle = std::thread::spawn(move || {
|
let tx_clone = tx.clone();
|
||||||
wait_response(socket, Some(std::time::Duration::from_millis(10)))
|
std::thread::spawn(move || {
|
||||||
|
allow_err!(wait_response(
|
||||||
|
socket,
|
||||||
|
Some(std::time::Duration::from_millis(10)),
|
||||||
|
tx_clone
|
||||||
|
));
|
||||||
});
|
});
|
||||||
join_handles.push(handle);
|
|
||||||
}
|
}
|
||||||
|
rx
|
||||||
|
}
|
||||||
|
|
||||||
// to-do: load saved peers, and update incrementally (then we can see offline)
|
async fn handle_received_peers(mut rx: UnboundedReceiver<DiscoveryPeer>) -> ResultType<()> {
|
||||||
let mut peers: Vec<DiscoveryPeer> = match serde_json::from_str(&config::LanPeers::load().peers)
|
let mut peers: Vec<DiscoveryPeer> = match serde_json::from_str(&config::LanPeers::load().peers)
|
||||||
{
|
{
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
_ => Vec::new(),
|
_ => Vec::new(),
|
||||||
};
|
};
|
||||||
|
peers.iter_mut().for_each(|peer| {
|
||||||
|
peer.online = false;
|
||||||
|
});
|
||||||
|
|
||||||
for handle in join_handles {
|
// handle received peers
|
||||||
match handle.join() {
|
let mut response_set = HashSet::new();
|
||||||
Ok(Ok(mut tmp)) => {
|
let mut last_write_time = Instant::now() - std::time::Duration::from_secs(4);
|
||||||
peers.append(&mut tmp);
|
loop {
|
||||||
}
|
tokio::select! {
|
||||||
Ok(Err(e)) => {
|
data = rx.recv() => match data {
|
||||||
log::error!("Failed lan discove {e}");
|
Some(peer) => {
|
||||||
}
|
let in_response_set = !response_set.insert(peer.id.clone());
|
||||||
Err(e) => {
|
let mut pre_found = false;
|
||||||
log::error!("Failed join lan discove thread {e:?}");
|
for peer1 in &mut peers {
|
||||||
|
if peer1.is_same_peer(&peer) {
|
||||||
|
if in_response_set {
|
||||||
|
peer1.mac_ips.extend(peer.mac_ips.clone());
|
||||||
|
peer1.hostname = peer.hostname.clone();
|
||||||
|
peer1.platform = peer.platform.clone();
|
||||||
|
peer1.online = true;
|
||||||
|
} else {
|
||||||
|
*peer1 = peer.clone();
|
||||||
|
}
|
||||||
|
pre_found = true;
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !pre_found {
|
||||||
|
peers.push(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if last_write_time.elapsed().as_millis() > 300 {
|
||||||
|
config::LanPeers::store(serde_json::to_string(&peers)?);
|
||||||
|
last_write_time = Instant::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log::info!("discover ping done");
|
|
||||||
config::LanPeers::store(serde_json::to_string(&peers)?);
|
config::LanPeers::store(serde_json::to_string(&peers)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::main(flavor = "current_thread")]
|
||||||
|
pub async fn discover() -> ResultType<()> {
|
||||||
|
let sockets = send_query()?;
|
||||||
|
let rx = spawn_wait_responses(sockets);
|
||||||
|
handle_received_peers(rx).await?;
|
||||||
|
|
||||||
|
log::info!("discover ping done");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user