added most features
This commit is contained in:
parent
3163644c62
commit
6a3324563c
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,2 @@
|
|||||||
/target
|
/target
|
||||||
db.json
|
cache.json
|
||||||
|
8
config.json
Normal file
8
config.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"allowed_ports": [
|
||||||
|
[
|
||||||
|
3000,
|
||||||
|
3005
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
499
src/main.rs
499
src/main.rs
@ -1,38 +1,38 @@
|
|||||||
#![feature(generic_const_exprs)]
|
// #![allow(unused)]
|
||||||
#![allow(unused)]
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
collections::{BTreeSet, HashMap, HashSet},
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
fs::File,
|
fs::File,
|
||||||
future::Future,
|
|
||||||
io::{BufReader, BufWriter},
|
io::{BufReader, BufWriter},
|
||||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
net::{IpAddr, SocketAddr},
|
||||||
ops::Range,
|
ops::Range,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::{Arc, Mutex},
|
sync::Arc,
|
||||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::{anyhow, bail};
|
||||||
use packets::{reject_static, Header, Packet, RemConnect};
|
use packets::{Header, Packet, RemConnect};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncReadExt, AsyncWriteExt},
|
io::AsyncWriteExt,
|
||||||
net::{TcpListener, TcpSocket, TcpStream},
|
net::{TcpListener, TcpStream},
|
||||||
select,
|
select,
|
||||||
|
sync::Mutex,
|
||||||
task::JoinHandle,
|
task::JoinHandle,
|
||||||
time::Instant,
|
time::{sleep, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::packets::dyn_ip_update;
|
use crate::packets::{dyn_ip_update, PacketKind, REJECT_OOP, REJECT_TIMEOUT};
|
||||||
|
|
||||||
const AUTH_TIMEOUT: Duration = Duration::from_secs(30);
|
const AUTH_TIMEOUT: Duration = Duration::from_secs(30);
|
||||||
const CALL_ACK_TIMEOUT: Duration = Duration::from_secs(30);
|
const CALL_ACK_TIMEOUT: Duration = Duration::from_secs(30);
|
||||||
const PING_INTERVAL: Duration = Duration::from_secs(15);
|
const CALL_TIMEOUT: Duration = Duration::from_secs(24 * 60 * 60);
|
||||||
const TIMEOUT_DELAY: Duration = Duration::from_secs(35);
|
const PORT_RETRY_TIME: Duration = Duration::from_secs(15 * 60);
|
||||||
const PORT_TIMEOUT: Duration = Duration::from_secs(60);
|
const PORT_OWNERSHIP_TIMEOUT: Duration = Duration::from_secs(1 * 60 * 60);
|
||||||
const PORT_RETRY_TIME: Duration = Duration::from_secs(60); // 10 *
|
const PING_TIMEOUT: Duration = Duration::from_secs(30);
|
||||||
|
const SEND_PING_INTERVAL: Duration = Duration::from_secs(30);
|
||||||
|
|
||||||
const BIND_IP: &str = "0.0.0.0";
|
const BIND_IP: &str = "0.0.0.0";
|
||||||
|
|
||||||
@ -48,14 +48,14 @@ struct Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
fn load(db: &Path) -> std::io::Result<Self> {
|
fn load(cache: &Path) -> std::io::Result<Self> {
|
||||||
println!("loading config");
|
println!("loading config");
|
||||||
Ok(serde_json::from_reader(BufReader::new(File::open(db)?))?)
|
Ok(serde_json::from_reader(BufReader::new(File::open(cache)?))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_or_default(db: &Path) -> std::io::Result<Self> {
|
fn load_or_default(cache: &Path) -> std::io::Result<Self> {
|
||||||
match Self::load(db) {
|
match Self::load(cache) {
|
||||||
Ok(db) => Ok(db),
|
Ok(cache) => Ok(cache),
|
||||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(Self::default()),
|
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(Self::default()),
|
||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
@ -75,11 +75,40 @@ struct PortHandler {
|
|||||||
free_ports: HashSet<Port>,
|
free_ports: HashSet<Port>,
|
||||||
errored_ports: BTreeSet<(UnixTimestamp, Port)>,
|
errored_ports: BTreeSet<(UnixTimestamp, Port)>,
|
||||||
allocated_ports: HashMap<Number, Port>,
|
allocated_ports: HashMap<Number, Port>,
|
||||||
port_status: HashMap<Port, PortStatus>,
|
|
||||||
|
#[serde(skip)]
|
||||||
|
port_state: HashMap<Port, PortState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Default, Debug)]
|
||||||
struct PortStatus {}
|
struct PortState {
|
||||||
|
last_change: UnixTimestamp,
|
||||||
|
status: PortStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PortState {
|
||||||
|
fn new_state(&mut self, status: PortStatus) {
|
||||||
|
self.last_change = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_secs();
|
||||||
|
|
||||||
|
self.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
enum PortStatus {
|
||||||
|
Disconnected,
|
||||||
|
Idle,
|
||||||
|
InCall,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PortStatus {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Disconnected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||||
struct AllowedPorts(Vec<Range<u16>>);
|
struct AllowedPorts(Vec<Range<u16>>);
|
||||||
@ -95,23 +124,19 @@ impl PortHandler {
|
|||||||
self.last_update = Some(Instant::now());
|
self.last_update = Some(Instant::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store(&self, db: &Path) -> anyhow::Result<()> {
|
fn store(&self, cache: &Path) -> anyhow::Result<()> {
|
||||||
println!("storing database");
|
println!("storing database");
|
||||||
serde_json::to_writer(BufWriter::new(File::create(db)?), self)?;
|
serde_json::to_writer(BufWriter::new(File::create(cache)?), self)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(db: &Path) -> std::io::Result<Self> {
|
fn load(cache: &Path) -> std::io::Result<Self> {
|
||||||
println!("loading database");
|
println!("loading database");
|
||||||
Ok(serde_json::from_reader(BufReader::new(File::open(db)?))?)
|
Ok(serde_json::from_reader(BufReader::new(File::open(cache)?))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_or_default(db: &Path) -> std::io::Result<Self> {
|
fn load_or_default(cache: &Path) -> Self {
|
||||||
match Self::load(db) {
|
Self::load(cache).unwrap_or(Self::default())
|
||||||
Ok(db) => Ok(db),
|
|
||||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(Self::default()),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_allowed_ports(&mut self, allowed_ports: &AllowedPorts) {
|
fn update_allowed_ports(&mut self, allowed_ports: &AllowedPorts) {
|
||||||
@ -144,37 +169,48 @@ impl PortHandler {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_port_guard<'fut, Fut, Func>(&mut self, port: Port, listener: TcpListener, f: Func)
|
fn start_rejector(
|
||||||
where
|
&mut self,
|
||||||
Fut: Future<Output = ()> + Send + 'fut,
|
port: Port,
|
||||||
Func: FnOnce(&'_ mut TcpListener) -> Fut + Send + 'static,
|
listener: TcpListener,
|
||||||
{
|
packet: Packet,
|
||||||
assert!(self
|
) -> anyhow::Result<()> {
|
||||||
.port_guards
|
println!("starting rejector: for port {port} with packet {packet:?}");
|
||||||
.insert(port, PortGuard::start(listener, f))
|
|
||||||
.is_none());
|
let port_guard = PortGuard::start(listener, packet);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
self.port_guards.insert(port, port_guard).is_none(),
|
||||||
|
"Tried to start rejector that is already running.
|
||||||
|
This should have been impossible since it requires two listeners on the same port."
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_rejector(&mut self, port: Port, listener: TcpListener, packet: Packet) {
|
async fn stop_rejector(&mut self, port: Port) -> Option<(TcpListener, Packet)> {
|
||||||
assert!(self
|
println!("stopping rejector: for port {port}");
|
||||||
.port_guards
|
|
||||||
.insert(
|
Some(self.port_guards.remove(&port)?.stop().await)
|
||||||
port,
|
}
|
||||||
PortGuard::start(listener, move |listener: &mut TcpListener| async move {
|
|
||||||
loop {
|
async fn change_rejector(
|
||||||
if let Ok((mut socket, _)) = listener.accept().await {
|
&mut self,
|
||||||
let (_, mut writer) = socket.split();
|
port: Port,
|
||||||
let _ = packet.send(&mut writer).await;
|
f: impl FnOnce(&mut Packet),
|
||||||
}
|
) -> anyhow::Result<()> {
|
||||||
}
|
let (listener, mut packet) = self
|
||||||
})
|
.stop_rejector(port)
|
||||||
)
|
.await
|
||||||
.is_none());
|
.ok_or_else(|| anyhow!("tried to stop rejector that is not running"))?;
|
||||||
|
|
||||||
|
f(&mut packet);
|
||||||
|
|
||||||
|
self.start_rejector(port, listener, packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PortGuard {
|
struct PortGuard {
|
||||||
listener: Arc<tokio::sync::Mutex<TcpListener>>,
|
state: Arc<(Mutex<TcpListener>, Packet)>,
|
||||||
handle: JoinHandle<()>,
|
handle: JoinHandle<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,38 +221,46 @@ impl Debug for PortGuard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PortGuard {
|
impl PortGuard {
|
||||||
fn start<'fut, Fut>(
|
fn start(listener: TcpListener, packet: Packet) -> Self {
|
||||||
listener: TcpListener,
|
let state = Arc::new((Mutex::new(listener), packet));
|
||||||
f: impl FnOnce(&mut TcpListener) -> Fut + Send + 'static,
|
|
||||||
) -> Self
|
|
||||||
where
|
|
||||||
Fut: Future<Output = ()> + Send + 'fut,
|
|
||||||
{
|
|
||||||
let mut listener = Arc::new(tokio::sync::Mutex::new(listener));
|
|
||||||
|
|
||||||
let handle = {
|
let handle = {
|
||||||
let listener = listener.clone();
|
let state = state.clone();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut lock = listener.lock().await;
|
let (listener, packet) = state.as_ref();
|
||||||
f(&mut *lock).await;
|
|
||||||
|
let listener = listener.lock().await;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Ok((mut socket, _)) = listener.accept().await {
|
||||||
|
let (_, mut writer) = socket.split();
|
||||||
|
let _ = packet.send(&mut writer).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
Self { listener, handle }
|
Self { state, handle }
|
||||||
}
|
}
|
||||||
|
async fn stop(self) -> (TcpListener, Packet) {
|
||||||
async fn stop(mut self) -> TcpListener {
|
|
||||||
self.handle.abort();
|
self.handle.abort();
|
||||||
let _ = self.handle.await;
|
let _ = self.handle.await;
|
||||||
Arc::try_unwrap(self.listener).unwrap().into_inner()
|
let (listener, packet) = Arc::try_unwrap(self.state).unwrap();
|
||||||
|
(listener.into_inner(), packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PortHandler {
|
impl PortHandler {
|
||||||
fn allocate_port_for_number(&mut self, number: Number) -> Option<Port> {
|
fn allocate_port_for_number(&mut self, number: Number) -> Option<Port> {
|
||||||
if let Some(port) = self.allocated_ports.get(&number) {
|
if let Some(port) = self.allocated_ports.get(&number) {
|
||||||
return Some(*port);
|
let already_connected = self
|
||||||
|
.port_state
|
||||||
|
.get(port)
|
||||||
|
.map(|state| state.status != PortStatus::Disconnected)
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
return if already_connected { None } else { Some(*port) };
|
||||||
}
|
}
|
||||||
|
|
||||||
let port = if let Some(&port) = self.free_ports.iter().next() {
|
let port = if let Some(&port) = self.free_ports.iter().next() {
|
||||||
@ -238,7 +282,7 @@ impl PortHandler {
|
|||||||
|
|
||||||
self.errored_ports = std::mem::take(&mut self.errored_ports)
|
self.errored_ports = std::mem::take(&mut self.errored_ports)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(mut timestamp, mut port)| {
|
.filter_map(|(mut timestamp, port)| {
|
||||||
if recovered_port.is_none()
|
if recovered_port.is_none()
|
||||||
&& now.saturating_sub(Duration::from_secs(timestamp)) >= PORT_RETRY_TIME
|
&& now.saturating_sub(Duration::from_secs(timestamp)) >= PORT_RETRY_TIME
|
||||||
{
|
{
|
||||||
@ -268,10 +312,31 @@ impl PortHandler {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if let Some((_, port)) = recovered_port {
|
if let Some((_, port)) = recovered_port {
|
||||||
|
self.register_update();
|
||||||
println!("recovered_port: {port}");
|
println!("recovered_port: {port}");
|
||||||
return Some(port);
|
return Some(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let removable_entry = self.allocated_ports.iter().find(|(_, port)| {
|
||||||
|
self.port_state
|
||||||
|
.get(port)
|
||||||
|
.map(|port_state| {
|
||||||
|
dbg!(port_state).status == PortStatus::Disconnected
|
||||||
|
&& dbg!(now.saturating_sub(Duration::from_secs(port_state.last_change)))
|
||||||
|
>= PORT_OWNERSHIP_TIMEOUT
|
||||||
|
})
|
||||||
|
.unwrap_or(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
dbg!(&removable_entry);
|
||||||
|
|
||||||
|
if let Some((&old_number, &port)) = removable_entry {
|
||||||
|
self.register_update();
|
||||||
|
println!("reused port {port} which used to be allocated to {old_number} which wasn't connected in a long time");
|
||||||
|
assert!(self.allocated_ports.remove(&old_number).is_some());
|
||||||
|
return Some(port);
|
||||||
|
}
|
||||||
|
|
||||||
None // TODO
|
None // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,92 +354,241 @@ impl PortHandler {
|
|||||||
self.allocated_ports.remove(&number);
|
self.allocated_ports.remove(&number);
|
||||||
self.free_ports.remove(&port);
|
self.free_ports.remove(&port);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn open_port(&mut self, port: Port) -> Option<TcpListener> {
|
#[derive(Debug, Default)]
|
||||||
todo!()
|
struct HandlerMetadata {
|
||||||
}
|
number: Option<Number>,
|
||||||
|
port: Option<Port>,
|
||||||
fn close_port_for(&mut self, number: Number, listener: TcpListener) -> anyhow::Result<()> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn connection_handler(
|
async fn connection_handler(
|
||||||
port_handler: Arc<Mutex<PortHandler>>,
|
handler_metadata: &mut HandlerMetadata,
|
||||||
|
port_handler: &Mutex<PortHandler>,
|
||||||
stream: &mut TcpStream,
|
stream: &mut TcpStream,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let (mut reader, mut writer) = stream.split();
|
let (mut reader, mut writer) = stream.split();
|
||||||
|
|
||||||
let mut packet = Packet::recv(&mut reader).await?;
|
let mut packet = Packet::default();
|
||||||
|
|
||||||
|
select! {
|
||||||
|
res = packet.recv_into_cancelation_safe(&mut reader) => res?,
|
||||||
|
_ = sleep(AUTH_TIMEOUT) => {
|
||||||
|
writer.write_all(REJECT_TIMEOUT).await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let RemConnect { number, pin } = packet.as_rem_connect()?;
|
let RemConnect { number, pin } = packet.as_rem_connect()?;
|
||||||
|
|
||||||
|
handler_metadata.number = Some(number);
|
||||||
|
|
||||||
|
let mut authenticated = false;
|
||||||
let (port, listener) = loop {
|
let (port, listener) = loop {
|
||||||
let port = port_handler
|
let mut updated_server = false;
|
||||||
.lock()
|
|
||||||
.unwrap()
|
let port = port_handler.lock().await.allocate_port_for_number(number);
|
||||||
.allocate_port_for_number(number);
|
|
||||||
|
|
||||||
println!("allocated port: {:?}", port);
|
println!("allocated port: {:?}", port);
|
||||||
|
|
||||||
let Some(port) = port else {
|
let Some(port) = port else {
|
||||||
writer.write_all(&reject_static(b"oop")).await?;
|
writer.write_all(REJECT_OOP).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let ip = dyn_ip_update(number, pin, port).await?;
|
if !authenticated {
|
||||||
|
let _ip = dyn_ip_update(number, pin, port).await?;
|
||||||
|
authenticated = true;
|
||||||
|
updated_server = true;
|
||||||
|
}
|
||||||
|
|
||||||
let listener = TcpListener::bind((BIND_IP, port)).await;
|
let mut port_handler = port_handler.lock().await;
|
||||||
|
|
||||||
let listener = match listener {
|
let listener = if let Some((listener, _package)) = port_handler.stop_rejector(port).await {
|
||||||
Ok(listener) => break (port, listener),
|
Ok(listener)
|
||||||
Err(err) => {
|
} else {
|
||||||
port_handler.lock().unwrap().mark_port_error(number, port);
|
TcpListener::bind((BIND_IP, port)).await
|
||||||
// tokio::time::sleep(Duration::from_millis(300)).await;
|
};
|
||||||
|
|
||||||
|
match listener {
|
||||||
|
Ok(listener) => {
|
||||||
|
if !updated_server {
|
||||||
|
let _ip = dyn_ip_update(number, pin, port).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
port_handler
|
||||||
|
.port_state
|
||||||
|
.entry(port)
|
||||||
|
.or_default()
|
||||||
|
.new_state(PortStatus::Idle);
|
||||||
|
|
||||||
|
handler_metadata.port = Some(port);
|
||||||
|
|
||||||
|
break (port, listener);
|
||||||
|
}
|
||||||
|
Err(_err) => {
|
||||||
|
port_handler.mark_port_error(number, port);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Foo {
|
enum Result {
|
||||||
Caller { stream: TcpStream, addr: SocketAddr },
|
Caller {
|
||||||
Packet { packet: Packet },
|
packet: Packet,
|
||||||
|
stream: TcpStream,
|
||||||
|
addr: SocketAddr,
|
||||||
|
},
|
||||||
|
Packet {
|
||||||
|
packet: Packet,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = select! {
|
let mut last_ping_sent_at = Instant::now();
|
||||||
kind = Packet::peek_packet_kind(&mut reader) => {
|
let mut last_ping_received_at = Instant::now();
|
||||||
packet.recv_into(&mut reader).await?;
|
|
||||||
Foo::Packet { packet }
|
let result = loop {
|
||||||
},
|
let now = Instant::now();
|
||||||
caller = listener.accept() => {
|
|
||||||
let (stream, addr) = caller?;
|
select! {
|
||||||
Foo::Caller { stream, addr }
|
caller = listener.accept() => {
|
||||||
},
|
let (stream, addr) = caller?;
|
||||||
|
break Result::Caller { packet, stream, addr }
|
||||||
|
},
|
||||||
|
_ = Packet::peek_packet_kind(&mut reader) => {
|
||||||
|
packet.recv_into(&mut reader).await?;
|
||||||
|
|
||||||
|
if packet.kind() == PacketKind::Ping {
|
||||||
|
last_ping_received_at = now;
|
||||||
|
} else {
|
||||||
|
break Result::Packet { packet }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ = sleep(now.saturating_duration_since(last_ping_sent_at).saturating_sub(SEND_PING_INTERVAL)) => {
|
||||||
|
writer.write_all(bytemuck::bytes_of(& Header { kind: PacketKind::Ping.raw(), length: 0 })).await?;
|
||||||
|
last_ping_sent_at = now;
|
||||||
|
}
|
||||||
|
_ = sleep(now.saturating_duration_since(last_ping_received_at).saturating_sub(PING_TIMEOUT)) => {
|
||||||
|
writer.write_all(REJECT_TIMEOUT).await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
dbg!(&result);
|
let (mut client, mut packet) = match result {
|
||||||
|
Result::Packet { packet } => {
|
||||||
|
if matches!(
|
||||||
|
packet.kind(),
|
||||||
|
packets::PacketKind::End | packets::PacketKind::Reject
|
||||||
|
) {
|
||||||
|
println!("got disconnect packet: {packet:?}");
|
||||||
|
|
||||||
match result {
|
port_handler
|
||||||
Foo::Caller { stream, addr } => todo!(),
|
.lock()
|
||||||
Foo::Packet { mut packet } => {
|
.await
|
||||||
match packet.kind() {
|
.start_rejector(port, listener, packet)?;
|
||||||
packets::PacketKind::End => {
|
return Ok(());
|
||||||
packet.header = Header { kind: 3, length: 0 };
|
} else {
|
||||||
packet.data.clear();
|
bail!("unexpected packet: {:?}", packet.kind())
|
||||||
}
|
|
||||||
packets::PacketKind::Reject => {}
|
|
||||||
|
|
||||||
kind => bail!("unexpected packet: {kind:?}"),
|
|
||||||
}
|
}
|
||||||
port_handler
|
}
|
||||||
.lock()
|
Result::Caller {
|
||||||
.unwrap()
|
mut packet,
|
||||||
.start_rejector(port, listener, packet);
|
stream,
|
||||||
|
addr,
|
||||||
|
} => {
|
||||||
|
println!("got caller from: {addr}");
|
||||||
|
|
||||||
|
packet.data.clear();
|
||||||
|
match addr.ip() {
|
||||||
|
IpAddr::V4(addr) => packet.data.extend_from_slice(&addr.octets()),
|
||||||
|
IpAddr::V6(addr) => packet.data.extend_from_slice(&addr.octets()),
|
||||||
|
}
|
||||||
|
packet.header = Header {
|
||||||
|
kind: PacketKind::RemCall.raw(),
|
||||||
|
length: packet.data.len() as u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
packet.send(&mut writer).await?;
|
||||||
|
|
||||||
|
(stream, packet)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
select! {
|
||||||
|
res = packet.recv_into_cancelation_safe(&mut reader) => res?,
|
||||||
|
_ = sleep(CALL_ACK_TIMEOUT) => {
|
||||||
|
writer.write_all(REJECT_TIMEOUT).await?;
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
match packet.kind() {
|
||||||
|
PacketKind::End | PacketKind::Reject => {
|
||||||
|
port_handler
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.start_rejector(port, listener, packet)?;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
PacketKind::RemAck => {
|
||||||
|
packet.header = Header {
|
||||||
|
kind: PacketKind::Reject.raw(),
|
||||||
|
length: 4,
|
||||||
|
};
|
||||||
|
packet.data.clear();
|
||||||
|
packet.data.extend_from_slice(b"occ");
|
||||||
|
packet.data.push(0);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut port_handler = port_handler.lock().await;
|
||||||
|
|
||||||
|
port_handler.register_update();
|
||||||
|
port_handler
|
||||||
|
.port_state
|
||||||
|
.entry(port)
|
||||||
|
.or_default()
|
||||||
|
.new_state(PortStatus::InCall);
|
||||||
|
|
||||||
|
port_handler.start_rejector(port, listener, packet)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
select! {
|
||||||
|
_ = tokio::io::copy_bidirectional(stream, &mut client) => {}
|
||||||
|
_ = sleep(CALL_TIMEOUT) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut port_handler = port_handler.lock().await;
|
||||||
|
|
||||||
|
port_handler.register_update();
|
||||||
|
port_handler
|
||||||
|
.port_state
|
||||||
|
.entry(port)
|
||||||
|
.or_default()
|
||||||
|
.new_state(PortStatus::Disconnected);
|
||||||
|
|
||||||
|
port_handler
|
||||||
|
.change_rejector(port, |packet| {
|
||||||
|
packet.data.clear();
|
||||||
|
packet.data.extend_from_slice(b"nc");
|
||||||
|
packet.data.push(0);
|
||||||
|
packet.header = Header {
|
||||||
|
kind: PacketKind::Reject.raw(),
|
||||||
|
length: packet.data.len() as u8,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
kind => bail!("unexpected packet: {:?}", kind),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@ -385,9 +599,9 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
panic!("no allowed ports");
|
panic!("no allowed ports");
|
||||||
}
|
}
|
||||||
|
|
||||||
let db_path = PathBuf::from("db.json");
|
let cache_path = PathBuf::from("cache.json");
|
||||||
|
|
||||||
let mut port_handler = PortHandler::load_or_default(&db_path)?;
|
let mut port_handler = PortHandler::load_or_default(&cache_path);
|
||||||
port_handler.update_allowed_ports(&config.allowed_ports);
|
port_handler.update_allowed_ports(&config.allowed_ports);
|
||||||
|
|
||||||
let port_handler = Arc::new(Mutex::new(port_handler));
|
let port_handler = Arc::new(Mutex::new(port_handler));
|
||||||
@ -397,9 +611,9 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut last_store = None;
|
let mut last_store = None;
|
||||||
loop {
|
loop {
|
||||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
sleep(Duration::from_secs(1)).await;
|
||||||
|
|
||||||
let port_handler = port_handler.lock().unwrap();
|
let port_handler = port_handler.lock().await;
|
||||||
|
|
||||||
if let Some(last_update) = port_handler.last_update {
|
if let Some(last_update) = port_handler.last_update {
|
||||||
let should_store = last_store
|
let should_store = last_store
|
||||||
@ -408,22 +622,26 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
if should_store {
|
if should_store {
|
||||||
last_store = Some(last_update);
|
last_store = Some(last_update);
|
||||||
port_handler.store(&db_path).unwrap();
|
port_handler.store(&cache_path).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let listener = TcpListener::bind(("127.0.0.1", 11812)).await?;
|
let listener = TcpListener::bind(("0.0.0.0", 11820)).await?;
|
||||||
|
|
||||||
while let Ok((mut stream, addr)) = listener.accept().await {
|
while let Ok((mut stream, addr)) = listener.accept().await {
|
||||||
println!("connection from {addr}");
|
println!("connection from {addr}");
|
||||||
|
|
||||||
let port_handler = port_handler.clone();
|
let port_handler = port_handler.clone();
|
||||||
|
|
||||||
|
let mut handler_metadata = HandlerMetadata::default();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(err) = connection_handler(port_handler, &mut stream).await {
|
let res = connection_handler(&mut handler_metadata, &port_handler, &mut stream).await;
|
||||||
|
|
||||||
|
if let Err(err) = res {
|
||||||
println!("client at {addr} had an error: {err}");
|
println!("client at {addr} had an error: {err}");
|
||||||
|
|
||||||
let mut packet = Packet::default();
|
let mut packet = Packet::default();
|
||||||
@ -432,13 +650,26 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
packet.data.truncate(0xfe);
|
packet.data.truncate(0xfe);
|
||||||
packet.data.push(0);
|
packet.data.push(0);
|
||||||
packet.header = Header {
|
packet.header = Header {
|
||||||
kind: 0xff,
|
kind: PacketKind::Error.raw(),
|
||||||
length: packet.data.len() as u8,
|
length: packet.data.len() as u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (_, mut writer) = stream.split();
|
let (_, mut writer) = stream.split();
|
||||||
let _ = packet.send(&mut writer).await;
|
let _ = packet.send(&mut writer).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if let Some(number) = handler_metadata.number {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
if let Some(port) = handler_metadata.port {
|
||||||
|
if let Some(port_state) = port_handler.lock().await.port_state.get_mut(&port) {
|
||||||
|
port_state.new_state(PortStatus::Disconnected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(Duration::from_secs(3)).await;
|
||||||
|
let _ = stream.shutdown().await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use std::{ffi::CString, mem::discriminant};
|
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
@ -7,25 +5,13 @@ use tokio::{
|
|||||||
net::tcp::{ReadHalf, WriteHalf},
|
net::tcp::{ReadHalf, WriteHalf},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const fn reject_static<const N: usize>(message: &[u8; N]) -> [u8; N + 2] {
|
pub const REJECT_OOP: &[u8; 6] = b"\x04\x04oop\x00";
|
||||||
let mut pkg = [0u8; N + 2];
|
pub const REJECT_TIMEOUT: &[u8; 10] = b"\x04\x08timeout\x00";
|
||||||
pkg[0] = 4;
|
|
||||||
pkg[1] = message.len() as u8;
|
|
||||||
let mut i = 0;
|
|
||||||
while i < message.len() {
|
|
||||||
pkg[i + 2] = message[i];
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
pkg
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const REJECT_OCC: &[u8; 6] = b"\x04\x04occ\x00";
|
|
||||||
pub const REJECT_NC: &[u8; 5] = b"\x04\x03nc\x00";
|
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum PacketKind {
|
pub enum PacketKind {
|
||||||
Unknown(u8),
|
Ping = 0x00,
|
||||||
DynIpUpdate = 0x01,
|
DynIpUpdate = 0x01,
|
||||||
DynIpUpdateResponse = 0x02,
|
DynIpUpdateResponse = 0x02,
|
||||||
End = 0x03,
|
End = 0x03,
|
||||||
@ -34,6 +20,7 @@ pub enum PacketKind {
|
|||||||
RemConfirm = 0x82,
|
RemConfirm = 0x82,
|
||||||
RemCall = 0x83,
|
RemCall = 0x83,
|
||||||
RemAck = 0x84,
|
RemAck = 0x84,
|
||||||
|
Unknown(u8),
|
||||||
Error = 0xff,
|
Error = 0xff,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +29,7 @@ impl PacketKind {
|
|||||||
use PacketKind::*;
|
use PacketKind::*;
|
||||||
|
|
||||||
match raw {
|
match raw {
|
||||||
|
0x00 => Ping,
|
||||||
0x01 => DynIpUpdate,
|
0x01 => DynIpUpdate,
|
||||||
0x02 => DynIpUpdateResponse,
|
0x02 => DynIpUpdateResponse,
|
||||||
0x03 => End,
|
0x03 => End,
|
||||||
@ -55,11 +43,11 @@ impl PacketKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kind(&self) -> u8 {
|
pub fn raw(&self) -> u8 {
|
||||||
use PacketKind::*;
|
use PacketKind::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Unknown(value) => *value,
|
Ping => 0,
|
||||||
DynIpUpdate => 0x01,
|
DynIpUpdate => 0x01,
|
||||||
DynIpUpdateResponse => 0x02,
|
DynIpUpdateResponse => 0x02,
|
||||||
End => 0x03,
|
End => 0x03,
|
||||||
@ -69,6 +57,8 @@ impl PacketKind {
|
|||||||
RemCall => 0x83,
|
RemCall => 0x83,
|
||||||
RemAck => 0x84,
|
RemAck => 0x84,
|
||||||
Error => 0xff,
|
Error => 0xff,
|
||||||
|
|
||||||
|
Unknown(value) => *value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,10 +101,18 @@ impl Packet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn recv(stream: &mut ReadHalf<'_>) -> std::io::Result<Packet> {
|
pub async fn recv_into_cancelation_safe(
|
||||||
let mut packet = Packet::default();
|
&mut self,
|
||||||
packet.recv_into(stream).await?;
|
stream: &mut ReadHalf<'_>,
|
||||||
Ok(packet)
|
) -> std::io::Result<()> {
|
||||||
|
// Makes sure all data is available before reading
|
||||||
|
let header_bytes = bytemuck::bytes_of_mut(&mut self.header);
|
||||||
|
stream.peek(header_bytes).await?;
|
||||||
|
self.data.resize(self.header.length as usize + 2, 0);
|
||||||
|
stream.peek(&mut self.data).await?;
|
||||||
|
|
||||||
|
// All data is available. Read the data
|
||||||
|
self.recv_into(stream).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn recv_into(&mut self, stream: &mut ReadHalf<'_>) -> std::io::Result<()> {
|
pub async fn recv_into(&mut self, stream: &mut ReadHalf<'_>) -> std::io::Result<()> {
|
||||||
@ -161,7 +159,7 @@ impl Packet {
|
|||||||
pub async fn dyn_ip_update(number: u32, pin: u16, port: u16) -> anyhow::Result<std::net::Ipv4Addr> {
|
pub async fn dyn_ip_update(number: u32, pin: u16, port: u16) -> anyhow::Result<std::net::Ipv4Addr> {
|
||||||
let mut packet = Packet::default();
|
let mut packet = Packet::default();
|
||||||
packet.header = Header {
|
packet.header = Header {
|
||||||
kind: PacketKind::DynIpUpdate.kind(),
|
kind: PacketKind::DynIpUpdate.raw(),
|
||||||
length: 8,
|
length: 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -171,7 +169,8 @@ pub async fn dyn_ip_update(number: u32, pin: u16, port: u16) -> anyhow::Result<s
|
|||||||
packet.data.extend_from_slice(&pin.to_le_bytes());
|
packet.data.extend_from_slice(&pin.to_le_bytes());
|
||||||
packet.data.extend_from_slice(&port.to_le_bytes());
|
packet.data.extend_from_slice(&port.to_le_bytes());
|
||||||
|
|
||||||
let mut socket = tokio::net::TcpStream::connect(("127.0.0.1", 11811)).await?;
|
let mut socket = tokio::net::TcpStream::connect(("tlnserv.teleprinter.net", 11811)).await?;
|
||||||
|
// 127.0.0.1
|
||||||
|
|
||||||
let (mut reader, mut writer) = socket.split();
|
let (mut reader, mut writer) = socket.split();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user