#[cfg(windows)]
mod platform {
use super::*;
const UDP_CONTROL_SEND_TIMEOUT: std::time::Duration =
std::time::Duration::from_millis(100);
pub struct UdpRawSocket {
inner: Socket,
local_addr: SocketAddr,
}
impl UdpRawSocket {
pub fn open(
bind_addr: SocketAddr,
recv_buf_size: usize,
send_buf_size: usize,
) -> Result<Self, TransportError> {
let domain = if bind_addr.is_ipv4() {
Domain::IPV4
} else {
Domain::IPV6
};
let sock = Socket::new(domain, Type::DGRAM, Some(Protocol::UDP))
.map_err(|e| TransportError::StartFailed(format!("socket create failed: {}", e)))?;
sock.set_nonblocking(true).map_err(|e| {
TransportError::StartFailed(format!("set nonblocking failed: {}", e))
})?;
let _ = sock.set_reuse_address(true);
sock.bind(&bind_addr.into())
.map_err(|e| TransportError::StartFailed(format!("bind failed: {}", e)))?;
sock.set_recv_buffer_size(recv_buf_size)
.map_err(|e| TransportError::StartFailed(format!("set recv buffer: {}", e)))?;
sock.set_send_buffer_size(send_buf_size)
.map_err(|e| TransportError::StartFailed(format!("set send buffer: {}", e)))?;
let local_addr = sock
.local_addr()
.map_err(|e| TransportError::StartFailed(format!("get local addr: {}", e)))?
.as_socket()
.ok_or_else(|| {
TransportError::StartFailed("local address is not an IP socket".into())
})?;
Ok(Self {
inner: sock,
local_addr,
})
}
pub fn adopt(
socket: std::net::UdpSocket,
recv_buf_size: usize,
send_buf_size: usize,
) -> Result<Self, TransportError> {
let sock = Socket::from(socket);
sock.set_nonblocking(true).map_err(|e| {
TransportError::StartFailed(format!("set nonblocking failed: {}", e))
})?;
sock.set_recv_buffer_size(recv_buf_size)
.map_err(|e| TransportError::StartFailed(format!("set recv buffer: {}", e)))?;
sock.set_send_buffer_size(send_buf_size)
.map_err(|e| TransportError::StartFailed(format!("set send buffer: {}", e)))?;
let local_addr = sock
.local_addr()
.map_err(|e| TransportError::StartFailed(format!("get local addr: {}", e)))?
.as_socket()
.ok_or_else(|| {
TransportError::StartFailed("local address is not an IP socket".into())
})?;
Ok(Self {
inner: sock,
local_addr,
})
}
pub fn local_addr(&self) -> SocketAddr {
self.local_addr
}
pub fn recv_buffer_size(&self) -> Result<usize, TransportError> {
self.inner
.recv_buffer_size()
.map_err(|e| TransportError::StartFailed(format!("get recv buffer: {}", e)))
}
pub fn send_buffer_size(&self) -> Result<usize, TransportError> {
self.inner
.send_buffer_size()
.map_err(|e| TransportError::StartFailed(format!("get send buffer: {}", e)))
}
pub fn into_async(self) -> Result<AsyncUdpSocket, TransportError> {
let std_socket: std::net::UdpSocket = self.inner.into();
let tokio_socket = tokio::net::UdpSocket::from_std(std_socket)
.map_err(|e| TransportError::StartFailed(format!("tokio socket failed: {}", e)))?;
Ok(AsyncUdpSocket {
inner: Arc::new(tokio_socket),
})
}
}
#[derive(Clone)]
pub struct AsyncUdpSocket {
inner: Arc<tokio::net::UdpSocket>,
}
impl AsyncUdpSocket {
pub async fn send_to(
&self,
data: &[u8],
dest: &SocketAddr,
) -> Result<usize, TransportError> {
match tokio::time::timeout(UDP_CONTROL_SEND_TIMEOUT, self.inner.send_to(data, dest))
.await
{
Ok(result) => {
result.map_err(|e| TransportError::SendFailed(format!("{}", e)))
}
Err(_) => Err(TransportError::Timeout),
}
}
pub async fn recv_from(
&self,
buf: &mut [u8],
) -> Result<(usize, SocketAddr, u32, usize), TransportError> {
let (n, addr) = self
.inner
.recv_from(buf)
.await
.map_err(|e| TransportError::RecvFailed(format!("{}", e)))?;
Ok((n, addr, 0, 0))
}
}
}
pub use platform::{AsyncUdpSocket, UdpRawSocket};
#[cfg(test)]
#[path = "socket/tests.rs"]
mod tests;