1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
/*
Hurry Curry! - a game about cooking
Copyright (C) 2025 Hurry Curry! Contributors
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")
}
|