diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8042b23fd..7750a92b4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1076,6 +1076,8 @@ set_src(ENGINE_SERVER GLOB src/engine/server
sql_server.h
sql_string_helpers.cpp
sql_string_helpers.h
+ upnp.cpp
+ upnp.h
)
set_src(GAME_SERVER GLOB_RECURSE src/game/server
antibot.cpp
@@ -1741,7 +1743,7 @@ foreach(target ${TARGETS_OWN})
endif()
if(UPNP)
target_compile_definitions(${target} PRIVATE CONF_UPNP)
- target_include_directories(${target} PRIVATE ${MINIUPNPC_INCLUDE_DIRS})
+ target_include_directories(${target} PRIVATE ${MINIUPNPC_INCLUDE_DIRS})
endif()
if(VIDEORECORDER)
target_compile_definitions(${target} PRIVATE CONF_VIDEORECORDER)
diff --git a/README.md b/README.md
index 8e4eedd3c..b4644be29 100644
--- a/README.md
+++ b/README.md
@@ -80,7 +80,7 @@ Whether to optimize for development, speeding up the compilation process a littl
* **-DUPNP=[ON|OFF]**
Whether to enable UPnP support for the server.
-You need to install `libminiupnpc-dev`.
+You need to install `libminiupnpc-dev` on Debian, `miniupnpc` on Arch Linux.
* **-GNinja**
Use the Ninja build system instead of Make. This automatically parallizes the build and is generally faster. Compile with `ninja` instead of `make`. Install Ninja with `sudo apt install ninja-build` on Debian, `sudo pacman -S --needed ninja` on Arch Linux.
diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp
index 9cedf1f4b..34c508e93 100644
--- a/src/engine/server/server.cpp
+++ b/src/engine/server/server.cpp
@@ -34,17 +34,10 @@
#include
#include
#include
-#include
#include "register.h"
#include "server.h"
-#if defined(CONF_UPNP)
- #include
- #include
- #include
-#endif
-
#if defined(CONF_FAMILY_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#include
@@ -1970,42 +1963,7 @@ int CServer::Run()
}
#if defined(CONF_UPNP)
- if(g_Config.m_SvUseUPnP)
- {
- struct UPNPUrls upnp_urls;
- struct IGDdatas upnp_data;
- char aLanAddr[64];
- char aPort[6];
- int error = 0;
- struct UPNPDev *upnp_dev = upnpDiscover(2000, NULL, NULL, 0, 0, 2, &error);
- int status = UPNP_GetValidIGD(upnp_dev, &upnp_urls, &upnp_data, aLanAddr, sizeof(aLanAddr));
- dbg_msg("upnp", "status=%d, lan_addr=%s", status, aLanAddr);
-
- if(status == 1)
- {
- dbg_msg("upnp", "found valid IGD: %s", upnp_urls.controlURL);
- str_format(aPort, sizeof(aPort), "%d", BindAddr.port);
- error = UPNP_AddPortMapping(upnp_urls.controlURL, upnp_data.first.servicetype,
- aPort, aPort, aLanAddr,
- "DDNet Server " GAME_RELEASE_VERSION,
- "UDP", NULL, "0");
-
- if(error)
- {
- dbg_msg("upnp", "failed to map port");
- dbg_msg("upnp", "error: %s", strupnperror(error));
- }
- else
- dbg_msg("upnp", "successfully mapped port");
- }
- else
- {
- dbg_msg("upnp", "no valid IGD found");
- dbg_msg("upnp", "disabled");
- }
- FreeUPNPUrls(&upnp_urls);
- freeUPNPDevlist(upnp_dev);
- }
+ m_UPnP.Open(BindAddr);
#endif
if(!m_NetServer.Open(BindAddr, &m_ServerBan, g_Config.m_SvMaxClients, g_Config.m_SvMaxClientsPerIP, 0))
@@ -2276,6 +2234,10 @@ int CServer::Run()
}
#endif
+#if defined (CONF_UPNP)
+ m_UPnP.Shutdown();
+#endif
+
return ErrorShutdown();
}
diff --git a/src/engine/server/server.h b/src/engine/server/server.h
index cee0009ef..671282ded 100644
--- a/src/engine/server/server.h
+++ b/src/engine/server/server.h
@@ -28,6 +28,10 @@
#include "authmanager.h"
#include "name_ban.h"
+#if defined (CONF_UPNP)
+ #include "upnp.h"
+#endif
+
#if defined (CONF_SQL)
#include "sql_connector.h"
#include "sql_server.h"
@@ -92,6 +96,10 @@ class CServer : public IServer
class IConsole *m_pConsole;
class IStorage *m_pStorage;
+#if defined(CONF_UPNP)
+ CUPnP m_UPnP;
+#endif
+
#if defined(CONF_SQL)
lock m_GlobalSqlLock;
diff --git a/src/engine/server/upnp.cpp b/src/engine/server/upnp.cpp
new file mode 100644
index 000000000..6649d14fd
--- /dev/null
+++ b/src/engine/server/upnp.cpp
@@ -0,0 +1,74 @@
+#ifdef CONF_UPNP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "upnp.h"
+
+void CUPnP::Open(NETADDR Address)
+{
+ if(g_Config.m_SvUseUPnP)
+ {
+ m_Enabled = false;
+ m_Addr = Address;
+ m_UPnPUrls = (struct UPNPUrls *)malloc(sizeof(struct UPNPUrls));
+ m_UPnPData = (struct IGDdatas *)malloc(sizeof(struct IGDdatas));
+
+ char aLanAddr[64];
+ char aPort[6];
+ int Error;
+
+ m_UPnPDevice = upnpDiscover(2000, NULL, NULL, 0, 0, 2, &Error);
+
+ int Status = UPNP_GetValidIGD(m_UPnPDevice, m_UPnPUrls, m_UPnPData, aLanAddr, sizeof(aLanAddr));
+ dbg_msg("upnp", "status=%d, lan_addr=%s", Status, aLanAddr);
+
+ if(Status == 1)
+ {
+ m_Enabled = true;
+ dbg_msg("upnp", "found valid IGD: %s", m_UPnPUrls->controlURL);
+ str_format(aPort, sizeof(aPort), "%d", m_Addr.port);
+ Error = UPNP_AddPortMapping(m_UPnPUrls->controlURL, m_UPnPData->first.servicetype,
+ aPort, aPort, aLanAddr,
+ "DDNet Server " GAME_RELEASE_VERSION,
+ "UDP", NULL, "0");
+
+ if(Error)
+ dbg_msg("upnp", "failed to map port, error: %s", strupnperror(Error));
+ else
+ dbg_msg("upnp", "successfully mapped port");
+ }
+ else
+ dbg_msg("upnp", "no valid IGD found, disabled");
+ }
+}
+
+void CUPnP::Shutdown()
+{
+ if(g_Config.m_SvUseUPnP)
+ {
+ if(m_Enabled)
+ {
+ char aPort[6];
+ str_format(aPort, sizeof(aPort), "%d", m_Addr.port);
+ int Error = UPNP_DeletePortMapping(m_UPnPUrls->controlURL, m_UPnPData->first.servicetype, aPort, "UDP", NULL);
+
+ if(Error != 0)
+ {
+ dbg_msg("upnp", "failed to delete port mapping on shutdown: %s", strupnperror(Error));
+ }
+ FreeUPNPUrls(m_UPnPUrls);
+ freeUPNPDevlist(m_UPnPDevice);
+ }
+ free(m_UPnPUrls);
+ free(m_UPnPData);
+ m_UPnPUrls = NULL;
+ m_UPnPData = NULL;
+ }
+
+}
+
+#endif
\ No newline at end of file
diff --git a/src/engine/server/upnp.h b/src/engine/server/upnp.h
new file mode 100644
index 000000000..58a269ea4
--- /dev/null
+++ b/src/engine/server/upnp.h
@@ -0,0 +1,18 @@
+#ifndef ENGINE_SERVER_UPNP_H
+#define ENGINE_SERVER_UPNP_H
+
+#include
+class CUPnP
+{
+ NETADDR m_Addr;
+ struct UPNPUrls *m_UPnPUrls;
+ struct IGDdatas *m_UPnPData;
+ struct UPNPDev *m_UPnPDevice;
+ bool m_Enabled;
+
+public:
+ void Open(NETADDR Address);
+ void Shutdown();
+};
+
+#endif
diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h
index 92a3f4e2e..beefc6b0a 100644
--- a/src/engine/shared/config_variables.h
+++ b/src/engine/shared/config_variables.h
@@ -222,7 +222,7 @@ MACRO_CONFIG_INT(SvSqlQueriesDelay, sv_sql_queries_delay, 1, 0, 20, CFGFLAG_SERV
#endif
#if defined(CONF_UPNP)
-MACRO_CONFIG_INT(SvUseUPnP, sv_use_upnp, 1, 0, 1, CFGFLAG_SERVER, "Enables UPnP support.")
+MACRO_CONFIG_INT(SvUseUPnP, sv_use_upnp, 0, 0, 1, CFGFLAG_SERVER, "Enables UPnP support.")
#endif
MACRO_CONFIG_INT(SvDDRaceRules, sv_ddrace_rules, 1, 0, 1, CFGFLAG_SERVER, "Whether the default mod rules are displayed or not")