use core::net::{IpAddr, Ipv4Addr, SocketAddr};
#[cfg(feature = "std")]
use std::sync::Arc;
#[cfg(not(feature = "std"))]
use alloc::sync::Arc;
use crate::{
device::Device,
io::{IoImpl, TcpListenerImpl, TcpStreamImpl, TlsStreamImpl, UdpSocketImpl},
packet::{NetworkPacket, NetworkPacketBody},
};
async fn broadcast_udp_identity<
Io: IoImpl<UdpSocket, TcpStream, TcpListener, TlsStream> + Unpin + 'static,
UdpSocket: UdpSocketImpl + Unpin + 'static,
TcpStream: TcpStreamImpl + Unpin + 'static,
TcpListener: TcpListenerImpl<TcpStream> + Unpin + 'static,
TlsStream: TlsStreamImpl + Unpin + 'static,
>(
device: Arc<Device<Io, UdpSocket, TcpStream, TcpListener, TlsStream>>,
) {
let Ok(mut socket) = device
.io_impl
.bind_udp(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0))
.await
else {
return;
};
let my_identity_packet = device.get_identity_packet();
let serialized_my_identity_packet = serde_json::to_string(&my_identity_packet).unwrap();
socket.set_broadcast(true).unwrap();
let _ = socket
.send_to(
serialized_my_identity_packet.as_bytes(),
SocketAddr::new(IpAddr::V4(Ipv4Addr::BROADCAST), crate::config::UDP_PORT),
)
.await;
}
pub async fn setup_udp<
Io: IoImpl<UdpSocket, TcpStream, TcpListener, TlsStream> + Unpin + 'static,
UdpSocket: UdpSocketImpl + Unpin + 'static,
TcpStream: TcpStreamImpl + Unpin + 'static,
TcpListener: TcpListenerImpl<TcpStream> + Unpin + 'static,
TlsStream: TlsStreamImpl + Unpin + 'static,
>(
device: Arc<Device<Io, UdpSocket, TcpStream, TcpListener, TlsStream>>,
) {
broadcast_udp_identity(Arc::clone(&device)).await;
let Ok(udp_listener) = device
.io_impl
.bind_udp_reuse_v4(SocketAddr::new(
IpAddr::V4(Ipv4Addr::UNSPECIFIED),
crate::config::UDP_PORT,
))
.await
else {
return;
};
udp_listener.set_broadcast(true).unwrap();
let mut i = 0;
let mut buf = [0u8; crate::config::UDP_BUFFER_SIZE];
loop {
let Ok((bytes_read, mut addr)) = udp_listener.recv_from(&mut buf[i..]).await else {
log::warn!(
"UDP packet is too large, consider reading the documentation of config::UDP_BUFFER_SIZE"
);
i = 0;
continue;
};
i += bytes_read;
let device = Arc::clone(&device);
if let Ok(NetworkPacket {
body: NetworkPacketBody::Identity(packet),
..
}) = NetworkPacket::try_read_from(&buf[..i])
{
i = 0;
if packet.device_id == device.host_device_id {
log::trace!("Discovered myself, ignore the MDNS request");
continue;
}
if device.links.lock().await.contains_key(&packet.device_id) {
log::debug!(
"Device {} has already established connection, ignore the MDNS request",
packet.device_id
);
continue;
}
log::debug!("UDP Identity packet received, upgrading connection");
let Some(peer_tcp_port) = packet.get_tcp_port() else {
log::warn!(
"Peer device identity packet does not contain its TCP port, can't connect to it"
);
continue;
};
addr.set_port(peer_tcp_port);
let Ok(mut socket) = device.io_impl.connect_tcp(addr).await else {
log::warn!("Failed to make a TCP connection to the peer device");
continue;
};
socket.writable().await.unwrap();
device
.get_identity_packet()
.write_to_socket_unencrypted(&mut socket)
.await;
super::tls::upgrade_tcp_connection(packet, socket, device, false).await;
}
if bytes_read == 0 {
log::warn!("udp: Failed to parse the received JSON");
i = 0;
}
}
}