Files
game_engine/crates/voltex_net/src/socket.rs
tolelom 566990b7af feat(net): add UDP server/client with connection management
Adds NetSocket (non-blocking UdpSocket wrapper with local_addr), NetServer
(connection tracking via HashMap, poll/broadcast/send_to_client), and NetClient
(connect/poll/send/disconnect lifecycle). Includes an integration test on
127.0.0.1:0 that validates ClientConnected, Connected, and UserData receipt
end-to-end with 50ms sleeps to ensure UDP packet delivery.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 14:29:41 +09:00

59 lines
1.9 KiB
Rust

use std::net::{SocketAddr, UdpSocket};
use crate::Packet;
/// Maximum UDP datagram size we'll allocate for receiving.
const MAX_PACKET_SIZE: usize = 65535;
/// A non-blocking UDP socket wrapper.
pub struct NetSocket {
inner: UdpSocket,
}
impl NetSocket {
/// Bind a new non-blocking UDP socket to the given address.
pub fn bind(addr: &str) -> Result<Self, String> {
let socket = UdpSocket::bind(addr)
.map_err(|e| format!("UdpSocket::bind({}) failed: {}", addr, e))?;
socket
.set_nonblocking(true)
.map_err(|e| format!("set_nonblocking failed: {}", e))?;
Ok(NetSocket { inner: socket })
}
/// Returns the local address this socket is bound to.
pub fn local_addr(&self) -> SocketAddr {
self.inner.local_addr().expect("local_addr unavailable")
}
/// Serialize and send a packet to the given address.
pub fn send_to(&self, packet: &Packet, addr: SocketAddr) -> Result<(), String> {
let bytes = packet.to_bytes();
self.inner
.send_to(&bytes, addr)
.map_err(|e| format!("send_to failed: {}", e))?;
Ok(())
}
/// Try to receive one packet. Returns None on WouldBlock (no data available).
pub fn recv_from(&self) -> Option<(Packet, SocketAddr)> {
let mut buf = vec![0u8; MAX_PACKET_SIZE];
match self.inner.recv_from(&mut buf) {
Ok((len, addr)) => {
match Packet::from_bytes(&buf[..len]) {
Ok(packet) => Some((packet, addr)),
Err(e) => {
eprintln!("[NetSocket] Failed to parse packet from {}: {}", addr, e);
None
}
}
}
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => None,
Err(e) => {
eprintln!("[NetSocket] recv_from error: {}", e);
None
}
}
}
}