Add UPnP support

This commit is contained in:
Ryozuki 2020-04-14 12:11:50 +02:00
parent 164a887214
commit b647c1e978
No known key found for this signature in database
GPG key ID: 848FCC08E5B89681
5 changed files with 102 additions and 0 deletions

View file

@ -84,6 +84,7 @@ option(WEBSOCKETS "Enable websockets support" OFF)
option(MYSQL "Enable mysql support" OFF)
option(AUTOUPDATE "Enable the autoupdater" ${AUTOUPDATE_DEFAULT})
option(VIDEORECORDER "Enable video recording support via FFmpeg" OFF)
option(UPNP "Enable UPnP support" OFF)
option(ANTIBOT "Enable support for a dynamic anticheat library" OFF)
option(CLIENT "Compile client" ON)
option(DOWNLOAD_GTEST "Download and compile GTest" ${AUTO_DEPENDENCIES_DEFAULT})
@ -326,6 +327,9 @@ endif()
find_package(Ogg)
find_package(Opus)
find_package(Opusfile)
if(UPNP)
find_package(Miniupnpc)
endif()
find_package(Pnglite)
find_package(PythonInterp)
find_package(SDL2)
@ -398,6 +402,9 @@ show_dependency_status("Ogg" OGG)
show_dependency_status("OpenSSL Crypto" CRYPTO)
show_dependency_status("Opus" OPUS)
show_dependency_status("Opusfile" OPUSFILE)
if(UPNP)
show_dependency_status("Miniupnpc" MINIUPNPC)
endif()
show_dependency_status("Pnglite" PNGLITE)
show_dependency_status("PythonInterp" PYTHONINTERP)
show_dependency_status("SDL2" SDL2)
@ -425,6 +432,10 @@ if(WEBSOCKETS AND NOT(WEBSOCKETS_FOUND))
message(SEND_ERROR "You must install libwebsockets to compile the DDNet server with websocket support")
endif()
if(UPNP AND NOT(MINIUPNPC_FOUND))
message(SEND_ERROR "You must install miniupnpc to compile the DDNet server with UPnP support")
endif()
if(CLIENT AND NOT(FREETYPE_FOUND))
message(SEND_ERROR "You must install Freetype to compile the DDNet client")
endif()
@ -1142,6 +1153,7 @@ set(LIBS_SERVER
${LIBS}
${MYSQL_LIBRARIES}
${TARGET_ANTIBOT}
${MINIUPNPC_LIBRARIES}
# Add pthreads (on non-Windows) at the end, so that other libraries can depend
# on it.
${CMAKE_THREAD_LIBS_INIT}
@ -1727,6 +1739,10 @@ foreach(target ${TARGETS_OWN})
target_compile_definitions(${target} PRIVATE CONF_WEBSOCKETS)
target_include_directories(${target} PRIVATE ${WEBSOCKETS_INCLUDE_DIRS})
endif()
if(UPNP)
target_compile_definitions(${target} PRIVATE CONF_UPNP)
target_include_directories(${target} PRIVATE ${MINIUPNPC_INCLUDE_DIRS})
endif()
if(VIDEORECORDER)
target_compile_definitions(${target} PRIVATE CONF_VIDEORECORDER)
endif()

View file

@ -78,6 +78,9 @@ Whether to download and compile GTest. Useful if GTest is not installed and, for
* **-DDEV=[ON|OFF]** <br>
Whether to optimize for development, speeding up the compilation process a little. If enabled, don't generate stuff necessary for packaging. Setting to ON will set CMAKE\_BUILD\_TYPE to Debug by default. Default value is OFF.
* **-DUPNP=[ON|OFF]** <br>
Whether to enable UPnP support for the server.
* **-GNinja** <br>
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.

33
cmake/FindMiniupnpc.cmake Normal file
View file

@ -0,0 +1,33 @@
if(NOT CMAKE_CROSSCOMPILING)
find_package(PkgConfig QUIET)
pkg_check_modules(PC_MINIUPNPC miniupnpc)
endif()
set_extra_dirs_lib(MINIUPNPC miniupnpc)
find_library(MINIUPNPC_LIBRARY
NAMES miniupnpc
HINTS ${HINTS_MINIUPNPC_LIBDIR} ${PC_MINIUPNPC_LIBDIR} ${PC_MINIUPNPC_LIBRARY_DIRS}
PATHS ${PATHS_MINIUPNPC_LIBDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
set_extra_dirs_include(MINIUPNPC miniupnpc "${MINIUPNPC_LIBRARY}")
find_path(MINIUPNPC_INCLUDEDIR miniupnpc.h
PATH_SUFFIXES miniupnpc
HINTS ${HINTS_MINIUPNPC_INCLUDEDIR} ${PC_MINIUPNPC_INCLUDEDIR} ${PC_MINIUPNPC_INCLUDE_DIRS}
PATHS ${PATHS_MINIUPNPC_INCLUDEDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Miniupnpc DEFAULT_MSG MINIUPNPC_INCLUDEDIR)
mark_as_advanced(MINIUPNPC_INCLUDEDIR MINIUPNPC_LIBRARY)
if(MINIUPNPC_FOUND)
set(MINIUPNPC_INCLUDE_DIRS ${MINIUPNPC_INCLUDEDIR})
if(MINIUPNPC_LIBRARY)
set(MINIUPNPC_LIBRARIES ${MINIUPNPC_LIBRARY})
else()
set(MINIUPNPC_LIBRARIES)
endif()
endif()

View file

@ -34,10 +34,17 @@
#include <vector>
#include <engine/shared/linereader.h>
#include <game/extrainfo.h>
#include <game/version.h>
#include "register.h"
#include "server.h"
#if defined(CONF_UPNP)
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#include <miniupnpc/upnperrors.h>
#endif
#if defined(CONF_FAMILY_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
@ -1962,6 +1969,45 @@ int CServer::Run()
BindAddr.port = g_Config.m_SvPort;
}
#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);
}
#endif
if(!m_NetServer.Open(BindAddr, &m_ServerBan, g_Config.m_SvMaxClients, g_Config.m_SvMaxClientsPerIP, 0))
{
dbg_msg("server", "couldn't open socket. port %d might already be in use", g_Config.m_SvPort);

View file

@ -221,6 +221,10 @@ MACRO_CONFIG_STR(SvSqlFailureFile, sv_sql_failure_file, 64, "failed_sql.sql", CF
MACRO_CONFIG_INT(SvSqlQueriesDelay, sv_sql_queries_delay, 1, 0, 20, CFGFLAG_SERVER, "Delay in seconds between SQL queries of a single player")
#endif
#if defined(CONF_UPNP)
MACRO_CONFIG_INT(SvUseUPnP, sv_use_upnp, 1, 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")
MACRO_CONFIG_STR(SvRulesLine1, sv_rules_line1, 128, "", CFGFLAG_SERVER, "Rules line 1")
MACRO_CONFIG_STR(SvRulesLine2, sv_rules_line2, 128, "", CFGFLAG_SERVER, "Rules line 2")