summaryrefslogtreecommitdiff
path: root/server/registry/src/conn_test.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-09-21 12:48:36 +0200
committermetamuffin <metamuffin@disroot.org>2024-09-21 12:48:36 +0200
commit41c95fc5b6b1c8bc4b944d889414a4197a23837b (patch)
tree86519d51df113263e0c1e6d92b96b35c72cf37d9 /server/registry/src/conn_test.rs
parent526bde82158fc58f59a8147566ef0ef01845ac49 (diff)
downloadhurrycurry-41c95fc5b6b1c8bc4b944d889414a4197a23837b.tar
hurrycurry-41c95fc5b6b1c8bc4b944d889414a4197a23837b.tar.bz2
hurrycurry-41c95fc5b6b1c8bc4b944d889414a4197a23837b.tar.zst
reg: connection test
Diffstat (limited to 'server/registry/src/conn_test.rs')
-rw-r--r--server/registry/src/conn_test.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/server/registry/src/conn_test.rs b/server/registry/src/conn_test.rs
new file mode 100644
index 00000000..2fda288c
--- /dev/null
+++ b/server/registry/src/conn_test.rs
@@ -0,0 +1,78 @@
+/*
+ Hurry Curry! - a game about cooking
+ Copyright 2024 metamuffin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, version 3 of the License only.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+*/
+use crate::MAX_ADDR_CACHE;
+use anyhow::{bail, Result};
+use hurrycurry_client_lib::network::tokio::Network;
+use hurrycurry_protocol::PacketC;
+use log::info;
+use std::{
+ collections::BTreeMap,
+ net::SocketAddr,
+ time::{Duration, Instant},
+};
+use tokio::{net::TcpStream, sync::RwLock, time::timeout};
+
+#[derive(Debug, Clone, Copy)]
+struct ConnectTest {
+ verified_at: Instant,
+ version: (u32, u32),
+}
+
+static CONNECT_OK: RwLock<BTreeMap<SocketAddr, ConnectTest>> = RwLock::const_new(BTreeMap::new());
+
+pub(crate) async fn test_connect(addr: SocketAddr, uri: &str) -> Result<(u32, u32), &'static str> {
+ let r = CONNECT_OK.read().await.get(&addr).copied();
+ if let Some(r) = r {
+ Ok(r.version)
+ } else {
+ // TODO locks to prevent parallel tests for same addr and dos attempts
+ let res = timeout(Duration::from_secs(10), test_connect_inner(addr, uri))
+ .await
+ .map_err(|_| "connect timeout")?;
+ info!("connect result: {res:?}");
+ let version = res.map_err(|_| "server unreachable")?;
+ {
+ let mut g = CONNECT_OK.write().await;
+ g.insert(
+ addr,
+ ConnectTest {
+ verified_at: Instant::now(),
+ version,
+ },
+ );
+ while g.len() > MAX_ADDR_CACHE {
+ // TODO perf maybe later
+ if let Some(key) = g.iter().min_by_key(|(_, v)| v.verified_at).map(|(k, _)| *k) {
+ g.remove(&key);
+ }
+ }
+ }
+ info!("cache updated");
+ Ok(version)
+ }
+}
+async fn test_connect_inner(addr: SocketAddr, uri: &str) -> Result<(u32, u32)> {
+ info!("test connect {addr} {uri:?}");
+ let stream = TcpStream::connect(addr).await?;
+ let net = Network::connect_raw(stream, uri).await?;
+ let packet = net.receive().await?;
+ match packet {
+ Some(PacketC::Version { minor, major, .. }) => return Ok((major, minor)),
+ _ => bail!("bad initial packet"),
+ }
+}