summaryrefslogtreecommitdiff
path: root/server/src/network/upnp.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/network/upnp.rs')
-rw-r--r--server/src/network/upnp.rs72
1 files changed, 72 insertions, 0 deletions
diff --git a/server/src/network/upnp.rs b/server/src/network/upnp.rs
new file mode 100644
index 00000000..a16e9684
--- /dev/null
+++ b/server/src/network/upnp.rs
@@ -0,0 +1,72 @@
+/*
+ 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 anyhow::{bail, Result};
+use get_if_addrs::get_if_addrs;
+use igd::{
+ aio::{search_gateway, Gateway},
+ PortMappingProtocol, SearchOptions,
+};
+use log::{error, info};
+use std::{
+ net::{IpAddr, Ipv4Addr, SocketAddrV4},
+ time::Duration,
+};
+use tokio::time::interval;
+
+pub async fn upnp_loop(port: u16) {
+ // TODO multiple gateways
+ let (gateway, local_addr) = match upnp_setup().await {
+ Ok(g) => g,
+ Err(e) => {
+ error!("UPnP gateway not found: {e}");
+ return;
+ }
+ };
+ let mut interval = interval(Duration::from_secs(120));
+ loop {
+ interval.tick().await;
+ match gateway
+ .add_port(
+ PortMappingProtocol::TCP,
+ 27032,
+ SocketAddrV4::new(local_addr, port),
+ 800,
+ "Hurry Curry! Game Server",
+ )
+ .await
+ {
+ Ok(()) => info!("port mapped successfully"),
+ Err(e) => error!("upnp failed: {e}"),
+ }
+ }
+}
+
+async fn upnp_setup() -> Result<(Gateway, Ipv4Addr)> {
+ let gateway = search_gateway(SearchOptions::default()).await?;
+ info!("IGD address is {}", gateway.addr);
+ for i in get_if_addrs()? {
+ let a = i.addr.ip();
+ if !a.is_loopback() {
+ if let IpAddr::V4(a) = a {
+ info!("local v4 address is {a}");
+ return Ok((gateway, a));
+ }
+ }
+ }
+ bail!("no good local address found")
+}