1use std::io::{self};
2use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
3
4use socket2::{Domain, Protocol, Socket, Type};
5
6use crate::transceiver::Transceiver;
7
8#[derive(thiserror::Error, Debug)]
9#[error("failed to create and bind udp socket: {0}")]
10pub struct Error(#[from] std::io::Error);
11
12pub type Result<T> = std::result::Result<T, Error>;
13
14pub struct NetcodeSocket(UdpSocket);
37
38impl NetcodeSocket {
39 pub fn new(
40 addr: impl ToSocketAddrs,
41 send_buf_size: usize,
42 recv_buf_size: usize,
43 ) -> Result<Self> {
44 let addr = addr.to_socket_addrs()?.next().ok_or_else(|| {
45 io::Error::new(io::ErrorKind::InvalidInput, "no socket addresses found")
46 })?;
47 let socket = Socket::new(Domain::for_address(addr), Type::DGRAM, Some(Protocol::UDP))?;
48 if addr.is_ipv6() {
49 socket.set_only_v6(true)?;
50 }
51 socket.set_send_buffer_size(send_buf_size)?;
52 socket.set_recv_buffer_size(recv_buf_size)?;
53 socket.bind(&addr.into())?;
54 socket.set_nonblocking(true)?;
55 Ok(NetcodeSocket(socket.into()))
56 }
57}
58
59impl Transceiver for NetcodeSocket {
60 type IntoError = Error;
61
62 fn addr(&self) -> SocketAddr {
63 self.0.local_addr().expect("address should be bound")
64 }
65
66 fn recv(&self, buf: &mut [u8]) -> Result<Option<(usize, SocketAddr)>> {
67 match self.0.recv_from(buf) {
68 Ok((len, addr)) if len > 0 => Ok(Some((len, addr))),
69 Ok(_) => Ok(None),
70 Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
71 Err(e) => Err(Error::from(e)),
72 }
73 }
74
75 fn send(&self, buf: &[u8], addr: SocketAddr) -> Result<usize> {
76 match self.0.send_to(buf, addr) {
77 Ok(len) => Ok(len),
78 Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(0),
79 Err(e) => Err(Error::from(e)),
80 }
81 }
82}