use std::{
marker::PhantomData,
net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs},
num::NonZeroUsize,
sync::{mpsc::Receiver, Arc, Barrier},
};
use quinn::{
crypto::rustls::QuicServerConfig, default_runtime, Connection, ConnectionError, Endpoint,
EndpointConfig, ReadError, ReadToEndError, VarInt,
};
use rustls::pki_types::PrivatePkcs8KeyDer;
use tokio::{runtime::Handle, sync::oneshot};
use crate::{
async_runtime::async_runtime,
disconnection::DisconnectionHandle,
net_traits::{NetReceive, NetSend},
receiving::receive_message_raw,
sending::{send_message, SendingResult, SendingStateHandle},
};
pub(crate) const SERVER_NAME: &str = "jaaj";
pub struct ServerListenerNetworking<S: NetSend, R: NetReceive> {
_async_runtime_handle: Handle,
local_port: u16,
client_receiver: Receiver<ClientOnServerNetworking<S, R>>,
}
impl<S: NetSend, R: NetReceive> ServerListenerNetworking<S, R> {
pub fn new(
desired_port: Option<u16>,
address: Option<IpAddr>,
thread_count: Option<NonZeroUsize>,
) -> ServerListenerNetworking<S, R> {
rustls::crypto::ring::default_provider()
.install_default()
.unwrap();
let async_runtime_handle = async_runtime(thread_count);
let async_runtime_handle_cloned = async_runtime_handle.clone();
let (client_sender, client_receiver) = std::sync::mpsc::channel();
let server_config = {
let cert = rcgen::generate_simple_self_signed(vec![SERVER_NAME.into()]).unwrap();
let key = PrivatePkcs8KeyDer::from(cert.key_pair.serialize_der()).into();
let certs = vec![cert.cert.into()];
let server_crypto = rustls::ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(certs, key)
.unwrap();
quinn::ServerConfig::with_crypto(Arc::new(
QuicServerConfig::try_from(server_crypto).unwrap(),
))
};
let socket = if let Some(desired_port) = desired_port {
#[derive(Clone)]
struct SocketAddrsToTry {
ip_addr: IpAddr,
next_port: u16,
}
impl Iterator for SocketAddrsToTry {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
let port = self.next_port;
self.next_port = self.next_port.wrapping_add(1);
Some(SocketAddr::new(self.ip_addr, port))
}
}
impl ToSocketAddrs for SocketAddrsToTry {
type Iter = SocketAddrsToTry;
fn to_socket_addrs(&self) -> std::io::Result<SocketAddrsToTry> {
Ok(self.clone())
}
}
let addresses_to_try = SocketAddrsToTry {
ip_addr: address.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)),
next_port: desired_port,
};
std::net::UdpSocket::bind(addresses_to_try).unwrap()
} else {
const PORT_UNSPECIFIED: u16 = 0;
let socket_address = SocketAddr::new(
address.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)),
PORT_UNSPECIFIED,
);
std::net::UdpSocket::bind(socket_address).unwrap()
};
let actual_server_address = socket.local_addr().unwrap();
async_runtime_handle.spawn(async move {
let endpoint = Endpoint::new(
EndpointConfig::default(),
Some(server_config),
socket,
default_runtime().unwrap(),
)
.unwrap();
tokio::spawn(async move {
loop {
let connection = endpoint.accept().await.unwrap().await.unwrap();
let client = ClientOnServerNetworking::new(
async_runtime_handle_cloned.clone(),
connection,
endpoint.clone(),
);
client_sender.send(client).unwrap();
}
});
});
ServerListenerNetworking {
_async_runtime_handle: async_runtime_handle,
local_port: actual_server_address.port(),
client_receiver,
}
}
pub fn server_port(&self) -> u16 {
self.local_port
}
pub fn poll_client(&self) -> Option<ClientOnServerNetworking<S, R>> {
self.client_receiver.try_recv().ok()
}
}
pub struct ClientOnServerNetworking<S: NetSend, R: NetReceive> {
async_runtime_handle: Handle,
connection: Connection,
endpoint: Endpoint,
receiving_receiver: Receiver<ClientOnServerEvent<R>>,
_phantom: PhantomData<S>,
}
pub enum ClientOnServerEvent<R: NetReceive> {
Message(R),
Disconnected(ClientOnServerDisconnectionDetails),
}
pub enum ClientOnServerDisconnectionDetails {
None,
Timeout,
}
fn connection_error_to_client_on_server_event<R: NetReceive>(
error: ConnectionError,
) -> Option<ClientOnServerEvent<R>> {
match error {
ConnectionError::ApplicationClosed(_thingy) => {
Some(ClientOnServerEvent::Disconnected(
ClientOnServerDisconnectionDetails::None,
))
}
ConnectionError::ConnectionClosed(_thingy) => {
Some(ClientOnServerEvent::Disconnected(
ClientOnServerDisconnectionDetails::None,
))
}
ConnectionError::LocallyClosed => {
None
}
ConnectionError::TimedOut => Some(ClientOnServerEvent::Disconnected(
ClientOnServerDisconnectionDetails::Timeout,
)),
error => {
panic!("{error}");
}
}
}
impl<S: NetSend, R: NetReceive> ClientOnServerNetworking<S, R> {
fn new(
async_runtime_handle: Handle,
connection: Connection,
endpoint: Endpoint,
) -> ClientOnServerNetworking<S, R> {
let (receiving_sender, receiving_receiver) = std::sync::mpsc::channel();
let connection_cloned = connection.clone();
tokio::spawn(async move {
loop {
match connection_cloned.accept_uni().await {
Ok(mut stream) => {
let receiving_sender_cloned = receiving_sender.clone();
tokio::spawn(async move {
match receive_message_raw(&mut stream).await {
Ok(message_raw) => {
let message: R =
rmp_serde::decode::from_slice(&message_raw).unwrap();
let event = ClientOnServerEvent::Message(message);
let _ = receiving_sender_cloned.send(event);
}
Err(ReadToEndError::Read(ReadError::ConnectionLost(error))) => {
let event = connection_error_to_client_on_server_event(error);
if let Some(event) = event {
let _ = receiving_sender_cloned.send(event);
}
}
Err(error) => {
panic!("{error}");
}
}
});
}
Err(error) => {
let event = connection_error_to_client_on_server_event(error);
if let Some(event) = event {
let _ = receiving_sender.send(event);
}
return;
}
};
}
});
ClientOnServerNetworking {
async_runtime_handle,
connection,
endpoint,
receiving_receiver,
_phantom: PhantomData,
}
}
pub fn client_address(&self) -> SocketAddr {
self.connection.remote_address()
}
pub fn send_message_to_client(&self, message: S) -> SendingStateHandle {
let connection = self.connection.clone();
let (result_sender, result_receiver) = oneshot::channel();
self.async_runtime_handle.spawn(async move {
let result = send_message(&connection, &message).await;
let _ = result_sender.send(SendingResult::from_result(result));
});
SendingStateHandle::from_result_receiver(result_receiver)
}
pub fn poll_event_from_client(&self) -> Option<ClientOnServerEvent<R>> {
self.receiving_receiver.try_recv().ok()
}
pub fn disconnect(&self) -> DisconnectionHandle {
self.connection.close(VarInt::from_u32(0), &[]);
let endpoint = self.endpoint.clone();
let barrier = Arc::new(Barrier::new(2));
let barrier_cloned = Arc::clone(&barrier);
self.async_runtime_handle.spawn(async move {
endpoint.wait_idle().await;
barrier_cloned.wait();
});
DisconnectionHandle::with_barrier(barrier)
}
}