Changeset View
Standalone View
source/lobby/XmppClient.cpp
Show All 22 Lines | |||||
#ifdef WIN32 | #ifdef WIN32 | ||||
# include <winsock2.h> | # include <winsock2.h> | ||||
#endif | #endif | ||||
#include "i18n/L10n.h" | #include "i18n/L10n.h" | ||||
#include "lib/external_libraries/enet.h" | #include "lib/external_libraries/enet.h" | ||||
#include "lib/utf8.h" | #include "lib/utf8.h" | ||||
#include "network/NetServer.h" | #include "network/NetServer.h" | ||||
#include "network/NetClient.h" | |||||
#include "network/StunClient.h" | #include "network/StunClient.h" | ||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "ps/ConfigDB.h" | #include "ps/ConfigDB.h" | ||||
#include "ps/Pyrogenesis.h" | #include "ps/Pyrogenesis.h" | ||||
#include "scriptinterface/ScriptExtraHeaders.h" // StructuredClone | #include "scriptinterface/ScriptExtraHeaders.h" // StructuredClone | ||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
#include <gloox/gloox.h> | #include <gloox/gloox.h> | ||||
#include <iostream> | #include <iostream> | ||||
//debug | //debug | ||||
#if 1 | #if 0 | ||||
Silier: revert | |||||
#define DbgXMPP(x) | #define DbgXMPP(x) | ||||
#else | #else | ||||
#define DbgXMPP(x) std::cout << x << std::endl; | #define DbgXMPP(x) std::cout << x << std::endl; | ||||
static std::string tag_xml(const glooxwrapper::IQ& iq) | static std::string tag_xml(const glooxwrapper::IQ& iq) | ||||
{ | { | ||||
std::string ret; | std::string ret; | ||||
glooxwrapper::Tag* tag = iq.tag(); | glooxwrapper::Tag* tag = iq.tag(); | ||||
Show All 38 Lines | : m_ScriptInterface(scriptInterface), | ||||
m_password(sPassword), | m_password(sPassword), | ||||
m_room(sRoom), | m_room(sRoom), | ||||
m_nick(sNick), | m_nick(sNick), | ||||
m_initialLoadComplete(false), | m_initialLoadComplete(false), | ||||
m_isConnected(false), | m_isConnected(false), | ||||
m_sessionManager(nullptr), | m_sessionManager(nullptr), | ||||
m_certStatus(gloox::CertStatus::CertOk), | m_certStatus(gloox::CertStatus::CertOk), | ||||
m_PlayerMapUpdate(false) | m_PlayerMapUpdate(false) | ||||
{ | { | ||||
if (m_ScriptInterface) | if (m_ScriptInterface) | ||||
Done Inline ActionsNo need to pass empty string to std::string, it has a valid default c-tor. vladislavbelov: No need to pass empty string to `std::string`, it has a valid default c-tor. | |||||
Not Done Inline ActionsInvalid naming should be m_PascalCase Stan: Invalid naming should be m_PascalCase | |||||
Done Inline Actionsyes, but cc says follow style of the document trying to edit as the rule above cc guidelines Silier: yes, but cc says follow style of the document trying to edit as the rule above cc guidelines | |||||
Not Done Inline ActionsThen m_PlayerMapUpdate is wrong. Stan: Then m_PlayerMapUpdate is wrong. | |||||
JS_AddExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), XmppClient::Trace, this); | JS_AddExtraGCRootsTracer(m_ScriptInterface->GetGeneralJSContext(), XmppClient::Trace, this); | ||||
// Read lobby configuration from default.cfg | // Read lobby configuration from default.cfg | ||||
std::string sXpartamupp; | std::string sXpartamupp; | ||||
std::string sEchelon; | std::string sEchelon; | ||||
CFG_GET_VAL("lobby.server", m_server); | CFG_GET_VAL("lobby.server", m_server); | ||||
CFG_GET_VAL("lobby.xpartamupp", sXpartamupp); | CFG_GET_VAL("lobby.xpartamupp", sXpartamupp); | ||||
CFG_GET_VAL("lobby.echelon", sEchelon); | CFG_GET_VAL("lobby.echelon", sEchelon); | ||||
Show All 35 Lines | XmppClient::XmppClient(const ScriptInterface* scriptInterface, const std::string& sUsername, const std::string& sPassword, const std::string& sRoom, const std::string& sNick, const int historyRequestSize, bool regOpt) | ||||
m_client->registerIqHandler(this, EXTBOARDLISTQUERY); | m_client->registerIqHandler(this, EXTBOARDLISTQUERY); | ||||
m_client->registerStanzaExtension(new ProfileQuery()); | m_client->registerStanzaExtension(new ProfileQuery()); | ||||
m_client->registerIqHandler(this, EXTPROFILEQUERY); | m_client->registerIqHandler(this, EXTPROFILEQUERY); | ||||
m_client->registerStanzaExtension(new LobbyAuth()); | m_client->registerStanzaExtension(new LobbyAuth()); | ||||
m_client->registerIqHandler(this, EXTLOBBYAUTH); | m_client->registerIqHandler(this, EXTLOBBYAUTH); | ||||
m_client->registerStanzaExtension(new ConnectionData()); | |||||
Not Done Inline ActionsDoes gloox take care of the ptr deletion? Stan: Does gloox take care of the ptr deletion? | |||||
Done Inline Actionsguess so. else we are in trouble already, but i ll check Silier: guess so. else we are in trouble already, but i ll check | |||||
m_client->registerIqHandler(this, EXTCONNECTIONDATA); | |||||
m_client->registerMessageHandler(this); | m_client->registerMessageHandler(this); | ||||
// Uncomment to see the raw stanzas | // Uncomment to see the raw stanzas | ||||
//m_client->getWrapped()->logInstance().registerLogHandler( gloox::LogLevelDebug, gloox::LogAreaAll, this ); | //m_client->getWrapped()->logInstance().registerLogHandler( gloox::LogLevelDebug, gloox::LogAreaAll, this ); | ||||
if (!regOpt) | if (!regOpt) | ||||
{ | { | ||||
// Create a Multi User Chat Room | // Create a Multi User Chat Room | ||||
▲ Show 20 Lines • Show All 196 Lines • ▼ Show 20 Lines | void XmppClient::SendIqGetProfile(const std::string& player) | ||||
// Send IQ | // Send IQ | ||||
ProfileQuery* b = new ProfileQuery(); | ProfileQuery* b = new ProfileQuery(); | ||||
b->m_Command = player; | b->m_Command = player; | ||||
glooxwrapper::IQ iq(gloox::IQ::Get, echelonJid, m_client->getID()); | glooxwrapper::IQ iq(gloox::IQ::Get, echelonJid, m_client->getID()); | ||||
iq.addExtension(b); | iq.addExtension(b); | ||||
DbgXMPP("SendIqGetProfile [" << tag_xml(iq) << "]"); | DbgXMPP("SendIqGetProfile [" << tag_xml(iq) << "]"); | ||||
m_client->send(iq); | m_client->send(iq); | ||||
} | } | ||||
void XmppClient::SendIqGetConnectionData(const std::string& jid) | |||||
{ | |||||
glooxwrapper::JID targetJID(jid); | |||||
ConnectionData* b = new ConnectionData(); | |||||
Done Inline ActionsStrange naming. vladislavbelov: Strange naming. | |||||
glooxwrapper::IQ iq(gloox::IQ::Get, targetJID, m_client->getID()); | |||||
iq.addExtension(b); | |||||
DbgXMPP("SendIqGetConnectionData []"); | |||||
m_client->send(iq); | |||||
} | |||||
Done Inline Actions? Stan: ? | |||||
Done Inline ActionsDocumentation: Request the Connection data (ip, port...) from the server. wraitii: Documentation: Request the Connection data (ip, port...) from the server. | |||||
/** | /** | ||||
* Send game report containing numerous game properties to the server. | * Send game report containing numerous game properties to the server. | ||||
* | * | ||||
* @param data A JS array of game statistics | * @param data A JS array of game statistics | ||||
*/ | */ | ||||
void XmppClient::SendIqGameReport(const ScriptInterface& scriptInterface, JS::HandleValue data) | void XmppClient::SendIqGameReport(const ScriptInterface& scriptInterface, JS::HandleValue data) | ||||
{ | { | ||||
glooxwrapper::JID echelonJid(m_echelonId); | glooxwrapper::JID echelonJid(m_echelonId); | ||||
Show All 17 Lines | void XmppClient::SendIqGameReport(const ScriptInterface& scriptInterface, JS::HandleValue data) | ||||
// Send IQ | // Send IQ | ||||
glooxwrapper::IQ iq(gloox::IQ::Set, echelonJid, m_client->getID()); | glooxwrapper::IQ iq(gloox::IQ::Set, echelonJid, m_client->getID()); | ||||
iq.addExtension(game); | iq.addExtension(game); | ||||
DbgXMPP("SendGameReport [" << tag_xml(iq) << "]"); | DbgXMPP("SendGameReport [" << tag_xml(iq) << "]"); | ||||
m_client->send(iq); | m_client->send(iq); | ||||
}; | }; | ||||
std::string XmppClient::GetGameIp(const ScriptInterface& scriptInterface, const std::string& hostName, bool stun) | |||||
Done Inline Actionsnuke Silier: nuke | |||||
{ | |||||
ScriptRequest rq(scriptInterface); | |||||
for (const glooxwrapper::Tag* const& t : m_GameList) | |||||
{ | |||||
JS::RootedValue game(rq.cx); | |||||
ScriptInterface::CreateObject(rq, &game); | |||||
glooxwrapper::string userName = t->findAttribute("hostUsername"); | |||||
if (userName.to_string().compare(hostName) == 0) | |||||
Done Inline Actionsshould not be here Silier: should not be here | |||||
return t->findAttribute(stun ? "stunIP" : "ip").to_string(); | |||||
} | |||||
Done Inline Actionsif stunIP not empty, return, else return regular Silier: if stunIP not empty, return, else return regular
i also wonder why there are two if clearly one… | |||||
return ""; | |||||
} | |||||
/** | /** | ||||
* Send a request to register a game to the server. | * Send a request to register a game to the server. | ||||
* | * | ||||
* @param data A JS array of game attributes | * @param data A JS array of game attributes | ||||
*/ | */ | ||||
void XmppClient::SendIqRegisterGame(const ScriptInterface& scriptInterface, JS::HandleValue data) | void XmppClient::SendIqRegisterGame(const ScriptInterface& scriptInterface, JS::HandleValue data) | ||||
{ | { | ||||
glooxwrapper::JID xpartamuppJid(m_xpartamuppId); | glooxwrapper::JID xpartamuppJid(m_xpartamuppId); | ||||
▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
void XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | void XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | ||||
{ | { | ||||
ScriptRequest rq(scriptInterface); | ScriptRequest rq(scriptInterface); | ||||
ScriptInterface::CreateArray(rq, ret); | ScriptInterface::CreateArray(rq, ret); | ||||
int j = 0; | int j = 0; | ||||
const char* stats[] = { "name", "ip", "port", "stunIP", "stunPort", "hostUsername", "state", | const char* stats[] = { "name", "port", "stunPort", "hostUsername", "state", | ||||
Done Inline Actionsremove ports Silier: remove ports | |||||
"nbp", "maxnbp", "players", "mapName", "niceMapName", "mapSize", "mapType", | "nbp", "maxnbp", "players", "mapName", "niceMapName", "mapSize", "mapType", | ||||
"victoryConditions", "startTime", "mods" }; | "victoryConditions", "startTime", "mods" }; | ||||
for(const glooxwrapper::Tag* const& t : m_GameList) | for(const glooxwrapper::Tag* const& t : m_GameList) | ||||
{ | { | ||||
JS::RootedValue game(rq.cx); | JS::RootedValue game(rq.cx); | ||||
ScriptInterface::CreateObject(rq, &game); | ScriptInterface::CreateObject(rq, &game); | ||||
for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) | for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) | ||||
scriptInterface.SetProperty(game, stats[i], t->findAttribute(stats[i])); | scriptInterface.SetProperty(game, stats[i], t->findAttribute(stats[i])); | ||||
scriptInterface.SetProperty(game, "useSTUN", !t->findAttribute("stunIP").empty()); | |||||
Done Inline Actionsnuke Silier: nuke | |||||
scriptInterface.SetPropertyInt(ret, j++, game); | scriptInterface.SetPropertyInt(ret, j++, game); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Handle requests from the GUI for leaderboard data. | * Handle requests from the GUI for leaderboard data. | ||||
* | * | ||||
* @return A JS array containing all known leaderboard data | * @return A JS array containing all known leaderboard data | ||||
▲ Show 20 Lines • Show All 204 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/** | /** | ||||
* Handle portions of messages containing custom stanza extensions. | * Handle portions of messages containing custom stanza extensions. | ||||
*/ | */ | ||||
bool XmppClient::handleIq(const glooxwrapper::IQ& iq) | bool XmppClient::handleIq(const glooxwrapper::IQ& iq) | ||||
{ | { | ||||
DbgXMPP("handleIq [" << tag_xml(iq) << "]"); | DbgXMPP("handleIq [" << tag_xml(iq) << "]"); | ||||
LOGWARNING("handleIq[%s]", tag_xml(iq)); | |||||
Done Inline Actionsnuke Silier: nuke | |||||
if (iq.subtype() == gloox::IQ::Result) | if (iq.subtype() == gloox::IQ::Result) | ||||
{ | { | ||||
const GameListQuery* gq = iq.findExtension<GameListQuery>(EXTGAMELISTQUERY); | const GameListQuery* gq = iq.findExtension<GameListQuery>(EXTGAMELISTQUERY); | ||||
const BoardListQuery* bq = iq.findExtension<BoardListQuery>(EXTBOARDLISTQUERY); | const BoardListQuery* bq = iq.findExtension<BoardListQuery>(EXTBOARDLISTQUERY); | ||||
const ProfileQuery* pq = iq.findExtension<ProfileQuery>(EXTPROFILEQUERY); | const ProfileQuery* pq = iq.findExtension<ProfileQuery>(EXTPROFILEQUERY); | ||||
const ConnectionData* cd = iq.findExtension<ConnectionData>(EXTCONNECTIONDATA); | |||||
if (cd) | |||||
{ | |||||
LOGMESSAGE("XmppClient: Received connection data from %s", iq.from().username()); | |||||
Done Inline Actionsnuke Silier: nuke | |||||
if (cd->m_Ip.empty()) | |||||
{ | |||||
LOGMESSAGE("Refused connection from %s" + iq.from().username()); | |||||
Done Inline Actionstransform to gui message, Silier: transform to gui message,
make sure to cancel this properly | |||||
g_NetClient->SetupServerData("", 0, false); | |||||
g_NetClient->TryToConnect(iq.from().full()); | |||||
SAFE_DELETE(g_NetClient); | |||||
Not Done Inline ActionsWhy is it needed to do this check? wraitii: Why is it needed to do this check? | |||||
Done Inline Actionsbecause iq is identified by sender and its id, so we react only to the ones we asked and no-one can break us just by sending random answer Silier: because iq is identified by sender and its id, so we react only to the ones we asked and no-one… | |||||
Not Done Inline Actions👍 wraitii: 👍 | |||||
return true; | |||||
} | |||||
g_NetClient->SetupServerData(cd->m_Ip.to_string(), stoi(cd->m_port.to_string()), !cd->m_useSTUN.empty()); | |||||
Not Done Inline ActionsI think it would be more logical to call PushGuiMessage directly. If you end up keeping the function, consider renaming it to HandleGetConnectionDataFailed, this makes it look like an FSM state but it's not one. wraitii: I think it would be more logical to call `PushGuiMessage` directly.
Presumably you should also… | |||||
Done Inline Actionsno, js is closing connection like in case of other error messages Silier: no, js is closing connection like in case of other error messages | |||||
Not Done Inline Actionsk I was wondering that. wraitii: k I was wondering that. | |||||
if (!g_NetClient->TryToConnect(iq.from().full())) | |||||
{ | |||||
LOGMESSAGE("Failed to connect to %s", iq.from().username()); | |||||
SilierAuthorUnsubmitted Done Inline Actionsgui message, cancel connecting properly Silier: gui message, cancel connecting properly | |||||
SAFE_DELETE(g_NetClient); | |||||
} | |||||
Done Inline Actionsuseless blank line wraitii: useless blank line | |||||
} | |||||
if (gq) | if (gq) | ||||
{ | { | ||||
for (const glooxwrapper::Tag* const& t : m_GameList) | for (const glooxwrapper::Tag* const& t : m_GameList) | ||||
glooxwrapper::Tag::free(t); | glooxwrapper::Tag::free(t); | ||||
m_GameList.clear(); | m_GameList.clear(); | ||||
for (const glooxwrapper::Tag* const& t : gq->m_GameList) | for (const glooxwrapper::Tag* const& t : gq->m_GameList) | ||||
m_GameList.emplace_back(t->clone()); | m_GameList.emplace_back(t->clone()); | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | if (lobbyAuth) | ||||
m_client->send(response); | m_client->send(response); | ||||
if (g_NetServer) | if (g_NetServer) | ||||
g_NetServer->OnLobbyAuth(iq.from().username(), lobbyAuth->m_Token.to_string()); | g_NetServer->OnLobbyAuth(iq.from().username(), lobbyAuth->m_Token.to_string()); | ||||
else | else | ||||
LOGERROR("Received lobby authentication request, but not hosting currently!"); | LOGERROR("Received lobby authentication request, but not hosting currently!"); | ||||
} | } | ||||
} | } | ||||
else if (iq.subtype() == gloox::IQ::Get) | |||||
{ | |||||
const ConnectionData* cd = iq.findExtension<ConnectionData>(EXTCONNECTIONDATA); | |||||
if (cd) | |||||
{ | |||||
LOGMESSAGE("XmppClient: Recieved request for connection data from %s", iq.from().username()); | |||||
Done Inline Actionswant to log to mainlog Silier: want to log to mainlog | |||||
if (!g_NetServer) | |||||
return true; | |||||
bool useSTUN = g_NetServer->GetUseSTUN(); | |||||
u16 port = useSTUN ? g_NetServer->GetSTUNport() : g_NetServer->GetPort(); | |||||
std::string ip = "127.0.0.1"; | |||||
if (useSTUN) | |||||
{ | |||||
ip = g_NetServer->GetSTUNip(); | |||||
} | |||||
else | |||||
// Get public ip | |||||
{ | |||||
if (!StunClient::FindStunEndpoint(ip, port)) | |||||
SilierAuthorUnsubmitted Done Inline Actionsthis is wrong, we need just public ip Silier: this is wrong, we need just public ip | |||||
ip = ""; | |||||
LOGWARNING("Found public ip and port: %s %u", ip, port); | |||||
Done Inline Actionsnuke Silier: nuke | |||||
} | |||||
glooxwrapper::IQ response(gloox::IQ::Result, iq.from(), iq.id()); | |||||
ConnectionData* connectionData = new ConnectionData(); | |||||
connectionData->m_Ip = ip; | |||||
connectionData->m_port = std::to_string(port); | |||||
connectionData->m_useSTUN = useSTUN ? "true" : ""; | |||||
response.addExtension(connectionData); | |||||
m_client->send(response); | |||||
} | |||||
} | |||||
else if (iq.subtype() == gloox::IQ::Error) | else if (iq.subtype() == gloox::IQ::Error) | ||||
CreateGUIMessage("system", "error", std::time(nullptr), "text", iq.error_error()); | CreateGUIMessage("system", "error", std::time(nullptr), "text", iq.error_error()); | ||||
else | else | ||||
{ | { | ||||
CreateGUIMessage("system", "error", std::time(nullptr), "text", wstring_from_utf8(g_L10n.Translate("unknown subtype (see logs)"))); | CreateGUIMessage("system", "error", std::time(nullptr), "text", wstring_from_utf8(g_L10n.Translate("unknown subtype (see logs)"))); | ||||
LOGMESSAGE("unknown subtype '%s'", tag_name(iq).c_str()); | LOGMESSAGE("unknown subtype '%s'", tag_name(iq).c_str()); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 492 Lines • Show Last 20 Lines |
revert