diff --git a/engine/server/application/CustomerServiceServer/src/shared/ConnectionServerConnection.cpp b/engine/server/application/CustomerServiceServer/src/shared/ConnectionServerConnection.cpp index 3031dd2a..1e70e7a5 100755 --- a/engine/server/application/CustomerServiceServer/src/shared/ConnectionServerConnection.cpp +++ b/engine/server/application/CustomerServiceServer/src/shared/ConnectionServerConnection.cpp @@ -24,6 +24,8 @@ #include "sharedNetwork/NetworkSetupData.h" #include "UnicodeUtils.h" +#include "sharedFoundation/CrcConstexpr.hpp" + //----------------------------------------------------------------------- ConnectionServerConnection::ConnectionServerConnection(const std::string & a, const unsigned short p) : @@ -62,11 +64,13 @@ void ConnectionServerConnection::onReceive(const Archive::ByteStream & message) ri = message.begin(); - if (m.isType("GameClientMessage")) + if (m.getType() == constcrc("GameClientMessage")) { GameClientMessage c(ri); Archive::ReadIterator cri = c.getByteStream().begin(); GameNetworkMessage cm(cri); + + const uint32 messageType = cm.getType(); std::vector::const_iterator i; for (i = c.getDistributionList().begin(); i != c.getDistributionList().end(); ++i) @@ -75,68 +79,81 @@ void ConnectionServerConnection::onReceive(const Archive::ByteStream & message) NetworkId const &networkId = (*i); - if (cm.isType("RequestCategoriesMessage")) - { - RequestCategoriesMessage message(cri); - CustomerServiceServer::getInstance().requestCategories(networkId, message.getLanguage()); - } - else if (cm.isType("ConnectPlayerMessage")) - { - ConnectPlayerMessage message(cri); - CustomerServiceServer::getInstance().requestRegisterCharacter(networkId, this, message.getStationId()); - } - else if (cm.isType("DisconnectPlayerMessage")) - { - CustomerServiceServer::getInstance().requestUnRegisterCharacter(networkId); - } - else if (cm.isType("CreateTicketMessage")) - { - CreateTicketMessage message(cri); + switch(messageType) { + case constcrc("RequestCategoriesMessage") : + { + RequestCategoriesMessage message(cri); + CustomerServiceServer::getInstance().requestCategories(networkId, message.getLanguage()); + break; + } + case constcrc("ConnectPlayerMessage") : + { + ConnectPlayerMessage message(cri); + CustomerServiceServer::getInstance().requestRegisterCharacter(networkId, this, message.getStationId()); + break; + } + case constcrc("DisconnectPlayerMessage") : + { + CustomerServiceServer::getInstance().requestUnRegisterCharacter(networkId); + break; + } + case constcrc("CreateTicketMessage") : + { + CreateTicketMessage message(cri); - CustomerServiceServer::getInstance().createTicket(networkId, - message.getStationId(), message.getCharacterName(), - message.getCategory(), message.getSubCategory(), - message.getDetails(), message.getHiddenDetails(), - message.getHarassingPlayerName(), - message.getLanguage(), message.isBug() - ); - } - else if (cm.isType("AppendCommentMessage")) - { - AppendCommentMessage message(cri); - CustomerServiceServer::getInstance().appendComment(networkId, message.getStationId(), message.getCharacterName(), message.getTicketId(), message.getComment()); - } - else if (cm.isType("CancelTicketMessage")) - { - CancelTicketMessage message(cri); - CustomerServiceServer::getInstance().cancelTicket(networkId, message.getStationId(), message.getTicketId(), message.getComment()); - } - else if (cm.isType("GetTicketsMessage")) - { - GetTicketsMessage message(cri); - CustomerServiceServer::getInstance().getTickets(networkId, message.getStationId()); - } - else if (cm.isType("GetCommentsMessage")) - { - GetCommentsMessage message(cri); - CustomerServiceServer::getInstance().getComments(networkId, - message.getTicketId()); - } - else if (cm.isType("SearchKnowledgeBaseMessage")) - { - SearchKnowledgeBaseMessage message(cri); - CustomerServiceServer::getInstance().searchKnowledgeBase(networkId, message.getSearchString(), message.getLanguage()); - } - else if (cm.isType("GetArticleMessage")) - { - GetArticleMessage message(cri); - CustomerServiceServer::getInstance().getArticle(networkId, message.getId(), message.getLanguage()); - } - else if (cm.isType("NewTicketActivityMessage")) - { - NewTicketActivityMessage message(cri); + CustomerServiceServer::getInstance().createTicket(networkId, + message.getStationId(), message.getCharacterName(), + message.getCategory(), message.getSubCategory(), + message.getDetails(), message.getHiddenDetails(), + message.getHarassingPlayerName(), + message.getLanguage(), message.isBug() + ); + break; + } + case constcrc("AppendCommentMessage") : + { + AppendCommentMessage message(cri); + CustomerServiceServer::getInstance().appendComment(networkId, message.getStationId(), message.getCharacterName(), message.getTicketId(), message.getComment()); + break; + } + case constcrc("CancelTicketMessage") : + { + CancelTicketMessage message(cri); + CustomerServiceServer::getInstance().cancelTicket(networkId, message.getStationId(), message.getTicketId(), message.getComment()); + break; + } + case constcrc("GetTicketsMessage") : + { + GetTicketsMessage message(cri); + CustomerServiceServer::getInstance().getTickets(networkId, message.getStationId()); + break; + } + case constcrc("GetCommentsMessage") : + { + GetCommentsMessage message(cri); + CustomerServiceServer::getInstance().getComments(networkId, + message.getTicketId()); + break; + } + case constcrc("SearchKnowledgeBaseMessage") : + { + SearchKnowledgeBaseMessage message(cri); + CustomerServiceServer::getInstance().searchKnowledgeBase(networkId, message.getSearchString(), message.getLanguage()); + break; + } + case constcrc("GetArticleMessage") : + { + GetArticleMessage message(cri); + CustomerServiceServer::getInstance().getArticle(networkId, message.getId(), message.getLanguage()); + break; + } + case constcrc("NewTicketActivityMessage") : + { + NewTicketActivityMessage message(cri); - CustomerServiceServer::getInstance().requestNewTicketActivity(networkId, message.getStationId()); + CustomerServiceServer::getInstance().requestNewTicketActivity(networkId, message.getStationId()); + break; + } } } } diff --git a/engine/server/application/LoginServer/src/shared/CentralServerConnection.cpp b/engine/server/application/LoginServer/src/shared/CentralServerConnection.cpp index 2f096fce..443e187e 100755 --- a/engine/server/application/LoginServer/src/shared/CentralServerConnection.cpp +++ b/engine/server/application/LoginServer/src/shared/CentralServerConnection.cpp @@ -30,6 +30,8 @@ #include "Unicode.h" #include "UnicodeUtils.h" +#include "sharedFoundation/CrcConstexpr.hpp" + //----------------------------------------------------------------------- namespace CentralServerConnectionNamespace @@ -101,194 +103,216 @@ void CentralServerConnection::onReceive(const Archive::ByteStream & message) Archive::ReadIterator ri = message.begin(); GameNetworkMessage m(ri); ri = message.begin(); - // handle messages the connection object itself may be interested in - if(m.isType("LoginClusterName")) - { - const LoginClusterName c(ri); - ri = message.begin(); - setClusterName(c.getClusterName()); - LOG("CentralServerConnection", ("Galaxy [%s] connected", c.getClusterName().c_str())); - } - else if ( m.isType( "LoginClusterName2" ) ) - { - const LoginClusterName2 c( ri ); - ri = message.begin(); - - const std::string &clusterName = c.getClusterName(); - const std::string &branch = c.getBranch(); - const int changelist = c.getChangelist(); - const std::string &networkVersion = c.getNetworkVersion(); - - DEBUG_REPORT_LOG( true, ( "!!!!!!!!!!!!!!!! name=%s branch=%s changelist=%d net=%s\n", clusterName.c_str(), branch.c_str(), changelist, networkVersion.c_str() ) ); - - setClusterName( clusterName ); - setNetworkVersion( c.getNetworkVersion() ); - LOG("CentralServerConnection", ("Galaxy [%s] connected", getClusterName().c_str())); - - LoginServer::getInstance().setClusterInfoByName( clusterName, branch, changelist, networkVersion ); - - } - else if(m.isType("ToggleAvatarLoginStatus")) - { - const ToggleAvatarLoginStatus t(ri); - if(t.getEnabled()) - { - LOG("CustomerService", ("CharacterTransfer: ToggleAvatarLoginStatus(%s, %d, %s, true)", t.getClusterName().c_str(), t.getStationId(), t.getCharacterId().getValueString().c_str())); - } - else - { - // send message to the cluster to drop connected clients for the - // station id in case the avatar being disabled is currently logged in - GenericValueTypeMessage const closeRequest("TransferCloseClientConnection", t.getStationId()); - LoginServer::getInstance().sendToCluster(LoginServer::getInstance().getClusterIDByName(t.getClusterName()), closeRequest); - - LOG("CustomerService", ("CharacterTransfer: ToggleAvatarLoginStatus(%s, %d, %s, false)\n", t.getClusterName().c_str(), t.getStationId(), t.getCharacterId().getValueString().c_str())); - } - DatabaseConnection::getInstance().toggleDisableCharacter(LoginServer::getInstance().getClusterIDByName(t.getClusterName()), t.getCharacterId(), t.getStationId(), t.getEnabled()); - } - else if(m.isType("CtsCompletedForcharacter")) - { - const GenericValueTypeMessage > msg(ri); - LoginServer::getInstance().sendToCluster(LoginServer::getInstance().getClusterIDByName(msg.getValue().first), msg); - } - else if(m.isType("TransferRequestCharacterList")) - { - const GenericValueTypeMessage request(ri); - const TransferCharacterData & d = request.getValue(); - DatabaseConnection::getInstance().requestAvatarListForAccount(d.getSourceStationId(), &d); - } - else if(m.isType("TransferReplyLoginLocationData")) - { - const GenericValueTypeMessage reply(ri); - const TransferCharacterData & d = reply.getValue(); - LOG("CustomerService", ("CharacterTransfer: Received login location data. %s", d.toString().c_str())); - } - else if(m.isType("TransferGetCharacterDataFromLoginServer")) - { - // the TransferServer sent a request to the central server - // to retrieve a character ID from the login database given - // a source station ID and a source character name. Retrieve - // this data from the login database. - const GenericValueTypeMessage request(ri); - TransferCharacterData d = request.getValue(); - DatabaseConnection::getInstance().requestAvatarListForAccount(d.getSourceStationId(), &d); - LOG("CustomerService", ("CharacterTransfer: Received TransferGetCharactetrDataFromLoginServer from CentralServer. %s", d.toString().c_str())); - } - else if(m.isType("TransferRenameCharacterInLoginDatabase")) - { - const GenericValueTypeMessage request(ri); - LOG("CustomerService", ("CharacterTransfer: Received TransferRenameCharacterInLoginDatabase : %s", request.getValue().toString().c_str())); - const TransferCharacterData & requestData = request.getValue(); - DatabaseConnection::getInstance().renameCharacter(getClusterId(), requestData.getCharacterId(), Unicode::narrowToWide(requestData.getDestinationCharacterName()), &requestData); - } - else if(m.isType("TransferKickConnectedClients")) - { - const GenericValueTypeMessage kick(ri); - ClientConnection * clientConnection = LoginServer::getInstance().getValidatedClient(kick.getValue()); - if(! clientConnection) - { - clientConnection = LoginServer::getInstance().getUnvalidatedClient(kick.getValue()); - } - - if(clientConnection) - { - clientConnection->disconnect(); - } - } - else if(m.isType("TransferAccountRequestLoginServer")) - { - const GenericValueTypeMessage request(ri); - LOG("CustomerService", ("CharacterTransfer: Received TransferAccountRequestLoginServer from station ID %d to from station ID %d", request.getValue().getSourceStationId(), request.getValue().getDestinationStationId())); - const TransferAccountData requestData = request.getValue(); - DatabaseConnection::getInstance().requestAvatarListAccountTransfer(&requestData); - } - else if(m.isType("EnableCharacterMessage")) - { - const GenericValueTypeMessage, std::string> > msg(ri); - - LOG("LoginServer", ("EnableCharacter %d, %s request from %s\n", msg.getValue().first.first, msg.getValue().first.second.getValueString().c_str(), msg.getValue().second.c_str())); - - DatabaseConnection::getInstance().enableCharacter(msg.getValue().first.first, msg.getValue().first.second, msg.getValue().second, true, m_clusterId); - } - else if(m.isType("DisableCharacterMessage")) - { - const GenericValueTypeMessage, std::string> > msg(ri); - - LOG("LoginServer", ("DisableCharacter %d, %s request from %s\n", msg.getValue().first.first, msg.getValue().first.second.getValueString().c_str(), msg.getValue().second.c_str())); - - DatabaseConnection::getInstance().enableCharacter(msg.getValue().first.first, msg.getValue().first.second, msg.getValue().second, false, m_clusterId); - } - else if(m.isType("DeleteFailedTransfer")) - { - GenericValueTypeMessage deleteCharacter(ri); - LOG("CustomerService", ("CharacterTransfer: LoginServer received request to delete a character for a failed transfer. %s", deleteCharacter.getValue().toString().c_str())); - LoginServer::getInstance().deleteCharacter(m_clusterId, deleteCharacter.getValue().getDestinationCharacterId(), deleteCharacter.getValue().getDestinationStationId()); - } - else if(m.isType("RequestTransferClosePseudoClientConnection")) - { - GenericValueTypeMessage > const request(ri); - GenericValueTypeMessage const closeRequest("TransferClosePseudoClientConnection", request.getValue().second); - LoginServer::getInstance().sendToCluster(LoginServer::getInstance().getClusterIDByName(request.getValue().first), closeRequest); - } - else if(m.isType("CSToolResponse" ) ) - { - CSToolResponse response(ri); - // find the connection, if it still exists - CSToolConnection * con = CSToolConnection::getCSToolConnectionByToolId( response.getToolId() ); - - // send the response - if( con ) - { - std::string message; - message = m_clusterName + ":" + response.getResult(); - - if( message[ message.length() -1 ] == '\n' && message[ message.length() - 2 ] != '\r' ) - { - message[ message.length() - 1 ] = '\r'; - message += '\n'; - } - - con->sendToTool( message ); - } - } - else if(m.isType("ConGenericMessage")) - { - ConGenericMessage con(ri); - parseCommand(con.getMsg(), con.getMsgId()); - } - else if(m.isType("LoginToggleCompletedTutorial")) - { - GenericValueTypeMessage< std::pair > const request(ri); - std::pair values = request.getValue(); - DatabaseConnection::getInstance().toggleCompletedTutorial(values.first, values.second); - } - else if(m.isType("AllCluserGlobalChannel")) - { - typedef std::pair, bool> PayloadType; - GenericValueTypeMessage msg(ri); + const uint32 messageType = m.getType(); + + // handle messages the connection object itself may be interested in + switch (messageType) { + case constcrc("LoginClusterName") : + { + const LoginClusterName c(ri); + ri = message.begin(); + setClusterName(c.getClusterName()); + LOG("CentralServerConnection", ("Galaxy [%s] connected", c.getClusterName().c_str())); + break; + } + case constcrc( "LoginClusterName2" ) : + { + const LoginClusterName2 c( ri ); + ri = message.begin(); + + const std::string &clusterName = c.getClusterName(); + const std::string &branch = c.getBranch(); + const int changelist = c.getChangelist(); + const std::string &networkVersion = c.getNetworkVersion(); + + DEBUG_REPORT_LOG( true, ( "!!!!!!!!!!!!!!!! name=%s branch=%s changelist=%d net=%s\n", clusterName.c_str(), branch.c_str(), changelist, networkVersion.c_str() ) ); + + setClusterName( clusterName ); + setNetworkVersion( c.getNetworkVersion() ); + LOG("CentralServerConnection", ("Galaxy [%s] connected", getClusterName().c_str())); + + LoginServer::getInstance().setClusterInfoByName( clusterName, branch, changelist, networkVersion ); + + break; + } + case constcrc("ToggleAvatarLoginStatus") : + { + const ToggleAvatarLoginStatus t(ri); + if(t.getEnabled()) + { + LOG("CustomerService", ("CharacterTransfer: ToggleAvatarLoginStatus(%s, %d, %s, true)", t.getClusterName().c_str(), t.getStationId(), t.getCharacterId().getValueString().c_str())); + } + else + { + // send message to the cluster to drop connected clients for the + // station id in case the avatar being disabled is currently logged in + GenericValueTypeMessage const closeRequest("TransferCloseClientConnection", t.getStationId()); + LoginServer::getInstance().sendToCluster(LoginServer::getInstance().getClusterIDByName(t.getClusterName()), closeRequest); - PayloadType const & payload = msg.getValue(); - std::string const & channelName = payload.first.first; - std::string const & messageText = payload.first.second; - bool const & isRemove = payload.second; + LOG("CustomerService", ("CharacterTransfer: ToggleAvatarLoginStatus(%s, %d, %s, false)\n", t.getClusterName().c_str(), t.getStationId(), t.getCharacterId().getValueString().c_str())); + } + DatabaseConnection::getInstance().toggleDisableCharacter(LoginServer::getInstance().getClusterIDByName(t.getClusterName()), t.getCharacterId(), t.getStationId(), t.getEnabled()); + break; + } + case constcrc("CtsCompletedForcharacter") : + { + const GenericValueTypeMessage > msg(ri); + LoginServer::getInstance().sendToCluster(LoginServer::getInstance().getClusterIDByName(msg.getValue().first), msg); + break; + } + case constcrc("TransferRequestCharacterList") : + { + const GenericValueTypeMessage request(ri); + const TransferCharacterData & d = request.getValue(); + DatabaseConnection::getInstance().requestAvatarListForAccount(d.getSourceStationId(), &d); + break; + } + case constcrc("TransferReplyLoginLocationData") : + { + const GenericValueTypeMessage reply(ri); + const TransferCharacterData & d = reply.getValue(); + LOG("CustomerService", ("CharacterTransfer: Received login location data. %s", d.toString().c_str())); + break; + } + case constcrc("TransferGetCharacterDataFromLoginServer") : + { + // the TransferServer sent a request to the central server + // to retrieve a character ID from the login database given + // a source station ID and a source character name. Retrieve + // this data from the login database. + const GenericValueTypeMessage request(ri); + TransferCharacterData d = request.getValue(); + DatabaseConnection::getInstance().requestAvatarListForAccount(d.getSourceStationId(), &d); + LOG("CustomerService", ("CharacterTransfer: Received TransferGetCharactetrDataFromLoginServer from CentralServer. %s", d.toString().c_str())); + break; + } + case constcrc("TransferRenameCharacterInLoginDatabase") : + { + const GenericValueTypeMessage request(ri); + LOG("CustomerService", ("CharacterTransfer: Received TransferRenameCharacterInLoginDatabase : %s", request.getValue().toString().c_str())); + const TransferCharacterData & requestData = request.getValue(); + DatabaseConnection::getInstance().renameCharacter(getClusterId(), requestData.getCharacterId(), Unicode::narrowToWide(requestData.getDestinationCharacterName()), &requestData); + break; + } + case constcrc("TransferKickConnectedClients") : + { + const GenericValueTypeMessage kick(ri); + ClientConnection * clientConnection = LoginServer::getInstance().getValidatedClient(kick.getValue()); + if(! clientConnection) + { + clientConnection = LoginServer::getInstance().getUnvalidatedClient(kick.getValue()); + } - LOG("CustomerService", ("BroadcastVoiceChannel: LoginServer sending AllCluserGlobalChannel to all clusters chan(%s) text(%s) remove(%d)", - channelName.c_str(), messageText.c_str(), (isRemove?1:0) )); + if(clientConnection) + { + clientConnection->disconnect(); + } + break; + } + case constcrc("TransferAccountRequestLoginServer") : + { + const GenericValueTypeMessage request(ri); + LOG("CustomerService", ("CharacterTransfer: Received TransferAccountRequestLoginServer from station ID %d to from station ID %d", request.getValue().getSourceStationId(), request.getValue().getDestinationStationId())); + const TransferAccountData requestData = request.getValue(); + DatabaseConnection::getInstance().requestAvatarListAccountTransfer(&requestData); + break; + } + case constcrc("EnableCharacterMessage") : + { + const GenericValueTypeMessage, std::string> > msg(ri); - LoginServer::getInstance().sendToAllClusters(msg); - } + LOG("LoginServer", ("EnableCharacter %d, %s request from %s\n", msg.getValue().first.first, msg.getValue().first.second.getValueString().c_str(), msg.getValue().second.c_str())); - else if(m.isType("GcwScoreStatRaw")) - { - GenericValueTypeMessage >, std::map > > > > const msg(ri); - LoginServer::getInstance().sendToAllClusters(msg, nullptr, 0, msg.getValue().first.c_str()); - } + DatabaseConnection::getInstance().enableCharacter(msg.getValue().first.first, msg.getValue().first.second, msg.getValue().second, true, m_clusterId); + break; + } + case constcrc("DisableCharacterMessage") : + { + const GenericValueTypeMessage, std::string> > msg(ri); - else if(m.isType("GcwScoreStatPct")) - { - GenericValueTypeMessage, std::map > > > const msg(ri); - LoginServer::getInstance().sendToAllClusters(msg, nullptr, 0, msg.getValue().first.c_str()); + LOG("LoginServer", ("DisableCharacter %d, %s request from %s\n", msg.getValue().first.first, msg.getValue().first.second.getValueString().c_str(), msg.getValue().second.c_str())); + + DatabaseConnection::getInstance().enableCharacter(msg.getValue().first.first, msg.getValue().first.second, msg.getValue().second, false, m_clusterId); + break; + } + case constcrc("DeleteFailedTransfer") : + { + GenericValueTypeMessage deleteCharacter(ri); + LOG("CustomerService", ("CharacterTransfer: LoginServer received request to delete a character for a failed transfer. %s", deleteCharacter.getValue().toString().c_str())); + LoginServer::getInstance().deleteCharacter(m_clusterId, deleteCharacter.getValue().getDestinationCharacterId(), deleteCharacter.getValue().getDestinationStationId()); + break; + } + case constcrc("RequestTransferClosePseudoClientConnection") : + { + GenericValueTypeMessage > const request(ri); + GenericValueTypeMessage const closeRequest("TransferClosePseudoClientConnection", request.getValue().second); + LoginServer::getInstance().sendToCluster(LoginServer::getInstance().getClusterIDByName(request.getValue().first), closeRequest); + break; + } + case constcrc("CSToolResponse") : + { + CSToolResponse response(ri); + // find the connection, if it still exists + CSToolConnection * con = CSToolConnection::getCSToolConnectionByToolId( response.getToolId() ); + + // send the response + if( con ) + { + std::string message; + message = m_clusterName + ":" + response.getResult(); + + if( message[ message.length() -1 ] == '\n' && message[ message.length() - 2 ] != '\r' ) + { + message[ message.length() - 1 ] = '\r'; + message += '\n'; + } + + con->sendToTool( message ); + } + break; + } + case constcrc("ConGenericMessage") : + { + ConGenericMessage con(ri); + parseCommand(con.getMsg(), con.getMsgId()); + break; + } + case constcrc("LoginToggleCompletedTutorial") : + { + GenericValueTypeMessage< std::pair > const request(ri); + std::pair values = request.getValue(); + DatabaseConnection::getInstance().toggleCompletedTutorial(values.first, values.second); + break; + } + case constcrc("AllCluserGlobalChannel") : + { + typedef std::pair, bool> PayloadType; + GenericValueTypeMessage msg(ri); + + PayloadType const & payload = msg.getValue(); + std::string const & channelName = payload.first.first; + std::string const & messageText = payload.first.second; + bool const & isRemove = payload.second; + + LOG("CustomerService", ("BroadcastVoiceChannel: LoginServer sending AllCluserGlobalChannel to all clusters chan(%s) text(%s) remove(%d)", + channelName.c_str(), messageText.c_str(), (isRemove?1:0) )); + + LoginServer::getInstance().sendToAllClusters(msg); + break; + } + case constcrc("GcwScoreStatRaw") : + { + GenericValueTypeMessage >, std::map > > > > const msg(ri); + LoginServer::getInstance().sendToAllClusters(msg, nullptr, 0, msg.getValue().first.c_str()); + break; + } + case constcrc("GcwScoreStatPct") : + { + GenericValueTypeMessage, std::map > > > const msg(ri); + LoginServer::getInstance().sendToAllClusters(msg, nullptr, 0, msg.getValue().first.c_str()); + break; + } } } @@ -354,6 +378,7 @@ void CentralServerConnection::setClusterId(uint32 clusterId) void CentralServerConnection::parseCommand(const std::string & cmd, int track) { + //TODO: wtf is this crap? // int i = s_track; // s_resultsMap[i] = this; // ++s_track; diff --git a/engine/server/application/LoginServer/src/shared/ClientConnection.cpp b/engine/server/application/LoginServer/src/shared/ClientConnection.cpp index a4ea6168..03b24c70 100755 --- a/engine/server/application/LoginServer/src/shared/ClientConnection.cpp +++ b/engine/server/application/LoginServer/src/shared/ClientConnection.cpp @@ -23,6 +23,8 @@ #include "sharedNetworkMessages/GenericValueTypeMessage.h" #include "sharedNetworkMessages/LoginEnumCluster.h" +#include "sharedFoundation/CrcConstexpr.hpp" + #include #include "webAPI.h" @@ -97,77 +99,80 @@ void ClientConnection::onReceive(const Archive::ByteStream & message) GameNetworkMessage m(ri); ri = message.begin(); - //Validation check - if (!getIsValidated() && !m.isType("LoginClientId")) - { - //Receiving message from unvalidated client. Pitch it. - DEBUG_WARNING(true, ("Received %s message from unknown, unvalidated client", m.getCmdName().c_str())); - return; - } + const uint32 messageType = m.getType(); - if(m.isType("LoginClientId")) - { - // send the client the server "now" Epoch time so that the - // client has an idea of how much difference there is between - // the client's Epoch time and the server Epoch time - GenericValueTypeMessage const serverNowEpochTime( - "ServerNowEpochTime", static_cast(::time(nullptr))); - send(serverNowEpochTime, true); - - LoginClientId id(ri); - - // verify version -#if PRODUCTION == 1 - - if(!ConfigLoginServer::getValidateClientVersion() || id.getVersion() == GameNetworkMessage::NetworkVersionId) + switch (messageType) { + case constcrc("LoginClientId") : { - validateClient(id.getId(), id.getKey()); - } - else - { - LOG("CustomerService", ("Login:LoginServer dropping client (stationId=[%lu], ip=[%s], id=[%s], key=[%s], version=[%s]) because of network version mismatch (required version=[%s])", m_stationId, getRemoteAddress().c_str(), id.getId().c_str(), id.getKey().c_str(), id.getVersion().c_str(), GameNetworkMessage::NetworkVersionId.c_str())); - // disconnect is handled on the client side, as soon as it recieves this message - #if _DEBUG - LoginIncorrectClientId incorrectId(GameNetworkMessage::NetworkVersionId, ApplicationVersion::getInternalVersion()); - #else - LoginIncorrectClientId incorrectId("", ""); - #endif // _DEBUG - send(incorrectId, true); - } - -#else - - validateClient( id.getId(), id.getKey() ); - -#endif // PRODUCTION == 1 - - } - else if ( m.isType( "RequestExtendedClusterInfo" ) ) - { - LoginServer::getInstance().sendExtendedClusterInfo( *this ); - } - else if (m.isType("DeleteCharacterMessage")) - { - DeleteCharacterMessage msg(ri); - std::vector::const_iterator f = std::find(m_charactersPendingDeletion.begin(), m_charactersPendingDeletion.end(), msg.getCharacterId()); - if ((m_waitingForCharacterLoginDeletion || m_waitingForCharacterClusterDeletion) && f != m_charactersPendingDeletion.end()) - { - DeleteCharacterReplyMessage reply(DeleteCharacterReplyMessage::rc_ALREADY_IN_PROGRESS); - send(reply,true); - } - else - { - if (LoginServer::getInstance().deleteCharacter(msg.getClusterId(), msg.getCharacterId(), getStationId())) + //Validation check + if (!getIsValidated() && messageType == constcrc("LoginClientId")) { - m_waitingForCharacterLoginDeletion=true; - m_waitingForCharacterClusterDeletion=true; - m_charactersPendingDeletion.push_back(msg.getCharacterId()); + //Receiving message from unvalidated client. Pitch it. + DEBUG_WARNING(true, ("Received %s message from unknown, unvalidated client", m.getCmdName().c_str())); + return; + } else { + // send the client the server "now" Epoch time so that the + // client has an idea of how much difference there is between + // the client's Epoch time and the server Epoch time + GenericValueTypeMessage const serverNowEpochTime( + "ServerNowEpochTime", static_cast(::time(nullptr))); + send(serverNowEpochTime, true); + + LoginClientId id(ri); + + // verify version + #if PRODUCTION == 1 + if(!ConfigLoginServer::getValidateClientVersion() || id.getVersion() == GameNetworkMessage::NetworkVersionId) + { + validateClient(id.getId(), id.getKey()); + } + else + { + LOG("CustomerService", ("Login:LoginServer dropping client (stationId=[%lu], ip=[%s], id=[%s], key=[%s], version=[%s]) because of network version mismatch (required version=[%s])", m_stationId, getRemoteAddress().c_str(), id.getId().c_str(), id.getKey().c_str(), id.getVersion().c_str(), GameNetworkMessage::NetworkVersionId.c_str())); + // disconnect is handled on the client side, as soon as it recieves this message + #if _DEBUG + LoginIncorrectClientId incorrectId(GameNetworkMessage::NetworkVersionId, ApplicationVersion::getInternalVersion()); + #else + LoginIncorrectClientId incorrectId("", ""); + #endif // _DEBUG + send(incorrectId, true); + } + #else + validateClient( id.getId(), id.getKey() ); + #endif // PRODUCTION == 1 + } + + break; + } + case constcrc("RequestExtendedClusterInfo" ) : + { + LoginServer::getInstance().sendExtendedClusterInfo( *this ); + break; + } + case constcrc("DeleteCharacterMessage") : + { + DeleteCharacterMessage msg(ri); + std::vector::const_iterator f = std::find(m_charactersPendingDeletion.begin(), m_charactersPendingDeletion.end(), msg.getCharacterId()); + if ((m_waitingForCharacterLoginDeletion || m_waitingForCharacterClusterDeletion) && f != m_charactersPendingDeletion.end()) + { + DeleteCharacterReplyMessage reply(DeleteCharacterReplyMessage::rc_ALREADY_IN_PROGRESS); + send(reply,true); } else { - DeleteCharacterReplyMessage reply(DeleteCharacterReplyMessage::rc_CLUSTER_DOWN); - send(reply,true); + if (LoginServer::getInstance().deleteCharacter(msg.getClusterId(), msg.getCharacterId(), getStationId())) + { + m_waitingForCharacterLoginDeletion=true; + m_waitingForCharacterClusterDeletion=true; + m_charactersPendingDeletion.push_back(msg.getCharacterId()); + } + else + { + DeleteCharacterReplyMessage reply(DeleteCharacterReplyMessage::rc_CLUSTER_DOWN); + send(reply,true); + } } + break; } } } diff --git a/engine/server/application/LoginServer/src/shared/LoginServer.cpp b/engine/server/application/LoginServer/src/shared/LoginServer.cpp index 75ddf13b..164038e8 100755 --- a/engine/server/application/LoginServer/src/shared/LoginServer.cpp +++ b/engine/server/application/LoginServer/src/shared/LoginServer.cpp @@ -68,6 +68,8 @@ #include "sharedNetworkMessages/LoginEnumCluster.h" #include "sharedUtility/DataTableManager.h" +#include "sharedFoundation/CrcConstexpr.hpp" + #include //----------------------------------------------------------------------- @@ -388,616 +390,655 @@ void LoginServer::pushKeyToAllServers(void) void LoginServer::receiveMessage(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message) { // determine message type + const uint32 messageType = message.getType(); - if (message.isType("LoginClusterName") || message.isType("LoginClusterName2")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - const LoginClusterName msg(ri); - if (msg.getClusterName().length() > 0) + switch(messageType) { + case constcrc("LoginClusterName") : + case constcrc("LoginClusterName2") : { - CentralServerConnection * connection = const_cast(safe_cast(&source)); - DEBUG_REPORT_LOG(true, ("Cluster connection %s opened\n", msg.getClusterName().c_str())); - ClusterListEntry *cle = nullptr; - if (ConfigLoginServer::getDevelopmentMode()) { - // in this mode, we trust the name sent by the cluster - cle = findClusterByName(msg.getClusterName()); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + const LoginClusterName msg(ri); + if (msg.getClusterName().length() > 0) + { + CentralServerConnection * connection = const_cast(safe_cast(&source)); + DEBUG_REPORT_LOG(true, ("Cluster connection %s opened\n", msg.getClusterName().c_str())); + ClusterListEntry *cle = nullptr; + if (ConfigLoginServer::getDevelopmentMode()) { + // in this mode, we trust the name sent by the cluster + cle = findClusterByName(msg.getClusterName()); #ifdef _DEBUG - // if in debug mode, we dynamically add clusters we don't know about - // DO NOT USE ON PRODUCTION! This is where other servers are getting hijacked. - if (!cle) - { - cle = addCluster(msg.getClusterName()); - } -#endif - } - else - { - // in this mode, the cluster name has to match what we were expecting - cle = findClusterByConnection(connection); - if (!cle) - DEBUG_FATAL(true, ("PROGRAMMER BUG: Got a connection from %s:%hu, which we weren't expecting. Cluster name is \"%s\".\n", connection->getRemoteAddress().c_str(), connection->getRemotePort(), msg.getClusterName().c_str())); - else - if (msg.getClusterName() != cle->m_clusterName) + // if in debug mode, we dynamically add clusters we don't know about + // DO NOT USE ON PRODUCTION! This is where other servers are getting hijacked. + if (!cle) { - WARNING(true, ("Server %i is named \"%s\" in the database. The server at the specified address (%s:%hu) reports its name as \"%s\". It will not be allowed in the service. Either the name in the database or the name in Central's config file should be corrected.\n", cle->m_clusterId, cle->m_clusterName.c_str(), connection->getRemoteAddress().c_str(), connection->getRemotePort(), msg.getClusterName().c_str())); - disconnectCluster(*cle, true, false); - cle = nullptr; + cle = addCluster(msg.getClusterName()); } - } - - if (cle) - { - cle->m_timeZone = msg.getTimeZone(); - cle->m_centralServerConnection = connection; - cle->m_connected = true; - pushAllKeys(connection); - - if (cle->m_clusterId == 0) - { - DEBUG_FATAL(!ConfigLoginServer::getDevelopmentMode(), ("Programmer bug: cle->m_clusterId was 0 in non-development mode. The code before this line should have prevented this.\n")); - DEBUG_REPORT_LOG(true, ("Cluster was not on the list. Adding it to the database.\n")); - DatabaseConnection::getInstance().registerNewCluster(msg.getClusterName(), connection->getRemoteAddress()); - } - else - cle->m_centralServerConnection->setClusterId(cle->m_clusterId); - - m_clusterStatusChanged = true; - - // tell the cluster its cluster id - if (cle->m_clusterId > 0) - { - GenericValueTypeMessage const msgClusterId("ClusterId", cle->m_clusterId); - cle->m_centralServerConnection->send(msgClusterId, true); - } - - // tell the cluster about its locked and secret state - GenericValueTypeMessage > const msgState("UpdateClusterLockedAndSecretState", std::make_pair(cle->m_locked, cle->m_secret)); - cle->m_centralServerConnection->send(msgState, true); - } - } - } - else if (message.isType("LoginConnectionServerAddress")) - { - const CentralServerConnection * cs = safe_cast(&source); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - - LoginConnectionServerAddress m(ri); //lint !e1774 !e826onServerEntry entry; - ConnectionServerEntry entry; - entry.clientServiceAddress = Address(Address(m.getClientServiceAddress(), 0).getSockAddr4()).getHostAddress(); - entry.clientServicePortPrivate = m.getClientServicePortPrivate(); - entry.clientServicePortPublic = m.getClientServicePortPublic(); - entry.id = m.getId(); - entry.numClients = m.getNumClients(); - entry.pingPort = m.getPingPort(); - - DEBUG_REPORT_LOG(true, ("ConnectionServer Reconnect - address from connection server (%s), address after conversion (%s)\n", m.getClientServiceAddress().c_str(), entry.clientServiceAddress.c_str())); - - ClusterListEntry *cle = findClusterByConnection(cs); - if (cle) - { - WARNING_STRICT_FATAL(!cle->m_centralServerConnection, ("Got reconnect for connection server with no central! Cluster %s\n", cs->getClusterName().c_str())); - std::vector::iterator i = std::find(cle->m_connectionServers.begin(), cle->m_connectionServers.end(), entry); - if (i == cle->m_connectionServers.end()) - { - cle->m_connectionServers.push_back(entry); - m_clusterStatusChanged = true; - } - else - { - *i = entry; - } - - std::sort(cle->m_connectionServers.begin(), cle->m_connectionServers.end(), ConnectionServerEntryLessThan()); - } - else - WARNING_STRICT_FATAL(true, ("Programmer bug: Got LoginConnectionServerAddress from a cluster that wasn't on the list. Probably indicates we aren't tracking connections properly.\n")); - } - else if (message.isType("PreloadFinishedMessage")) - { - const CentralServerConnection * cs = safe_cast(&source); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - PreloadFinishedMessage msg(ri); - - ClusterListEntry *cle = findClusterByConnection(cs); - if (cle) - { - if (msg.getFinished()) - { - REPORT_LOG(true, ("Cluster %s is ready for players.\n", cle->m_clusterName.c_str())); - if (!cle->m_readyForPlayers) - { - cle->m_readyForPlayers = true; - m_clusterStatusChanged = true; - } - } - else - { - REPORT_LOG(true, ("Cluster %s is not ready for players.\n", cle->m_clusterName.c_str())); - if (cle->m_readyForPlayers) - { - cle->m_readyForPlayers = false; - m_clusterStatusChanged = true; - PurgeManager::onClusterNoLongerReady(cle->m_clusterId); - } - } - } - else - WARNING_STRICT_FATAL(true, ("Programmer bug: Got PreloadFinishedMessage from a cluster that wasn't on the list. Probably indicates we aren't tracking connections properly.\n")); - } - else if (message.isType("ConnectionServerDown")) - { - const CentralServerConnection * centralConnection = safe_cast(&source); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ConnectionServerDown c(ri); //lint !e1774 !e826 - ClusterListEntry *cle = findClusterByConnection(centralConnection); - if (cle) - { - DEBUG_REPORT_LOG(true, ("Lost a connection server %d for %s.\n", c.getId(), cle->m_clusterName.c_str())); - - std::vector::iterator iter = cle->m_connectionServers.begin(); - bool found = false; - for (; iter != cle->m_connectionServers.end(); ++iter) - { - if (iter->id == c.getId()) - { - IGNORE_RETURN(cle->m_connectionServers.erase(iter)); - std::sort(cle->m_connectionServers.begin(), cle->m_connectionServers.end(), ConnectionServerEntryLessThan()); - found = true; - break; - } - } - DEBUG_REPORT_LOG(!found, ("Tried to remove a connection server that wasn't in our list.\n")); - m_clusterStatusChanged = true; - } - else - WARNING_STRICT_FATAL(true, ("Programmer bug: Got ConnectionServerDown from a cluster that wasn't on the list. Probably indicates we aren't tracking connections properly.\n")); - } - else if (message.isType("ConnectionClosed")) - { - const CentralServerConnection *c = dynamic_cast(&source); - if (c) - { - ClusterListEntry *cle = findClusterByConnection(c); - if (cle) - { - DEBUG_REPORT_LOG(true, ("Cluster connection %s closed.\n", c->getClusterName().c_str())); - disconnectCluster(*cle, false, true); - } - else - WARNING_STRICT_FATAL(true, ("Programmer bug: Cluster disconnected but it wasn't on the list. Probably indicates we aren't tracking connections properly.\n")); - } - } - else if (message.isType("ValidateAccountMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ValidateAccountMessage msg(ri); - - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - DatabaseConnection::getInstance().getAccountValidationData(msg.getStationId(), conn->getClusterId(), msg.getTrack(), msg.getSubscriptionBits()); - else - WARNING_STRICT_FATAL(true, ("Expect ValidateAccountMessage's to only come from CentralServers.\n")); - } - else if (message.isType("CntrlSrvDropDupeConns")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - sendToAllClusters(msg, dynamic_cast(&source)); - } - else if (message.isType("AdjustAccountFeatureIdRequest")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - AdjustAccountFeatureIdRequest const msg(ri); - - if (m_sessionApiClient) - { - // on a session authenticated cluster, this request should have been serviced by the ConnectionServer - } - else - { - // for testing purpose when not using session authentication, store - // the account feature Ids locally in memory, which will get cleared - // (obviously) when the LoginServer is restarted - std::map > * nonSessionTestingAccountFeatureIds = nullptr; - if (msg.getGameCode() == PlatformGameCode::SWG) - nonSessionTestingAccountFeatureIds = &s_nonSessionTestingAccountSwgFeatureIds; - else if (msg.getGameCode() == PlatformGameCode::SWGTCG) - nonSessionTestingAccountFeatureIds = &s_nonSessionTestingAccountSwgTcgFeatureIds; - - int currentFeatureIdCount = 0; - int updatedFeatureIdCount = 0; - if (nonSessionTestingAccountFeatureIds) - { - std::map & accountFeatureIds = (*nonSessionTestingAccountFeatureIds)[msg.getTargetStationId()]; - std::map::const_iterator accountFeatureId = accountFeatureIds.find(msg.getFeatureId()); - if (accountFeatureId != accountFeatureIds.end()) - currentFeatureIdCount = accountFeatureId->second; - - updatedFeatureIdCount = std::max(0, currentFeatureIdCount + msg.getAdjustment()); - if (updatedFeatureIdCount > 0) - { - accountFeatureIds[msg.getFeatureId()] = updatedFeatureIdCount; +#endif } else { - IGNORE_RETURN(accountFeatureIds.erase(msg.getFeatureId())); - if (accountFeatureIds.empty()) - IGNORE_RETURN(nonSessionTestingAccountFeatureIds->erase(msg.getTargetStationId())); - } - } + // in this mode, the cluster name has to match what we were expecting + cle = findClusterByConnection(connection); + if (!cle) + DEBUG_FATAL(true, ("PROGRAMMER BUG: Got a connection from %s:%hu, which we weren't expecting. Cluster name is \"%s\".\n", connection->getRemoteAddress().c_str(), connection->getRemotePort(), msg.getClusterName().c_str())); + else + if (msg.getClusterName() != cle->m_clusterName) + { + WARNING(true, ("Server %i is named \"%s\" in the database. The server at the specified address (%s:%hu) reports its name as \"%s\". It will not be allowed in the service. Either the name in the database or the name in Central's config file should be corrected.\n", cle->m_clusterId, cle->m_clusterName.c_str(), connection->getRemoteAddress().c_str(), connection->getRemotePort(), msg.getClusterName().c_str())); + disconnectCluster(*cle, true, false); + cle = nullptr; + } + } - // CS log SWG TCG account feature grant or SWG account feature grant for reward item trade in - if (nonSessionTestingAccountFeatureIds && !msg.getTargetPlayerDescription().empty() && msg.getTargetItem().isValid() && !msg.getTargetItemDescription().empty()) - { - if (msg.getGameCode() == PlatformGameCode::SWGTCG) - LOG("CustomerService", ("TcgRedemption: %s redeemed %s for SWGTCG account feature Id %lu (%d -> %d)", msg.getTargetPlayerDescription().c_str(), msg.getTargetItemDescription().c_str(), msg.getFeatureId(), currentFeatureIdCount, updatedFeatureIdCount)); - else if (msg.getGameCode() == PlatformGameCode::SWG) - LOG("CustomerService", ("VeteranRewards: %s traded in %s for SWG account feature Id %lu (%d -> %d)", msg.getTargetPlayerDescription().c_str(), msg.getTargetItemDescription().c_str(), msg.getFeatureId(), currentFeatureIdCount, updatedFeatureIdCount)); - } - - const CentralServerConnection * conn = dynamic_cast(&source); - if (conn) - { - AdjustAccountFeatureIdResponse const rsp(msg.getRequestingPlayer(), msg.getGameServer(), msg.getTargetPlayer(), msg.getTargetPlayerDescription(), msg.getTargetStationId(), msg.getTargetItem(), msg.getTargetItemDescription(), msg.getGameCode(), msg.getFeatureId(), currentFeatureIdCount, updatedFeatureIdCount, (nonSessionTestingAccountFeatureIds ? RESULT_SUCCESS : RESULT_CANCELLED), false); - sendToCluster(conn->getClusterId(), rsp); - } - } - } - else if (message.isType("AccountFeatureIdRequest")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - AccountFeatureIdRequest const msg(ri); - - if (m_sessionApiClient) - { - // on a session authenticated cluster, this request should have been serviced by the ConnectionServer - } - else - { - // for testing purpose when not using session authentication, store - // the account feature Ids locally in memory, which will get cleared - // (obviously) when the LoginServer is restarted - std::map > * nonSessionTestingAccountFeatureIds = nullptr; - if (msg.getGameCode() == PlatformGameCode::SWG) - nonSessionTestingAccountFeatureIds = &s_nonSessionTestingAccountSwgFeatureIds; - else if (msg.getGameCode() == PlatformGameCode::SWGTCG) - nonSessionTestingAccountFeatureIds = &s_nonSessionTestingAccountSwgTcgFeatureIds; - - static std::map const empty; - std::map const * accountFeatureIds = ∅ - - if (nonSessionTestingAccountFeatureIds) - { - std::map >::const_iterator iterFind = nonSessionTestingAccountFeatureIds->find(msg.getTargetStationId()); - if (iterFind != nonSessionTestingAccountFeatureIds->end()) - accountFeatureIds = &(iterFind->second); - } - - const CentralServerConnection * conn = dynamic_cast(&source); - if (conn) - { - static std::map const empty; - AccountFeatureIdResponse const rsp(msg.getRequester(), msg.getGameServer(), msg.getTarget(), msg.getTargetStationId(), msg.getGameCode(), msg.getRequestReason(), RESULT_SUCCESS, false, *accountFeatureIds, empty); - sendToCluster(conn->getClusterId(), rsp); - } - } - } - else if (message.isType("FeatureIdTransactionRequest")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - FeatureIdTransactionRequest const fitr(ri); - - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - DatabaseConnection::getInstance().featureIdTransactionRequest(conn->getClusterId(), fitr.getStationId(), fitr.getPlayer(), fitr.getGameServer()); - } - else if (message.isType("FeatureIdTransactionSyncUpdate")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - FeatureIdTransactionSyncUpdate const fitsu(ri); - - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - DatabaseConnection::getInstance().featureIdTransactionSyncUpdate(conn->getClusterId(), fitsu.getStationId(), fitsu.getPlayer(), fitsu.getItemId(), fitsu.getAdjustment()); - } - else if (message.isType("TransferRequestMoveValidation")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - const TransferRequestMoveValidation request(ri); - - TransferReplyMoveValidation::TransferReplyMoveValidationResult result = TransferReplyMoveValidation::TRMVR_can_create_regular_character; - - ClusterListEntry * cle = findClusterByName(request.getDestinationGalaxy()); - if (!cle) - { - result = TransferReplyMoveValidation::TRMVR_destination_galaxy_invalid; - } - else if (!cle->m_centralServerConnection) - { - result = TransferReplyMoveValidation::TRMVR_destination_galaxy_not_connected; - } - else if (!cle->m_readyForPlayers) - { - result = TransferReplyMoveValidation::TRMVR_destination_galaxy_in_loading; - } - - if (result == TransferReplyMoveValidation::TRMVR_can_create_regular_character) - { - // check with DB to see if account is allowed to create character on the destination galaxy - LOG("CustomerService", ("CharacterTransfer: Received TransferRequestMoveValidation : %s (character template id %lu) on %s to %s on %s. Forwarding request to Login Database.", request.getSourceCharacter().c_str(), request.getSourceCharacterTemplateId(), request.getSourceGalaxy().c_str(), request.getDestinationCharacter().c_str(), request.getDestinationGalaxy().c_str())); - DatabaseConnection::getInstance().getAccountValidationData(request, cle->m_centralServerConnection->getClusterId()); - } - else - { - // send failure back to originating server - TransferReplyMoveValidation reply(request.getTransferRequestSource(), request.getTrack(), request.getSourceStationId(), request.getDestinationStationId(), request.getSourceGalaxy(), request.getDestinationGalaxy(), request.getSourceCharacter(), request.getSourceCharacterId(), request.getSourceCharacterTemplateId(), request.getDestinationCharacter(), request.getCustomerLocalizedLanguage(), result); - const CentralServerConnection * conn = dynamic_cast(&source); - if (conn) - { - ClusterListEntry * sourceEntry = findClusterById(conn->getClusterId()); - if (sourceEntry && sourceEntry->m_centralServerConnection) + if (cle) { - sourceEntry->m_centralServerConnection->send(reply, true); - } - } - } - } - else if (message.isType("TransferReplyNameValidation")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const replyNameValidation(ri); + cle->m_timeZone = msg.getTimeZone(); + cle->m_centralServerConnection = connection; + cle->m_connected = true; + pushAllKeys(connection); - const CentralServerConnection * conn = dynamic_cast(&source); - if (conn) - { - ClusterListEntry * cle = findClusterByName(replyNameValidation.getValue().second.getSourceGalaxy()); - if (cle && cle->m_centralServerConnection) - { - LOG("CustomerService", ("CharacterTransfer: Received TransferReplyNameValidation from destination galaxy CentralServer, forwarding to source galaxy CentralServer : %s", replyNameValidation.getValue().second.toString().c_str())); - cle->m_centralServerConnection->send(replyNameValidation, true); - } - } - } - else if (message.isType("TransferLoginCharacterToDestinationServer")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const login(ri); - - const CentralServerConnection * conn = dynamic_cast(&source); - if (conn) - { - ClusterListEntry * cle = findClusterByName(login.getValue().getDestinationGalaxy()); - if (cle && cle->m_centralServerConnection) - { - LOG("CustomerService", ("CharacterTransfer: Received TransferLoginCharacterToDestinationServer from source galaxy CentralServer, forwarding to destination galaxy CentralServer : %s", login.getValue().toString().c_str())); - cle->m_centralServerConnection->send(login, true); - } - } - } - else if (message.isType("UpdateLoginConnectionServerStatus")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - UpdateLoginConnectionServerStatus msg(ri); - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - { - ClusterListEntry *cle = findClusterByConnection(conn); - if (cle) - { - std::vector::iterator i = cle->m_connectionServers.begin(); - for (; i != cle->m_connectionServers.end(); ++i) - { - if (i->id == msg.getId()) + if (cle->m_clusterId == 0) { - i->clientServicePortPublic = msg.getPublicPort(); - i->clientServicePortPrivate = msg.getPrivatePort(); - i->numClients = msg.getPlayerCount(); + DEBUG_FATAL(!ConfigLoginServer::getDevelopmentMode(), ("Programmer bug: cle->m_clusterId was 0 in non-development mode. The code before this line should have prevented this.\n")); + DEBUG_REPORT_LOG(true, ("Cluster was not on the list. Adding it to the database.\n")); + DatabaseConnection::getInstance().registerNewCluster(msg.getClusterName(), connection->getRemoteAddress()); + } + else + cle->m_centralServerConnection->setClusterId(cle->m_clusterId); + + m_clusterStatusChanged = true; + + // tell the cluster its cluster id + if (cle->m_clusterId > 0) + { + GenericValueTypeMessage const msgClusterId("ClusterId", cle->m_clusterId); + cle->m_centralServerConnection->send(msgClusterId, true); + } + + // tell the cluster about its locked and secret state + GenericValueTypeMessage > const msgState("UpdateClusterLockedAndSecretState", std::make_pair(cle->m_locked, cle->m_secret)); + cle->m_centralServerConnection->send(msgState, true); + } + } + break; + } + case constcrc("LoginConnectionServerAddress") : + { + const CentralServerConnection * cs = safe_cast(&source); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + + LoginConnectionServerAddress m(ri); //lint !e1774 !e826onServerEntry entry; + ConnectionServerEntry entry; + entry.clientServiceAddress = Address(Address(m.getClientServiceAddress(), 0).getSockAddr4()).getHostAddress(); + entry.clientServicePortPrivate = m.getClientServicePortPrivate(); + entry.clientServicePortPublic = m.getClientServicePortPublic(); + entry.id = m.getId(); + entry.numClients = m.getNumClients(); + entry.pingPort = m.getPingPort(); + + DEBUG_REPORT_LOG(true, ("ConnectionServer Reconnect - address from connection server (%s), address after conversion (%s)\n", m.getClientServiceAddress().c_str(), entry.clientServiceAddress.c_str())); + + ClusterListEntry *cle = findClusterByConnection(cs); + if (cle) + { + WARNING_STRICT_FATAL(!cle->m_centralServerConnection, ("Got reconnect for connection server with no central! Cluster %s\n", cs->getClusterName().c_str())); + std::vector::iterator i = std::find(cle->m_connectionServers.begin(), cle->m_connectionServers.end(), entry); + if (i == cle->m_connectionServers.end()) + { + cle->m_connectionServers.push_back(entry); + m_clusterStatusChanged = true; + } + else + { + *i = entry; + } + + std::sort(cle->m_connectionServers.begin(), cle->m_connectionServers.end(), ConnectionServerEntryLessThan()); + } + else + WARNING_STRICT_FATAL(true, ("Programmer bug: Got LoginConnectionServerAddress from a cluster that wasn't on the list. Probably indicates we aren't tracking connections properly.\n")); + break; + } + case constcrc("PreloadFinishedMessage") : + { + const CentralServerConnection * cs = safe_cast(&source); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + PreloadFinishedMessage msg(ri); + + ClusterListEntry *cle = findClusterByConnection(cs); + if (cle) + { + if (msg.getFinished()) + { + REPORT_LOG(true, ("Cluster %s is ready for players.\n", cle->m_clusterName.c_str())); + if (!cle->m_readyForPlayers) + { + cle->m_readyForPlayers = true; + m_clusterStatusChanged = true; + } + } + else + { + REPORT_LOG(true, ("Cluster %s is not ready for players.\n", cle->m_clusterName.c_str())); + if (cle->m_readyForPlayers) + { + cle->m_readyForPlayers = false; + m_clusterStatusChanged = true; + PurgeManager::onClusterNoLongerReady(cle->m_clusterId); + } + } + } + else + WARNING_STRICT_FATAL(true, ("Programmer bug: Got PreloadFinishedMessage from a cluster that wasn't on the list. Probably indicates we aren't tracking connections properly.\n")); + + break; + } + case constcrc("ConnectionServerDown") : + { + const CentralServerConnection * centralConnection = safe_cast(&source); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ConnectionServerDown c(ri); //lint !e1774 !e826 + ClusterListEntry *cle = findClusterByConnection(centralConnection); + if (cle) + { + DEBUG_REPORT_LOG(true, ("Lost a connection server %d for %s.\n", c.getId(), cle->m_clusterName.c_str())); + + std::vector::iterator iter = cle->m_connectionServers.begin(); + bool found = false; + for (; iter != cle->m_connectionServers.end(); ++iter) + { + if (iter->id == c.getId()) + { + IGNORE_RETURN(cle->m_connectionServers.erase(iter)); + std::sort(cle->m_connectionServers.begin(), cle->m_connectionServers.end(), ConnectionServerEntryLessThan()); + found = true; break; } } - std::sort(cle->m_connectionServers.begin(), cle->m_connectionServers.end(), ConnectionServerEntryLessThan()); + DEBUG_REPORT_LOG(!found, ("Tried to remove a connection server that wasn't in our list.\n")); + m_clusterStatusChanged = true; } + else + WARNING_STRICT_FATAL(true, ("Programmer bug: Got ConnectionServerDown from a cluster that wasn't on the list. Probably indicates we aren't tracking connections properly.\n")); + + break; } - } - else if (message.isType("UpdatePlayerCountMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - UpdatePlayerCountMessage msg(ri); - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) + case constcrc("ConnectionClosed") : { - ClusterListEntry *cle = findClusterByConnection(conn); - if (cle) + const CentralServerConnection *c = dynamic_cast(&source); + if (c) { - const int tutorialPlayerCount = (msg.getEmptySceneCount() + msg.getTutorialSceneCount() + msg.getFalconSceneCount()); - - // We only want to update the clients if some "threshold" has been crossed - if ((cle->m_notRecommendedCentral != msg.getLoadedRecently()) - || hasCrossedThreshold(cle->m_onlineTutorialLimit, cle->m_numTutorialPlayers, tutorialPlayerCount) - || hasCrossedThreshold(cle->m_onlineFreeTrialLimit, cle->m_numFreeTrialPlayers, msg.getFreeTrialCount()) - || hasCrossedThreshold(cle->m_onlinePlayerLimit, cle->m_numPlayers, msg.getCount())) + ClusterListEntry *cle = findClusterByConnection(c); + if (cle) { - m_clusterStatusChanged = true; + DEBUG_REPORT_LOG(true, ("Cluster connection %s closed.\n", c->getClusterName().c_str())); + disconnectCluster(*cle, false, true); } - - cle->m_numPlayers = msg.getCount(); - cle->m_numFreeTrialPlayers = msg.getFreeTrialCount(); - cle->m_notRecommendedCentral = msg.getLoadedRecently(); - cle->m_numTutorialPlayers = tutorialPlayerCount; + else + WARNING_STRICT_FATAL(true, ("Programmer bug: Cluster disconnected but it wasn't on the list. Probably indicates we aren't tracking connections properly.\n")); } + break; } - } - else if (message.isType("RenameCharacterMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - RenameCharacterMessage msg(ri); - - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - DatabaseConnection::getInstance().renameCharacter(conn->getClusterId(), msg.getCharacterId(), msg.getNewName(), nullptr); - else - WARNING_STRICT_FATAL(true, ("Got RenameCharacterMessage from something other than CentralServerConnection.\n")); - } - else if (message.isType("LoginCreateCharacterMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - LoginCreateCharacterMessage msg(ri); - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - DatabaseConnection::getInstance().createCharacter(conn->getClusterId(), msg.getStationId(), msg.getCharacterName(), msg.getCharacterObjectId(), msg.getTemplateId(), msg.getJedi()); - } - else if (message.isType("LoginRestoreCharacterMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - LoginRestoreCharacterMessage msg(ri); - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - DatabaseConnection::getInstance().restoreCharacter(conn->getClusterId(), msg.getWhoRequested(), msg.getAccount(), msg.getCharacterName(), msg.getCharacterId(), msg.getTemplateId(), msg.getJedi()); - } - else if (message.isType("LoginUpgradeAccountMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - LoginUpgradeAccountMessage *msg = new LoginUpgradeAccountMessage(ri); - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - DatabaseConnection::getInstance().upgradeAccount(msg, conn->getClusterId()); - } - else if (message.isType("ClaimRewardsMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ClaimRewardsMessage const * msg = new ClaimRewardsMessage(ri); - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) + case constcrc("ValidateAccountMessage") : { - // current restriction is that once per account event or item cannot require a "consuming" account feature id - uint32 const requiredAccountFeatureId = msg->getAccountFeatureId(); - bool const consumeAccountFeatureId = msg->getConsumeAccountFeatureId(); - if ((msg->getConsumeEvent() || msg->getConsumeItem()) && (requiredAccountFeatureId > 0) && consumeAccountFeatureId) + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ValidateAccountMessage msg(ri); + + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + DatabaseConnection::getInstance().getAccountValidationData(msg.getStationId(), conn->getClusterId(), msg.getTrack(), msg.getSubscriptionBits()); + else + WARNING_STRICT_FATAL(true, ("Expect ValidateAccountMessage's to only come from CentralServers.\n")); + break; + } + case constcrc("CntrlSrvDropDupeConns") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + sendToAllClusters(msg, dynamic_cast(&source)); + break; + } + case constcrc("AdjustAccountFeatureIdRequest") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + AdjustAccountFeatureIdRequest const msg(ri); + + if (m_sessionApiClient) { - ClaimRewardsReplyMessage const rsp(msg->getGameServer(), msg->getStationId(), msg->getPlayer(), msg->getRewardEvent(), msg->getRewardItem(), requiredAccountFeatureId, consumeAccountFeatureId, 0, 0, false); - sendToCluster(conn->getClusterId(), rsp); - delete msg; + // on a session authenticated cluster, this request should have been serviced by the ConnectionServer } - else if (requiredAccountFeatureId > 0) + else { - if (m_sessionApiClient) + // for testing purpose when not using session authentication, store + // the account feature Ids locally in memory, which will get cleared + // (obviously) when the LoginServer is restarted + std::map > * nonSessionTestingAccountFeatureIds = nullptr; + if (msg.getGameCode() == PlatformGameCode::SWG) + nonSessionTestingAccountFeatureIds = &s_nonSessionTestingAccountSwgFeatureIds; + else if (msg.getGameCode() == PlatformGameCode::SWGTCG) + nonSessionTestingAccountFeatureIds = &s_nonSessionTestingAccountSwgTcgFeatureIds; + + int currentFeatureIdCount = 0; + int updatedFeatureIdCount = 0; + if (nonSessionTestingAccountFeatureIds) { - if (consumeAccountFeatureId) + std::map & accountFeatureIds = (*nonSessionTestingAccountFeatureIds)[msg.getTargetStationId()]; + std::map::const_iterator accountFeatureId = accountFeatureIds.find(msg.getFeatureId()); + if (accountFeatureId != accountFeatureIds.end()) + currentFeatureIdCount = accountFeatureId->second; + + updatedFeatureIdCount = std::max(0, currentFeatureIdCount + msg.getAdjustment()); + if (updatedFeatureIdCount > 0) { - // request session/Platform to update the account feature id - // SessionApiClient will own (and delete) msg - m_sessionApiClient->handleClaimRewardsMessage(conn->getClusterId(), msg); + accountFeatureIds[msg.getFeatureId()] = updatedFeatureIdCount; } else { - LoginAPI::Feature oldFeature; - oldFeature.SetID(requiredAccountFeatureId); - oldFeature.SetData(msg->getAccountFeatureIdOldValue()); + IGNORE_RETURN(accountFeatureIds.erase(msg.getFeatureId())); + if (accountFeatureIds.empty()) + IGNORE_RETURN(nonSessionTestingAccountFeatureIds->erase(msg.getTargetStationId())); + } + } - LoginAPI::Feature newFeature; - newFeature.SetID(requiredAccountFeatureId); - newFeature.SetData(msg->getAccountFeatureIdNewValue()); + // CS log SWG TCG account feature grant or SWG account feature grant for reward item trade in + if (nonSessionTestingAccountFeatureIds && !msg.getTargetPlayerDescription().empty() && msg.getTargetItem().isValid() && !msg.getTargetItemDescription().empty()) + { + if (msg.getGameCode() == PlatformGameCode::SWGTCG) + LOG("CustomerService", ("TcgRedemption: %s redeemed %s for SWGTCG account feature Id %lu (%d -> %d)", msg.getTargetPlayerDescription().c_str(), msg.getTargetItemDescription().c_str(), msg.getFeatureId(), currentFeatureIdCount, updatedFeatureIdCount)); + else if (msg.getGameCode() == PlatformGameCode::SWG) + LOG("CustomerService", ("VeteranRewards: %s traded in %s for SWG account feature Id %lu (%d -> %d)", msg.getTargetPlayerDescription().c_str(), msg.getTargetItemDescription().c_str(), msg.getFeatureId(), currentFeatureIdCount, updatedFeatureIdCount)); + } + + const CentralServerConnection * conn = dynamic_cast(&source); + if (conn) + { + AdjustAccountFeatureIdResponse const rsp(msg.getRequestingPlayer(), msg.getGameServer(), msg.getTargetPlayer(), msg.getTargetPlayerDescription(), msg.getTargetStationId(), msg.getTargetItem(), msg.getTargetItemDescription(), msg.getGameCode(), msg.getFeatureId(), currentFeatureIdCount, updatedFeatureIdCount, (nonSessionTestingAccountFeatureIds ? RESULT_SUCCESS : RESULT_CANCELLED), false); + sendToCluster(conn->getClusterId(), rsp); + } + } + break; + } + case constcrc("AccountFeatureIdRequest") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + AccountFeatureIdRequest const msg(ri); + + if (m_sessionApiClient) + { + // on a session authenticated cluster, this request should have been serviced by the ConnectionServer + } + else + { + // for testing purpose when not using session authentication, store + // the account feature Ids locally in memory, which will get cleared + // (obviously) when the LoginServer is restarted + std::map > * nonSessionTestingAccountFeatureIds = nullptr; + if (msg.getGameCode() == PlatformGameCode::SWG) + nonSessionTestingAccountFeatureIds = &s_nonSessionTestingAccountSwgFeatureIds; + else if (msg.getGameCode() == PlatformGameCode::SWGTCG) + nonSessionTestingAccountFeatureIds = &s_nonSessionTestingAccountSwgTcgFeatureIds; + + static std::map const empty; + std::map const * accountFeatureIds = ∅ + + if (nonSessionTestingAccountFeatureIds) + { + std::map >::const_iterator iterFind = nonSessionTestingAccountFeatureIds->find(msg.getTargetStationId()); + if (iterFind != nonSessionTestingAccountFeatureIds->end()) + accountFeatureIds = &(iterFind->second); + } + + const CentralServerConnection * conn = dynamic_cast(&source); + if (conn) + { + static std::map const empty; + AccountFeatureIdResponse const rsp(msg.getRequester(), msg.getGameServer(), msg.getTarget(), msg.getTargetStationId(), msg.getGameCode(), msg.getRequestReason(), RESULT_SUCCESS, false, *accountFeatureIds, empty); + sendToCluster(conn->getClusterId(), rsp); + } + } + break; + } + case constcrc("FeatureIdTransactionRequest") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + FeatureIdTransactionRequest const fitr(ri); + + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + DatabaseConnection::getInstance().featureIdTransactionRequest(conn->getClusterId(), fitr.getStationId(), fitr.getPlayer(), fitr.getGameServer()); + break; + } + case constcrc("FeatureIdTransactionSyncUpdate") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + FeatureIdTransactionSyncUpdate const fitsu(ri); + + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + DatabaseConnection::getInstance().featureIdTransactionSyncUpdate(conn->getClusterId(), fitsu.getStationId(), fitsu.getPlayer(), fitsu.getItemId(), fitsu.getAdjustment()); + break; + } + case constcrc("TransferRequestMoveValidation") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + const TransferRequestMoveValidation request(ri); + + TransferReplyMoveValidation::TransferReplyMoveValidationResult result = TransferReplyMoveValidation::TRMVR_can_create_regular_character; + + ClusterListEntry * cle = findClusterByName(request.getDestinationGalaxy()); + if (!cle) + { + result = TransferReplyMoveValidation::TRMVR_destination_galaxy_invalid; + } + else if (!cle->m_centralServerConnection) + { + result = TransferReplyMoveValidation::TRMVR_destination_galaxy_not_connected; + } + else if (!cle->m_readyForPlayers) + { + result = TransferReplyMoveValidation::TRMVR_destination_galaxy_in_loading; + } + + if (result == TransferReplyMoveValidation::TRMVR_can_create_regular_character) + { + // check with DB to see if account is allowed to create character on the destination galaxy + LOG("CustomerService", ("CharacterTransfer: Received TransferRequestMoveValidation : %s (character template id %lu) on %s to %s on %s. Forwarding request to Login Database.", request.getSourceCharacter().c_str(), request.getSourceCharacterTemplateId(), request.getSourceGalaxy().c_str(), request.getDestinationCharacter().c_str(), request.getDestinationGalaxy().c_str())); + DatabaseConnection::getInstance().getAccountValidationData(request, cle->m_centralServerConnection->getClusterId()); + } + else + { + // send failure back to originating server + TransferReplyMoveValidation reply(request.getTransferRequestSource(), request.getTrack(), request.getSourceStationId(), request.getDestinationStationId(), request.getSourceGalaxy(), request.getDestinationGalaxy(), request.getSourceCharacter(), request.getSourceCharacterId(), request.getSourceCharacterTemplateId(), request.getDestinationCharacter(), request.getCustomerLocalizedLanguage(), result); + const CentralServerConnection * conn = dynamic_cast(&source); + if (conn) + { + ClusterListEntry * sourceEntry = findClusterById(conn->getClusterId()); + if (sourceEntry && sourceEntry->m_centralServerConnection) + { + sourceEntry->m_centralServerConnection->send(reply, true); + } + } + } + break; + } + case constcrc("TransferReplyNameValidation") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const replyNameValidation(ri); + + const CentralServerConnection * conn = dynamic_cast(&source); + if (conn) + { + ClusterListEntry * cle = findClusterByName(replyNameValidation.getValue().second.getSourceGalaxy()); + if (cle && cle->m_centralServerConnection) + { + LOG("CustomerService", ("CharacterTransfer: Received TransferReplyNameValidation from destination galaxy CentralServer, forwarding to source galaxy CentralServer : %s", replyNameValidation.getValue().second.toString().c_str())); + cle->m_centralServerConnection->send(replyNameValidation, true); + } + } + break; + } + case constcrc("TransferLoginCharacterToDestinationServer") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const login(ri); + + const CentralServerConnection * conn = dynamic_cast(&source); + if (conn) + { + ClusterListEntry * cle = findClusterByName(login.getValue().getDestinationGalaxy()); + if (cle && cle->m_centralServerConnection) + { + LOG("CustomerService", ("CharacterTransfer: Received TransferLoginCharacterToDestinationServer from source galaxy CentralServer, forwarding to destination galaxy CentralServer : %s", login.getValue().toString().c_str())); + cle->m_centralServerConnection->send(login, true); + } + } + break; + } + case constcrc("UpdateLoginConnectionServerStatus") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + UpdateLoginConnectionServerStatus msg(ri); + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + { + ClusterListEntry *cle = findClusterByConnection(conn); + if (cle) + { + std::vector::iterator i = cle->m_connectionServers.begin(); + for (; i != cle->m_connectionServers.end(); ++i) + { + if (i->id == msg.getId()) + { + i->clientServicePortPublic = msg.getPublicPort(); + i->clientServicePortPrivate = msg.getPrivatePort(); + i->numClients = msg.getPlayerCount(); + break; + } + } + std::sort(cle->m_connectionServers.begin(), cle->m_connectionServers.end(), ConnectionServerEntryLessThan()); + } + } + break; + } + case constcrc("UpdatePlayerCountMessage") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + UpdatePlayerCountMessage msg(ri); + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + { + ClusterListEntry *cle = findClusterByConnection(conn); + if (cle) + { + const int tutorialPlayerCount = (msg.getEmptySceneCount() + msg.getTutorialSceneCount() + msg.getFalconSceneCount()); + + // We only want to update the clients if some "threshold" has been crossed + if ((cle->m_notRecommendedCentral != msg.getLoadedRecently()) + || hasCrossedThreshold(cle->m_onlineTutorialLimit, cle->m_numTutorialPlayers, tutorialPlayerCount) + || hasCrossedThreshold(cle->m_onlineFreeTrialLimit, cle->m_numFreeTrialPlayers, msg.getFreeTrialCount()) + || hasCrossedThreshold(cle->m_onlinePlayerLimit, cle->m_numPlayers, msg.getCount())) + { + m_clusterStatusChanged = true; + } + + cle->m_numPlayers = msg.getCount(); + cle->m_numFreeTrialPlayers = msg.getFreeTrialCount(); + cle->m_notRecommendedCentral = msg.getLoadedRecently(); + cle->m_numTutorialPlayers = tutorialPlayerCount; + } + } + break; + } + case constcrc("RenameCharacterMessage") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + RenameCharacterMessage msg(ri); + + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + DatabaseConnection::getInstance().renameCharacter(conn->getClusterId(), msg.getCharacterId(), msg.getNewName(), nullptr); + else + WARNING_STRICT_FATAL(true, ("Got RenameCharacterMessage from something other than CentralServerConnection.\n")); + + break; + } + case constcrc("LoginCreateCharacterMessage") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + LoginCreateCharacterMessage msg(ri); + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + DatabaseConnection::getInstance().createCharacter(conn->getClusterId(), msg.getStationId(), msg.getCharacterName(), msg.getCharacterObjectId(), msg.getTemplateId(), msg.getJedi()); + + break; + } + case constcrc("LoginRestoreCharacterMessage") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + LoginRestoreCharacterMessage msg(ri); + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + DatabaseConnection::getInstance().restoreCharacter(conn->getClusterId(), msg.getWhoRequested(), msg.getAccount(), msg.getCharacterName(), msg.getCharacterId(), msg.getTemplateId(), msg.getJedi()); + + break; + } + case constcrc("LoginUpgradeAccountMessage") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + LoginUpgradeAccountMessage *msg = new LoginUpgradeAccountMessage(ri); + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + DatabaseConnection::getInstance().upgradeAccount(msg, conn->getClusterId()); + + break; + } + case constcrc("ClaimRewardsMessage") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ClaimRewardsMessage const * msg = new ClaimRewardsMessage(ri); + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + { + // current restriction is that once per account event or item cannot require a "consuming" account feature id + uint32 const requiredAccountFeatureId = msg->getAccountFeatureId(); + bool const consumeAccountFeatureId = msg->getConsumeAccountFeatureId(); + if ((msg->getConsumeEvent() || msg->getConsumeItem()) && (requiredAccountFeatureId > 0) && consumeAccountFeatureId) + { + ClaimRewardsReplyMessage const rsp(msg->getGameServer(), msg->getStationId(), msg->getPlayer(), msg->getRewardEvent(), msg->getRewardItem(), requiredAccountFeatureId, consumeAccountFeatureId, 0, 0, false); + sendToCluster(conn->getClusterId(), rsp); + delete msg; + } + else if (requiredAccountFeatureId > 0) + { + if (m_sessionApiClient) + { + if (consumeAccountFeatureId) + { + // request session/Platform to update the account feature id + // SessionApiClient will own (and delete) msg + m_sessionApiClient->handleClaimRewardsMessage(conn->getClusterId(), msg); + } + else + { + LoginAPI::Feature oldFeature; + oldFeature.SetID(requiredAccountFeatureId); + oldFeature.SetData(msg->getAccountFeatureIdOldValue()); + + LoginAPI::Feature newFeature; + newFeature.SetID(requiredAccountFeatureId); + newFeature.SetData(msg->getAccountFeatureIdNewValue()); + + DatabaseConnection::getInstance().claimRewards(conn->getClusterId(), msg->getGameServer(), msg->getStationId(), msg->getPlayer(), msg->getRewardEvent(), msg->getConsumeEvent(), msg->getRewardItem(), msg->getConsumeItem(), requiredAccountFeatureId, false, oldFeature.GetConsumeCount(), newFeature.GetConsumeCount()); + delete msg; + } + } + else + { + // for testing purpose when not using session authentication, store + // the account feature Ids locally in memory, which will get cleared + // (obviously) when the LoginServer is restarted + std::map & accountFeatureIds = s_nonSessionTestingAccountSwgFeatureIds[msg->getStationId()]; + std::map::const_iterator accountFeatureId = accountFeatureIds.find(requiredAccountFeatureId); + int currentFeatureIdCount = 0; + if (accountFeatureId != accountFeatureIds.end()) + currentFeatureIdCount = accountFeatureId->second; + + if (currentFeatureIdCount <= 0) + { + // fail because account doesn't have required feature id + IGNORE_RETURN(accountFeatureIds.erase(requiredAccountFeatureId)); + if (accountFeatureIds.empty()) + IGNORE_RETURN(s_nonSessionTestingAccountSwgFeatureIds.erase(msg->getStationId())); + + ClaimRewardsReplyMessage rsp(msg->getGameServer(), msg->getStationId(), msg->getPlayer(), msg->getRewardEvent(), msg->getRewardItem(), requiredAccountFeatureId, consumeAccountFeatureId, 0, 0, false); + sendToCluster(conn->getClusterId(), rsp); + } + else + { + // account has required feature id so claim is success, so update feature id for claim + int const updatedFeatureIdCount = (consumeAccountFeatureId ? std::max(0, currentFeatureIdCount - 1) : currentFeatureIdCount); + + if (consumeAccountFeatureId) + { + if (updatedFeatureIdCount > 0) + { + accountFeatureIds[requiredAccountFeatureId] = updatedFeatureIdCount; + } + else + { + IGNORE_RETURN(accountFeatureIds.erase(requiredAccountFeatureId)); + if (accountFeatureIds.empty()) + IGNORE_RETURN(s_nonSessionTestingAccountSwgFeatureIds.erase(msg->getStationId())); + } + } + + // if feature id updated successfully, record transaction + DatabaseConnection::getInstance().claimRewards(conn->getClusterId(), msg->getGameServer(), msg->getStationId(), msg->getPlayer(), msg->getRewardEvent(), msg->getConsumeEvent(), msg->getRewardItem(), msg->getConsumeItem(), requiredAccountFeatureId, consumeAccountFeatureId, currentFeatureIdCount, updatedFeatureIdCount); + } - DatabaseConnection::getInstance().claimRewards(conn->getClusterId(), msg->getGameServer(), msg->getStationId(), msg->getPlayer(), msg->getRewardEvent(), msg->getConsumeEvent(), msg->getRewardItem(), msg->getConsumeItem(), requiredAccountFeatureId, false, oldFeature.GetConsumeCount(), newFeature.GetConsumeCount()); delete msg; } } else { - // for testing purpose when not using session authentication, store - // the account feature Ids locally in memory, which will get cleared - // (obviously) when the LoginServer is restarted - std::map & accountFeatureIds = s_nonSessionTestingAccountSwgFeatureIds[msg->getStationId()]; - std::map::const_iterator accountFeatureId = accountFeatureIds.find(requiredAccountFeatureId); - int currentFeatureIdCount = 0; - if (accountFeatureId != accountFeatureIds.end()) - currentFeatureIdCount = accountFeatureId->second; - - if (currentFeatureIdCount <= 0) - { - // fail because account doesn't have required feature id - IGNORE_RETURN(accountFeatureIds.erase(requiredAccountFeatureId)); - if (accountFeatureIds.empty()) - IGNORE_RETURN(s_nonSessionTestingAccountSwgFeatureIds.erase(msg->getStationId())); - - ClaimRewardsReplyMessage rsp(msg->getGameServer(), msg->getStationId(), msg->getPlayer(), msg->getRewardEvent(), msg->getRewardItem(), requiredAccountFeatureId, consumeAccountFeatureId, 0, 0, false); - sendToCluster(conn->getClusterId(), rsp); - } - else - { - // account has required feature id so claim is success, so update feature id for claim - int const updatedFeatureIdCount = (consumeAccountFeatureId ? std::max(0, currentFeatureIdCount - 1) : currentFeatureIdCount); - - if (consumeAccountFeatureId) - { - if (updatedFeatureIdCount > 0) - { - accountFeatureIds[requiredAccountFeatureId] = updatedFeatureIdCount; - } - else - { - IGNORE_RETURN(accountFeatureIds.erase(requiredAccountFeatureId)); - if (accountFeatureIds.empty()) - IGNORE_RETURN(s_nonSessionTestingAccountSwgFeatureIds.erase(msg->getStationId())); - } - } - - // if feature id updated successfully, record transaction - DatabaseConnection::getInstance().claimRewards(conn->getClusterId(), msg->getGameServer(), msg->getStationId(), msg->getPlayer(), msg->getRewardEvent(), msg->getConsumeEvent(), msg->getRewardItem(), msg->getConsumeItem(), requiredAccountFeatureId, consumeAccountFeatureId, currentFeatureIdCount, updatedFeatureIdCount); - } - + DatabaseConnection::getInstance().claimRewards(conn->getClusterId(), msg->getGameServer(), msg->getStationId(), msg->getPlayer(), msg->getRewardEvent(), msg->getConsumeEvent(), msg->getRewardItem(), msg->getConsumeItem(), 0, false, 0, 0); delete msg; } } else { - DatabaseConnection::getInstance().claimRewards(conn->getClusterId(), msg->getGameServer(), msg->getStationId(), msg->getPlayer(), msg->getRewardEvent(), msg->getConsumeEvent(), msg->getRewardItem(), msg->getConsumeItem(), 0, false, 0, 0); delete msg; } + + break; } - else + case constcrc("PurgeCompleteMessage") : { - delete msg; + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage msg(ri); + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + PurgeManager::handlePurgeCompleteOnCluster(msg.getValue(), conn->getClusterId()); + else + WARNING_STRICT_FATAL(true, ("Programmer bug: got PurgeCompleteMessage from something that couldn't be cast to a CentralServerConnection")); + + break; } - } - else if (message.isType("PurgeCompleteMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage msg(ri); - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - PurgeManager::handlePurgeCompleteOnCluster(msg.getValue(), conn->getClusterId()); - else - WARNING_STRICT_FATAL(true, ("Programmer bug: got PurgeCompleteMessage from something that couldn't be cast to a CentralServerConnection")); - } - else if (message.isType("OccupyUnlockedSlotReq")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, uint32> > const occupyUnlockedSlotReq(ri); + case constcrc("OccupyUnlockedSlotReq") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, uint32> > const occupyUnlockedSlotReq(ri); - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - DatabaseConnection::getInstance().occupyUnlockedSlot(conn->getClusterId(), static_cast(occupyUnlockedSlotReq.getValue().first.first), occupyUnlockedSlotReq.getValue().first.second, occupyUnlockedSlotReq.getValue().second); - } - else if (message.isType("VacateUnlockedSlotReq")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, uint32> > const vacateUnlockedSlotReq(ri); + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + DatabaseConnection::getInstance().occupyUnlockedSlot(conn->getClusterId(), static_cast(occupyUnlockedSlotReq.getValue().first.first), occupyUnlockedSlotReq.getValue().first.second, occupyUnlockedSlotReq.getValue().second); + + break; + } + case constcrc("VacateUnlockedSlotReq") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, uint32> > const vacateUnlockedSlotReq(ri); - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - DatabaseConnection::getInstance().vacateUnlockedSlot(conn->getClusterId(), static_cast(vacateUnlockedSlotReq.getValue().first.first), vacateUnlockedSlotReq.getValue().first.second, vacateUnlockedSlotReq.getValue().second); - } - else if (message.isType("SwapUnlockedSlotReq")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::pair > > const swapUnlockedSlotReq(ri); + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + DatabaseConnection::getInstance().vacateUnlockedSlot(conn->getClusterId(), static_cast(vacateUnlockedSlotReq.getValue().first.first), vacateUnlockedSlotReq.getValue().first.second, vacateUnlockedSlotReq.getValue().second); + + break; + } + case constcrc("SwapUnlockedSlotReq") : + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::pair > > const swapUnlockedSlotReq(ri); - const CentralServerConnection *conn = dynamic_cast(&source); - if (conn) - DatabaseConnection::getInstance().swapUnlockedSlot(conn->getClusterId(), static_cast(swapUnlockedSlotReq.getValue().first.first), swapUnlockedSlotReq.getValue().first.second, swapUnlockedSlotReq.getValue().second.second, swapUnlockedSlotReq.getValue().second.first); - } + const CentralServerConnection *conn = dynamic_cast(&source); + if (conn) + DatabaseConnection::getInstance().swapUnlockedSlot(conn->getClusterId(), static_cast(swapUnlockedSlotReq.getValue().first.first), swapUnlockedSlotReq.getValue().first.second, swapUnlockedSlotReq.getValue().second.second, swapUnlockedSlotReq.getValue().second.first); + + break; + } } // ----------------------------------------------------------------------