use std::{
collections::HashMap,
future::poll_fn,
io::Result,
sync::Arc,
task::{Context, Poll, Waker},
};
use statime_base::UniversalTimestamp;
use timestamped_socket::interface::InterfaceName;
use crate::{
BoundInterface, ConnectedSocket, MAX_PACKET_SIZE, NetworkManagerData, OpenSocket,
PtpAddressFamily, SocketData, TimestampSource,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RecvResult<A> {
pub bytes_read: Arc<[u8]>,
pub remote_addr: A,
pub local_addr: A,
pub timestamp: Option<UniversalTimestamp>,
}
impl<A: PtpAddressFamily> NetworkManagerData<A> {
fn recv_for_socket(&self, socket_id: usize, cx: &mut Context<'_>) -> Poll<Result<()>> {
self.read_wakers.add_waker(cx.waker().clone());
let mut buf = [0u8; MAX_PACKET_SIZE];
let sockets = self.sockets.read().unwrap();
let interfaces = self.interfaces.read().unwrap();
if let Some(interface_name) = sockets[&socket_id].interface_filter {
if let Poll::Ready(recv_result) = interfaces[&Some(interface_name)].interface.poll_recv(
&mut buf,
&mut Context::from_waker(&Waker::from(self.read_wakers.clone())),
) {
Poll::Ready(handle_recv_result(
&buf,
&sockets,
recv_result,
Some(interface_name),
))
} else {
Poll::Pending
}
} else {
for (&interface_name, interface) in interfaces.iter() {
if let Poll::Ready(recv_result) = interface.interface.poll_recv(
&mut buf,
&mut Context::from_waker(&Waker::from(self.read_wakers.clone())),
) {
return Poll::Ready(handle_recv_result(
&buf,
&sockets,
recv_result,
interface_name,
));
}
}
Poll::Pending
}
}
}
fn handle_recv_result<A: PtpAddressFamily>(
buf: &[u8],
sockets: &HashMap<usize, SocketData<A>>,
recv_result: Result<timestamped_socket::socket::RecvResult<A>>,
interface_name: Option<InterfaceName>,
) -> Result<()> {
match recv_result {
Ok(recv_result) => {
let bytes_read: Arc<[u8]> = buf[..recv_result.bytes_read].into();
for socket in sockets.values() {
if socket
.interface_filter
.is_none_or(|socket_interface| Some(socket_interface) == interface_name)
&& socket
.local_filter
.is_none_or(|addr| addr == recv_result.local_addr)
&& socket
.remote_filter
.is_none_or(|addr| addr == recv_result.remote_addr)
{
let _ = socket.message_channel.try_send(RecvResult {
bytes_read: bytes_read.clone(),
remote_addr: recv_result.remote_addr,
local_addr: recv_result.local_addr,
timestamp: match socket.timestamp_source {
TimestampSource::System => recv_result
.timestamp_data
.software
.map(UniversalTimestamp::from),
TimestampSource::Hardware => recv_result
.timestamp_data
.hardware
.map(UniversalTimestamp::from),
},
});
}
}
Ok(())
}
Err(e) => Err(e),
}
}
impl<A: PtpAddressFamily> OpenSocket<A> {
pub async fn recv(&mut self) -> Result<RecvResult<A>> {
poll_fn(|cx| {
loop {
if let Poll::Ready(Some(recv_packet)) = self.packet_receiver.poll_recv(cx) {
return Poll::Ready(Ok(recv_packet));
}
match self.state.recv_for_socket(self.socket_id, cx) {
Poll::Ready(Ok(())) => {}
Poll::Ready(Err(e)) => break Poll::Ready(Err(e)),
Poll::Pending => break Poll::Pending,
}
}
})
.await
}
}
impl<A: PtpAddressFamily> ConnectedSocket<A> {
pub async fn recv(&mut self) -> Result<RecvResult<A>> {
poll_fn(|cx| {
loop {
if let Poll::Ready(Some(recv_packet)) = self.packet_receiver.poll_recv(cx) {
return Poll::Ready(Ok(recv_packet));
}
match self.state.recv_for_socket(self.socket_id, cx) {
Poll::Ready(Ok(())) => {}
Poll::Ready(Err(e)) => break Poll::Ready(Err(e)),
Poll::Pending => break Poll::Pending,
}
}
})
.await
}
}