diff --git a/binaries/data/config/default.cfg b/binaries/data/config/default.cfg
index cc06d577e8..324461202f 100644
--- a/binaries/data/config/default.cfg
+++ b/binaries/data/config/default.cfg
@@ -519,8 +519,6 @@ rememberpassword = true ; Whether to store the encrypted password in
gamerating = false ; Show the average rating of the participating players in a column of the gamelist
[lobby.stun]
-enabled = true ; The STUN protocol allows hosting games without configuring the firewall and router.
- ; If STUN is disabled, the game relies on direct connection, UPnP and port forwarding.
server = "lobby.wildfiregames.com" ; Address of the STUN server.
port = 3478 ; Port of the STUN server.
delay = 10 ; Duration in milliseconds that is waited between checking for retrieved STUN responses.
diff --git a/binaries/data/mods/public/autostart/autostart_host.js b/binaries/data/mods/public/autostart/autostart_host.js
index 787cdbd205..ff38fd62de 100644
--- a/binaries/data/mods/public/autostart/autostart_host.js
+++ b/binaries/data/mods/public/autostart/autostart_host.js
@@ -13,8 +13,8 @@ class AutoStartHost
const playerName = cmdLineArgs['autostart-playername'] || "anonymous";
const port = +(cmdLineArgs['autostart-port'] ?? 5073);
- // Stun and password not implemented for autostart.
- Engine.StartNetworkHost(playerName, port, false, "", !('autostart-disable-replay' in cmdLineArgs));
+ // Password not implemented for autostart.
+ Engine.StartNetworkHost(playerName, port, "", !('autostart-disable-replay' in cmdLineArgs));
}
catch (e)
{
diff --git a/binaries/data/mods/public/gui/gamesetup_mp/gamesetup_mp.js b/binaries/data/mods/public/gui/gamesetup_mp/gamesetup_mp.js
index 2ae6a5eebf..347c37acc9 100644
--- a/binaries/data/mods/public/gui/gamesetup_mp/gamesetup_mp.js
+++ b/binaries/data/mods/public/gui/gamesetup_mp/gamesetup_mp.js
@@ -50,15 +50,12 @@ function init(attribs)
case "host":
{
let hasXmppClient = Engine.HasXmppClient();
- Engine.GetGUIObjectByName("hostSTUNWrapper").hidden = !hasXmppClient;
Engine.GetGUIObjectByName("hostPasswordWrapper").hidden = !hasXmppClient;
if (hasXmppClient)
{
Engine.GetGUIObjectByName("hostPlayerName").caption = attribs.name;
Engine.GetGUIObjectByName("hostServerName").caption =
sprintf(translate("%(name)s's game"), { "name": attribs.name });
-
- Engine.GetGUIObjectByName("useSTUN").checked = Engine.ConfigDB_GetValue("user", "lobby.stun.enabled") == "true";
}
switchSetupPage("pageHost");
@@ -387,12 +384,10 @@ function startHost(playername, servername, port, password, loadSavedGame)
return false;
}
- let useSTUN = Engine.HasXmppClient() && Engine.GetGUIObjectByName("useSTUN").checked;
-
try
{
Engine.StartNetworkHost(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), port,
- useSTUN, password, loadSavedGame, true);
+ password, loadSavedGame, true);
}
catch (e)
{
diff --git a/binaries/data/mods/public/gui/gamesetup_mp/gamesetup_mp.xml b/binaries/data/mods/public/gui/gamesetup_mp/gamesetup_mp.xml
index c1d56f93ed..201491646d 100644
--- a/binaries/data/mods/public/gui/gamesetup_mp/gamesetup_mp.xml
+++ b/binaries/data/mods/public/gui/gamesetup_mp/gamesetup_mp.xml
@@ -115,15 +115,6 @@
-
-
diff --git a/source/lobby/StanzaExtensions.cpp b/source/lobby/StanzaExtensions.cpp
index bc70084373..7ca0da2fcf 100644
--- a/source/lobby/StanzaExtensions.cpp
+++ b/source/lobby/StanzaExtensions.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021 Wildfire Games.
+/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -298,9 +298,6 @@ ConnectionData::ConnectionData(const gloox::Tag* tag)
const gloox::Tag* pip = tag->findTag("connectiondata/isLocalIP");
if (pip)
m_IsLocalIP = pip->cdata();
- const gloox::Tag* s = tag->findTag("connectiondata/useSTUN");
- if (s)
- m_UseSTUN = s->cdata();
const gloox::Tag* pw = tag->findTag("connectiondata/password");
if (pw)
m_Password = pw->cdata();
@@ -335,8 +332,6 @@ gloox::Tag* ConnectionData::tag() const
t->addChild(new gloox::Tag("port", m_Port));
if (!m_IsLocalIP.empty())
t->addChild(new gloox::Tag("isLocalIP", m_IsLocalIP));
- if (!m_UseSTUN.empty())
- t->addChild(new gloox::Tag("useSTUN", m_UseSTUN));
if (!m_Password.empty())
t->addChild(new gloox::Tag("password", m_Password));
if (!m_ClientSalt.empty())
diff --git a/source/lobby/StanzaExtensions.h b/source/lobby/StanzaExtensions.h
index d22ce0d437..2a26c2610e 100644
--- a/source/lobby/StanzaExtensions.h
+++ b/source/lobby/StanzaExtensions.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021 Wildfire Games.
+/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -61,7 +61,6 @@ public:
std::string m_Ip;
std::string m_Port;
std::string m_IsLocalIP;
- std::string m_UseSTUN;
std::string m_Password;
std::string m_ClientSalt;
std::string m_Error;
diff --git a/source/lobby/XmppClient.cpp b/source/lobby/XmppClient.cpp
index 3773cdd6ee..7ca5abc5db 100644
--- a/source/lobby/XmppClient.cpp
+++ b/source/lobby/XmppClient.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2024 Wildfire Games.
+/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -855,8 +855,8 @@ bool XmppClient::handleIq(const gloox::IQ& iq)
return true;
}
- g_NetClient->SetupServerData(cd->m_Ip, stoi(cd->m_Port), !cd->m_UseSTUN.empty());
- g_NetClient->TryToConnect(iq.from().full(), !cd->m_IsLocalIP.empty());
+ g_NetClient->SetupServerData(cd->m_Ip, stoi(cd->m_Port));
+ g_NetClient->TryToConnectWithSTUN(iq.from().full(), !cd->m_IsLocalIP.empty());
}
if (gq)
{
@@ -866,23 +866,6 @@ bool XmppClient::handleIq(const gloox::IQ& iq)
return true;
}
- if (gq->m_Command == "register" && g_NetServer && !g_NetServer->GetUseSTUN())
- {
- if (gq->m_GameList.empty())
- {
- LOGWARNING("XmppClient: Received empty game list in response to Game Register");
- return true;
- }
- std::string publicIP = gq->m_GameList.front()->findAttribute("ip");
- if (publicIP.empty())
- {
- LOGWARNING("XmppClient: Received game with no IP in response to Game Register");
- return true;
- }
- g_NetServer->SetConnectionData(publicIP, g_NetServer->GetPublicPort());
- return true;
- }
-
for (const gloox::Tag* const& t : m_GameList)
delete t;
m_GameList.clear();
@@ -1006,7 +989,6 @@ bool XmppClient::handleIq(const gloox::IQ& iq)
{
connectionData->m_Ip = g_NetServer->GetPublicIp();
connectionData->m_Port = std::to_string(g_NetServer->GetPublicPort());
- connectionData->m_UseSTUN = g_NetServer->GetUseSTUN() ? "true" : "";
connectionData->m_IsLocalIP = "";
}
else
@@ -1016,7 +998,6 @@ bool XmppClient::handleIq(const gloox::IQ& iq)
{
connectionData->m_Ip = ip;
connectionData->m_Port = std::to_string(g_NetServer->GetLocalPort());
- connectionData->m_UseSTUN = "";
connectionData->m_IsLocalIP = "true";
}
else
diff --git a/source/network/NetClient.cpp b/source/network/NetClient.cpp
index 307b71098b..484a7bb4d1 100644
--- a/source/network/NetClient.cpp
+++ b/source/network/NetClient.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2024 Wildfire Games.
+/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -182,13 +182,12 @@ void CNetClient::SetupConnectionViaLobby()
g_XmppClient->SendIqGetConnectionData(m_HostJID, m_Password, m_UserName.ToUTF8(), false);
}
-void CNetClient::SetupServerData(CStr address, u16 port, bool stun)
+void CNetClient::SetupServerData(CStr address, u16 port)
{
ENSURE(!m_Session);
m_ServerAddress = address;
m_ServerPort = port;
- m_UseSTUN = stun;
}
void CNetClient::HandleGetServerDataFailed(const CStr& error)
@@ -203,8 +202,10 @@ void CNetClient::HandleGetServerDataFailed(const CStr& error)
);
}
-bool CNetClient::TryToConnect(const CStr& hostJID, bool localNetwork)
+bool CNetClient::TryToConnectWithSTUN(const CStr& hostJID, bool localNetwork)
{
+ ENSURE(g_XmppClient);
+
if (m_Session)
return false;
@@ -231,7 +232,7 @@ bool CNetClient::TryToConnect(const CStr& hostJID, bool localNetwork)
CStr ip;
u16 port = 0;
- if (g_XmppClient && m_UseSTUN)
+ if (!localNetwork)
{
if (!StunClient::FindPublicIP(*enetClient, ip, port))
{
@@ -252,7 +253,7 @@ bool CNetClient::TryToConnect(const CStr& hostJID, bool localNetwork)
return true;
}
}
- else if (g_XmppClient && localNetwork)
+ else
{
// We may need to punch a hole through the local firewall, so fetch our local IP.
// NB: we'll ignore failures here, and hope that the firewall will be open to connection
diff --git a/source/network/NetClient.h b/source/network/NetClient.h
index ac5f27e77d..2f56bf321b 100644
--- a/source/network/NetClient.h
+++ b/source/network/NetClient.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2024 Wildfire Games.
+/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -116,7 +116,7 @@ public:
* Set connection data to the remote networked server.
* @param address IP address or host name to connect to
*/
- void SetupServerData(CStr address, u16 port, bool stun);
+ void SetupServerData(CStr address, u16 port);
/**
* Set up a connection to the remote networked server.
@@ -136,7 +136,7 @@ public:
* @param localNetwork - if true, assume we are trying to connect on the local network.
* @return true on success, false on connection failure
*/
- bool TryToConnect(const CStr& hostJID, bool localNetwork);
+ bool TryToConnectWithSTUN(const CStr& hostJID, bool localNetwork);
/**
* Destroy the connection to the server.
@@ -325,7 +325,6 @@ private:
CStr m_HostJID;
CStr m_ServerAddress;
u16 m_ServerPort;
- bool m_UseSTUN;
/**
* Password to join the game.
diff --git a/source/network/NetServer.cpp b/source/network/NetServer.cpp
index f3753c2481..37fe2c96f3 100644
--- a/source/network/NetServer.cpp
+++ b/source/network/NetServer.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2024 Wildfire Games.
+/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -1676,7 +1676,7 @@ void CNetServerWorker::SendHolePunchingMessage(const CStr& ipStr, u16 port)
CNetServer::CNetServer(const bool continueSavedGame, const bool useLobbyAuth) :
m_Worker{new CNetServerWorker{continueSavedGame, useLobbyAuth}},
- m_LobbyAuth(useLobbyAuth), m_UseSTUN(false), m_PublicIp(""), m_PublicPort(20595), m_Password()
+ m_LobbyAuth(useLobbyAuth), m_PublicIp(""), m_PublicPort(20595), m_Password()
{
}
@@ -1685,11 +1685,6 @@ CNetServer::~CNetServer()
delete m_Worker;
}
-bool CNetServer::GetUseSTUN() const
-{
- return m_UseSTUN;
-}
-
bool CNetServer::UseLobbyAuth() const
{
return m_LobbyAuth;
@@ -1718,16 +1713,8 @@ u16 CNetServer::GetLocalPort() const
return m_Worker->m_Host->address.port;
}
-void CNetServer::SetConnectionData(const CStr& ip, const u16 port)
+bool CNetServer::SetConnectionData()
{
- m_PublicIp = ip;
- m_PublicPort = port;
- m_UseSTUN = false;
-}
-
-bool CNetServer::SetConnectionDataViaSTUN()
-{
- m_UseSTUN = true;
std::lock_guard lock(m_Worker->m_WorkerMutex);
if (!m_Worker->m_Host)
return false;
diff --git a/source/network/NetServer.h b/source/network/NetServer.h
index f1c2bf2ae9..060d12a328 100644
--- a/source/network/NetServer.h
+++ b/source/network/NetServer.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2024 Wildfire Games.
+/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -144,10 +144,7 @@ public:
void SendHolePunchingMessage(const CStr& ip, u16 port);
- void SetConnectionData(const CStr& ip, u16 port);
- bool SetConnectionDataViaSTUN();
-
- bool GetUseSTUN() const;
+ bool SetConnectionData();
/**
* Return the externally accessible IP.
@@ -186,7 +183,6 @@ public:
private:
CNetServerWorker* m_Worker;
const bool m_LobbyAuth;
- bool m_UseSTUN;
u16 m_PublicPort;
CStr m_PublicIp;
CStr m_Password;
diff --git a/source/network/scripting/JSInterface_Network.cpp b/source/network/scripting/JSInterface_Network.cpp
index ba5162521d..4438dbda2f 100644
--- a/source/network/scripting/JSInterface_Network.cpp
+++ b/source/network/scripting/JSInterface_Network.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2024 Wildfire Games.
+/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -65,7 +65,7 @@ bool HasNetClient()
return !!g_NetClient;
}
-void StartNetworkHost(const ScriptRequest& rq, const CStrW& playerName, const u16 serverPort, bool useSTUN,
+void StartNetworkHost(const ScriptRequest& rq, const CStrW& playerName, const u16 serverPort,
const CStr& password, const bool continueSavedGame, bool storeReplay)
{
ENSURE(!g_NetClient);
@@ -84,20 +84,12 @@ void StartNetworkHost(const ScriptRequest& rq, const CStrW& playerName, const u1
}
// In lobby, we send our public ip and port on request to the players who want to connect.
- // Thus we need to know our public IP. Use STUN if that's available,
- // otherwise, the lobby's reponse to the game registration stanza will tell us our public IP.
- if (hasLobby)
+ // Thus we need to know our public IP and use STUN to get it.
+ if (hasLobby && !g_NetServer->SetConnectionData())
{
- if (!useSTUN)
- // Don't store IP - the lobby bot will send it later.
- // (if a client tries to connect before it's setup, they'll be disconnected)
- g_NetServer->SetConnectionData("", serverPort);
- else if (!g_NetServer->SetConnectionDataViaSTUN())
- {
- ScriptException::Raise(rq, "Failed to host via STUN.");
- SAFE_DELETE(g_NetServer);
- return;
- }
+ ScriptException::Raise(rq, "Failed to resolve public IP-address.");
+ SAFE_DELETE(g_NetServer);
+ return;
}
// Generate a secret to identify the host client.
@@ -134,7 +126,7 @@ void StartNetworkHost(const ScriptRequest& rq, const CStrW& playerName, const u1
g_NetClient->SetGamePassword(hashedPass);
}
- g_NetClient->SetupServerData("127.0.0.1", serverPort, false);
+ g_NetClient->SetupServerData("127.0.0.1", serverPort);
g_NetClient->SetControllerSecret(secret);
if (!g_NetClient->SetupConnection(nullptr))
@@ -154,7 +146,7 @@ void StartNetworkJoin(const ScriptRequest& rq, const CStrW& playerName, const CS
g_Game = new CGame(storeReplay);
g_NetClient = new CNetClient(g_Game);
g_NetClient->SetUserName(playerName);
- g_NetClient->SetupServerData(serverAddress, serverPort, false);
+ g_NetClient->SetupServerData(serverAddress, serverPort);
if (!g_NetClient->SetupConnection(nullptr))
{
diff --git a/source/network/tests/test_Net.h b/source/network/tests/test_Net.h
index 027231b72a..56e27797ae 100644
--- a/source/network/tests/test_Net.h
+++ b/source/network/tests/test_Net.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2024 Wildfire Games.
+/* Copyright (C) 2025 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -73,7 +73,7 @@ public:
TS_ASSERT(server.SetupConnection(PS_DEFAULT_PORT));
for (CNetClient* client: clients)
{
- client->SetupServerData("127.0.0.1", PS_DEFAULT_PORT, false);
+ client->SetupServerData("127.0.0.1", PS_DEFAULT_PORT);
TS_ASSERT(client->SetupConnection(nullptr));
}
@@ -307,7 +307,7 @@ public:
client2B.SetUserName(L"bob");
clients.push_back(&client2B);
- client2B.SetupServerData("127.0.0.1", PS_DEFAULT_PORT, false);
+ client2B.SetupServerData("127.0.0.1", PS_DEFAULT_PORT);
TS_ASSERT(client2B.SetupConnection(nullptr));
for (size_t i = 0; ; ++i)