Always require lobby authentication for lobby matches, refs #3549 / rP21520 / D897.
[0ad.git] / source / network / scripting / JSInterface_Network.cpp
blob9b7fd7136a978df04f9e803dd47af5880900730a
1 /* Copyright (C) 2018 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #include "precompiled.h"
20 #include "JSInterface_Network.h"
22 #include "lib/external_libraries/enet.h"
23 #include "lib/external_libraries/libsdl.h"
24 #include "lib/types.h"
25 #include "lobby/IXmppClient.h"
26 #include "network/NetClient.h"
27 #include "network/NetMessage.h"
28 #include "network/NetServer.h"
29 #include "network/StunClient.h"
30 #include "ps/CLogger.h"
31 #include "ps/Game.h"
32 #include "scriptinterface/ScriptInterface.h"
34 u16 JSI_Network::GetDefaultPort(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
36 return PS_DEFAULT_PORT;
39 bool JSI_Network::HasNetServer(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
41 return g_NetServer;
44 bool JSI_Network::HasNetClient(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
46 return g_NetClient;
49 JS::Value JSI_Network::FindStunEndpoint(ScriptInterface::CxPrivate* pCxPrivate, int port)
51 return StunClient::FindStunEndpointHost(*(pCxPrivate->pScriptInterface), port);
54 void JSI_Network::StartNetworkHost(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& playerName, const u16 serverPort, const CStr& hostLobbyName)
56 ENSURE(!g_NetClient);
57 ENSURE(!g_NetServer);
58 ENSURE(!g_Game);
60 // Always use lobby authentication for lobby matches to prevent impersonation and smurfing, in particular through mods that implemented an UI for arbitrary or other players nicknames.
61 g_NetServer = new CNetServer(static_cast<bool>(g_XmppClient));
62 if (!g_NetServer->SetupConnection(serverPort))
64 pCxPrivate->pScriptInterface->ReportError("Failed to start server");
65 SAFE_DELETE(g_NetServer);
66 return;
69 g_Game = new CGame();
70 g_NetClient = new CNetClient(g_Game, true);
71 g_NetClient->SetUserName(playerName);
72 g_NetClient->SetHostingPlayerName(hostLobbyName);
74 if (!g_NetClient->SetupConnection("127.0.0.1", serverPort))
76 pCxPrivate->pScriptInterface->ReportError("Failed to connect to server");
77 SAFE_DELETE(g_NetClient);
78 SAFE_DELETE(g_Game);
82 void JSI_Network::StartNetworkJoin(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& playerName, const CStr& serverAddress, u16 serverPort, bool useSTUN, const CStr& hostJID)
84 ENSURE(!g_NetClient);
85 ENSURE(!g_NetServer);
86 ENSURE(!g_Game);
88 ENetHost* enetClient = nullptr;
89 if (g_XmppClient && useSTUN)
91 // Find an unused port
92 for (int i = 0; i < 5 && !enetClient; ++i)
94 // Ports below 1024 are privileged on unix
95 u16 port = 1024 + rand() % (UINT16_MAX - 1024);
96 ENetAddress hostAddr{ENET_HOST_ANY, port};
97 enetClient = enet_host_create(&hostAddr, 1, 1, 0, 0);
98 ++hostAddr.port;
101 if (!enetClient)
103 pCxPrivate->pScriptInterface->ReportError("Could not find an unused port for the enet STUN client");
104 return;
107 StunClient::StunEndpoint* stunEndpoint = StunClient::FindStunEndpointJoin(enetClient);
108 if (!stunEndpoint)
110 pCxPrivate->pScriptInterface->ReportError("Could not find the STUN endpoint");
111 return;
114 g_XmppClient->SendStunEndpointToHost(stunEndpoint, hostJID);
115 delete stunEndpoint;
117 SDL_Delay(1000);
120 g_Game = new CGame();
121 g_NetClient = new CNetClient(g_Game, false);
122 g_NetClient->SetUserName(playerName);
123 g_NetClient->SetHostingPlayerName(hostJID.substr(0, hostJID.find("@")));
125 if (g_XmppClient && useSTUN)
126 StunClient::SendHolePunchingMessages(enetClient, serverAddress.c_str(), serverPort);
128 if (!g_NetClient->SetupConnection(serverAddress, serverPort, enetClient))
130 pCxPrivate->pScriptInterface->ReportError("Failed to connect to server");
131 SAFE_DELETE(g_NetClient);
132 SAFE_DELETE(g_Game);
136 void JSI_Network::DisconnectNetworkGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
138 // TODO: we ought to do async reliable disconnections
140 SAFE_DELETE(g_NetServer);
141 SAFE_DELETE(g_NetClient);
142 SAFE_DELETE(g_Game);
145 CStr JSI_Network::GetPlayerGUID(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
147 if (!g_NetClient)
148 return "local";
150 return g_NetClient->GetGUID();
153 JS::Value JSI_Network::PollNetworkClient(ScriptInterface::CxPrivate* pCxPrivate)
155 if (!g_NetClient)
156 return JS::UndefinedValue();
158 // Convert from net client context to GUI script context
159 JSContext* cxNet = g_NetClient->GetScriptInterface().GetContext();
160 JSAutoRequest rqNet(cxNet);
161 JS::RootedValue pollNet(cxNet);
162 g_NetClient->GuiPoll(&pollNet);
163 return pCxPrivate->pScriptInterface->CloneValueFromOtherContext(g_NetClient->GetScriptInterface(), pollNet);
166 void JSI_Network::SetNetworkGameAttributes(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue attribs1)
168 ENSURE(g_NetClient);
170 // TODO: This is a workaround because we need to pass a MutableHandle to a JSAPI functions somewhere (with no obvious reason).
171 JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
172 JSAutoRequest rq(cx);
173 JS::RootedValue attribs(cx, attribs1);
175 g_NetClient->SendGameSetupMessage(&attribs, *(pCxPrivate->pScriptInterface));
178 void JSI_Network::AssignNetworkPlayer(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int playerID, const CStr& guid)
180 ENSURE(g_NetClient);
182 g_NetClient->SendAssignPlayerMessage(playerID, guid);
185 void JSI_Network::KickPlayer(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const CStrW& playerName, bool ban)
187 ENSURE(g_NetClient);
189 g_NetClient->SendKickPlayerMessage(playerName, ban);
192 void JSI_Network::SendNetworkChat(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const CStrW& message)
194 ENSURE(g_NetClient);
196 g_NetClient->SendChatMessage(message);
199 void JSI_Network::SendNetworkReady(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int message)
201 ENSURE(g_NetClient);
203 g_NetClient->SendReadyMessage(message);
206 void JSI_Network::ClearAllPlayerReady (ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
208 ENSURE(g_NetClient);
210 g_NetClient->SendClearAllReadyMessage();
213 void JSI_Network::StartNetworkGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
215 ENSURE(g_NetClient);
216 g_NetClient->SendStartGameMessage();
219 void JSI_Network::SetTurnLength(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int length)
221 if (g_NetServer)
222 g_NetServer->SetTurnLength(length);
223 else
224 LOGERROR("Only network host can change turn length");
227 void JSI_Network::RegisterScriptFunctions(const ScriptInterface& scriptInterface)
229 scriptInterface.RegisterFunction<u16, &GetDefaultPort>("GetDefaultPort");
230 scriptInterface.RegisterFunction<bool, &HasNetServer>("HasNetServer");
231 scriptInterface.RegisterFunction<bool, &HasNetClient>("HasNetClient");
232 scriptInterface.RegisterFunction<JS::Value, int, &FindStunEndpoint>("FindStunEndpoint");
233 scriptInterface.RegisterFunction<void, CStrW, u16, CStr, &StartNetworkHost>("StartNetworkHost");
234 scriptInterface.RegisterFunction<void, CStrW, CStr, u16, bool, CStr, &StartNetworkJoin>("StartNetworkJoin");
235 scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame");
236 scriptInterface.RegisterFunction<CStr, &GetPlayerGUID>("GetPlayerGUID");
237 scriptInterface.RegisterFunction<JS::Value, &PollNetworkClient>("PollNetworkClient");
238 scriptInterface.RegisterFunction<void, JS::HandleValue, &SetNetworkGameAttributes>("SetNetworkGameAttributes");
239 scriptInterface.RegisterFunction<void, int, CStr, &AssignNetworkPlayer>("AssignNetworkPlayer");
240 scriptInterface.RegisterFunction<void, CStrW, bool, &KickPlayer>("KickPlayer");
241 scriptInterface.RegisterFunction<void, CStrW, &SendNetworkChat>("SendNetworkChat");
242 scriptInterface.RegisterFunction<void, int, &SendNetworkReady>("SendNetworkReady");
243 scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady");
244 scriptInterface.RegisterFunction<void, &StartNetworkGame>("StartNetworkGame");
245 scriptInterface.RegisterFunction<void, int, &SetTurnLength>("SetTurnLength");