14 #include <gpcm/client.h>
16 typedef void (
GPCM::Client::*RequestActionFunc)(
const GameSpy::Parameter&);
18 static std::map<std::string, RequestActionFunc> mRequestActions =
47 bool isDisconnected =
false;
50 this->requestChallenge();
52 while(!isDisconnected)
54 std::vector<unsigned char> combined_buffer;
55 std::string last_seven_chars =
"";
59 std::vector<unsigned char> buffer(16384, 0);
61 int v = read(this->_socket, &(buffer[0]), 16384);
66 isDisconnected =
true;
73 this->UpdateLastRecievedTime();
83 combined_buffer.insert(combined_buffer.end(), buffer.begin(), buffer.end());
85 if(combined_buffer.size() > 7)
87 last_seven_chars.assign(combined_buffer.end() - 7, combined_buffer.end());
89 }
while (last_seven_chars !=
"\\final\\" && combined_buffer.size() < 32768);
91 std::vector<std::string> requests = GameSpy::RequestToRequests(Util::Buffer::ToString(combined_buffer));
93 for(
const std::string& request : requests)
95 this->_LogTransaction(
"-->", request);
97 this->onRequest(request);
106 this->_session.status =
"|s|0|ss|Offline";
108 this->_SendNewStatus();
125 GameSpy::Parameter parameter = GameSpy::Request2Parameter(request);
128 std::string action = parameter[0];
130 auto it = mRequestActions.find(action);
131 if (it != mRequestActions.end())
134 RequestActionFunc func = it->second;
137 (this->*(func))(parameter);
141 Logger::warning(
"action \"" + action +
"\" not implemented!", Server::Type::GPCM);
149 this->_session.challenge = Util::generateRandomChallenge();
151 Logger::info(this->GetAddress() +
" --> Challenge", Server::Type::GPCM);
153 std::string response = GameSpy::Parameter2Response({
155 "challenge", this->_session.challenge,
160 this->Send(response);
162 this->_LogTransaction(
"<--", response);
179 if(parameter.size() != 21 ||
180 !Util::isAscii(parameter[3]) ||
181 !Util::isAscii(parameter[5]) ||
182 !Util::isAscii(parameter[7]) ||
183 !Util::isAscii(parameter[19]))
188 std::string client_challenge = parameter[3];
189 std::string uniquenick = parameter[5];
190 std::string client_response = parameter[7];
191 std::string
id = parameter[19];
192 std::string server_challenge = this->_session.challenge;
194 Logger::info(this->GetAddress() +
" --> Login", Server::Type::GPCM);
197 player.SetUniquenickWithoutClanTag(uniquenick);
202 player.SetUniquenick(uniquenick);
205 !player.isVerified() ||
206 client_response != GameSpy::LoginResponse(player.GetPassword(), player.GetUniquenick(), client_challenge, server_challenge)
209 std::string response = GameSpy::Parameter2Response({
213 "errmsg",
"The password provided was incorrect.",
218 this->Send(response);
220 this->_LogTransaction(
"<--", response);
226 std::string proof = GameSpy::LoginProof(player.GetPassword(), player.GetUniquenick(), client_challenge, server_challenge);
229 this->Disconnect(player.GetProfileId());
232 this->_session.profileid = player.GetProfileId();
233 this->_session.authtoken = Util::generateRandomAuthtoken();
234 this->_session.status =
"|s|1|ss|Online";
236 std::string response = GameSpy::Parameter2Response({
239 "userid", std::to_string(player.GetUserId()),
240 "profileid", std::to_string(player.GetProfileId()),
241 "uniquenick", player.GetUniquenick(),
242 "lt", this->_session.authtoken,
247 this->Send(response);
248 this->_LogTransaction(
"<--", response);
251 Logger::info(this->GetAddress() +
" <-- User \"" + player.GetUniquenick() +
"\" logged in.", Server::Type::GPCM);
255 std::vector<int> player_friends = player.GetFriends();
257 response = GameSpy::Parameter2Response({
258 "bdy", std::to_string(player_friends.size()),
259 "list", Util::ToString(player_friends),
262 this->Send(response);
263 this->_LogTransaction(
"<--", response);
266 this->_sync_friends = player_friends;
267 this->_SyncFriends();
277 if(parameter.size() != 7)
306 if(parameter.size() != 9 ||
307 !Util::isAscii(parameter[5]) ||
308 !Util::isAscii(parameter[7]))
313 std::string profileid = parameter[5];
314 std::string
id = parameter[7];
316 Logger::info(this->GetAddress() +
" --> GetProfile: " + profileid, Server::Type::GPCM);
319 player.SetProfileId(profileid);
324 std::string response;
326 if(player.GetUserId() != -1)
328 std::string uniquenick = player.GetUniquenick();
333 if(clan.GetClanId() != -1)
335 uniquenick = clan.GetTag() +
" " + uniquenick;
338 response = GameSpy::Parameter2Response({
340 "profileid", std::to_string(player.GetProfileId()),
341 "userid", std::to_string(player.GetUserId()),
342 "nick", player.GetNick(),
343 "uniquenick", uniquenick,
344 "email",
"<private>",
349 "videocard1string",
"",
350 "videocard2string",
"",
353 "sig",
"d41d8cd98f00b204e9800998ecf8427e",
359 response = GameSpy::Parameter2Response({
361 "profileid", profileid,
362 "userid", std::to_string(-1),
364 "uniquenick",
"<Unknown>",
365 "email",
"<Unknown>",
370 "videocard1string",
"",
371 "videocard2string",
"",
374 "sig",
"d41d8cd98f00b204e9800998ecf8427e",
379 this->Send(response);
381 this->_LogTransaction(
"<--", response);
383 this->_SyncFriends();
400 if(parameter.size() != 9 ||
401 !Util::isAscii(parameter[5]) ||
402 !Util::isAscii(parameter[7]))
407 std::string statstring = parameter[5];
408 std::string locstring = parameter[7];
411 if(statstring ==
"Resting")
413 this->_session.status =
"|s|1|ss|Resting";
415 else if(statstring ==
"Online")
417 this->_session.status =
"|s|1|ss|Online";
419 else if(statstring ==
"Playing")
421 this->_session.status =
"|s|2|ss|Playing";
426 this->_session.status +=
"|ls|" + locstring;
429 this->_SendNewStatus();
442 if(parameter.size() != 9 ||
443 !Util::isAscii(parameter[5]) ||
444 !Util::UTF8::isValid(parameter[7]))
449 std::string profileid = parameter[5];
450 std::string msg = parameter[7];
452 if(msg.find(
"BFMCC-GAMEVALIDREQ ") != std::string::npos || msg.find(
"BFMCC-GAMEVALIDRESP ") != std::string::npos)
458 target_player.SetProfileId(profileid);
462 this->_session.profileid,
463 target_player.GetProfileId(),
482 if(parameter.size() != 9 ||
483 !Util::isAscii(parameter[5]) ||
484 !Util::isAscii(parameter[7]))
489 std::string target_profileid = parameter[5];
490 std::string reason = parameter[7];
493 target_player.SetProfileId(target_profileid);
496 this->_session.profileid,
497 target_player.GetProfileId(),
499 reason +
"|signed|d41d8cd98f00b204e9800998ecf8427e"
515 if(parameter.size() != 9)
520 std::string target_profileid = parameter[5];
521 std::string sig = parameter[7];
527 player.SetProfileId(this->_session.profileid);
528 target_player.SetProfileId(target_profileid);
532 this->_session.profileid,
533 target_player.GetProfileId(),
535 "I have authorized your request to add me to your list|signed|d41d8cd98f00b204e9800998ecf8427e"
540 this->_session.profileid,
541 target_player.GetProfileId(),
543 this->_session.status
548 std::vector<int> player_friends = player.GetFriends();
550 auto it = std::find(player_friends.begin(), player_friends.end(), target_player.GetProfileId());
552 if(it == player_friends.end())
559 std::string response = GameSpy::Parameter2Response({
562 "errmsg",
"The profile requested is already a buddy.",
566 this->Send(response);
568 this->_LogTransaction(
"<--", response);
584 if(parameter.size() != 7 ||
585 !Util::isAscii(parameter[5]))
590 std::string target_profileid = parameter[5];
596 player.SetProfileId(this->_session.profileid);
597 target_player.SetProfileId(target_profileid);
600 target_player.GetProfileId(),
601 player.GetProfileId(),
603 "I have revoked you from my list.|signed|d41d8cd98f00b204e9800998ecf8427e"
617 if(parameter.size() != 7 ||
618 !Util::isAscii(parameter[5]))
623 std::string target_profileid = parameter[5];
629 player.SetProfileId(this->_session.profileid);
630 target_player.SetProfileId(target_profileid);
634 std::vector<int> player_friends = player.GetFriends();
636 auto it = std::find(player_friends.begin(), player_friends.end(), target_player.GetProfileId());
637 if(it != player_friends.end())
643 std::string response = GameSpy::Parameter2Response({
646 "errmsg",
"The buddy to be deleted is not a buddy. ",
650 this->Send(response);
652 this->_LogTransaction(
"<--", response);
663 if(parameter.size() != 9 ||
664 !Util::isAscii(parameter[5]))
669 std::string target_profileid = parameter[5];
674 target_player.SetProfileId(target_profileid);
678 this->_session.profileid,
679 target_player.GetProfileId(),
681 this->_session.status
686 this->_session.profileid,
687 target_player.GetProfileId(),
689 "|p|1337|l|bfield1942ps2:/YOLO@1.1.1.1:1337"
707 player.SetProfileId(this->_session.profileid);
711 Logger::info(
"User \"" + player.GetUniquenick() +
"\" logged out", Server::Type::GPCM);
718 std::shared_lock<std::shared_mutex> guard2(g_settings_mutex);
720 if ((g_logger_mode & Logger::Mode::Development) == 0)
725 bool show_console = (g_settings[
"gpcm"][
"show_requests"].asBool() && direction ==
"-->") ||
726 (g_settings[
"gpcm"][
"show_responses"].asBool() && direction ==
"<--");
728 Logger::info(this->GetAddress() +
" " + direction +
" " + response,
729 Server::Type::GPCM, show_console);
736 player.SetProfileId(this->_session.profileid);
741 for(
int friend_profileid : player.GetFriends())
745 this->_session.profileid,
748 this->_session.status
755 if(this->_sync_friends.size() >= 1)
757 int id = this->_sync_friends.size() - 1;
758 int friend_profileid = this->_sync_friends[id];
761 std::string response;
763 if(session.profileid != -1)
765 response = GameSpy::Parameter2Response({
767 "f", std::to_string(friend_profileid),
768 "msg", session.status,
774 response = GameSpy::Parameter2Response({
776 "f", std::to_string(friend_profileid),
777 "msg",
"|s|0|ss|Offline",
782 this->Send(response);
784 this->_LogTransaction(
"<--", response);
787 this->_sync_friends.pop_back();
797 for(std::shared_ptr<Net::Socket> client : g_gpcm_server->
GetClients())
799 std::shared_ptr<GPCM::Client> gpcm_client = std::dynamic_pointer_cast<GPCM::Client>(client);
802 session = gpcm_client->GetSession();
804 if(session.profileid == profileid)
806 session.client = gpcm_client;
818 for(std::shared_ptr<Net::Socket> client : g_gpcm_server->
GetClients())
820 std::shared_ptr<GPCM::Client> gpcm_client = std::dynamic_pointer_cast<GPCM::Client>(client);
823 session = gpcm_client->GetSession();
825 if(session.authtoken == authtoken)
827 session.client = gpcm_client;
837 GPCM::Session target_session = findSessionByProfileId(target_profileid);
839 if(target_session.profileid != -1)
848 if(session.profileid != -1)
850 ip = session.client->GetIP();
853 g_database->
insertChat(profileid, ip, target_profileid, message);
856 std::string response = GameSpy::Parameter2Response({
858 "f", std::to_string(profileid),
863 target_session.client->Send(response);
865 target_session.client->_LogTransaction(
"<--", response);
873 for(std::shared_ptr<Net::Socket> client : g_gpcm_server->
GetClients())
875 std::shared_ptr<GPCM::Client> gpcm_client = std::dynamic_pointer_cast<GPCM::Client>(client);
878 session = gpcm_client->GetSession();
880 if(session.profileid == profileid)
882 gpcm_client.get()->Disconnect();
893 std::this_thread::sleep_for (std::chrono::seconds(60));
895 for(std::shared_ptr<Net::Socket> client : g_gpcm_server->
GetClients())
897 std::shared_ptr<GPCM::Client> gpcm_client = std::dynamic_pointer_cast<GPCM::Client>(client);
899 std::string response = GameSpy::Parameter2Response({
904 gpcm_client.get()->Send(response);
906 gpcm_client.get()->_LogTransaction(
"<--", response);
Represents a clan in the Battlefield game.
Represents a player with extended statistics.
bool queryPlayerByProfileId(Battlefield::Player &player)
Queries a player by their profile ID.
bool updatePlayerLastLogin(Battlefield::Player &player, const std::string &ip)
Updates the last login IP address and date for a player.
bool insertPlayerFriend(const Battlefield::Player &player, const Battlefield::Player &target_player)
Inserts a friendship relation between two players into the database.
bool queryPlayerFriendsByProfileId(Battlefield::Player &player)
Queries a player's friends by their profile ID.
bool queryPlayerByUniquenick(Battlefield::Player &player)
Queries a player by their unique nickname.
bool removePlayerFriend(const Battlefield::Player &player, const Battlefield::Player &target_player)
Removes a friendship relation between two players from the database.
bool queryClanByProfileId(Battlefield::Clan &clan, const Battlefield::Player &player)
Queries a clan by a player's profile ID.
bool insertChat(int profileid, const std::string &ip, int target_profileid, const std::string &msg)
Inserts a chat message into the database.
Represents a GPCM client.
void requestChallenge()
Sends a challenge to the client.
void requestInviteTo(const GameSpy::Parameter ¶meter)
Process an invite request from the client.
void requestGetProfile(const GameSpy::Parameter ¶meter)
Process a get-profile request from the client.
void requestAuthAdd(const GameSpy::Parameter ¶meter)
Process an auth-add request from the client.
void Disconnect()
Disconnects the client.
void Listen()
Listens for incoming messages from the GPCM client.
void _LogTransaction(const std::string &direction, const std::string &response) const
Log a transaction with direction and response.
~Client()
Destroys the GPCM client.
void requestRevoke(const GameSpy::Parameter ¶meter)
Process a revoke request from the client.
void requestPlayerInvite(const GameSpy::Parameter ¶meter)
Process a player-invite request from the client.
void _SyncFriends()
Synchronizes friends with the client.
static GPCM::Session findSessionByProfileId(int profileid)
Finds a session by profile ID.
static void SendBuddyMessage(int profileid, int target_profileid, const std::string &bm, const std::string &message)
Sends a buddy message from one profile ID to another.
Client(int socket, struct sockaddr_in address)
Constructs a new GPCM client.
static void Heartbeat()
Heartbeat function to manage client connections.
void requestStatus(const GameSpy::Parameter ¶meter)
Process a status request from the client.
void requestBm(const GameSpy::Parameter ¶meter)
Process a BM request from the client.
void requestDeleteBuddy(const GameSpy::Parameter ¶meter)
Process a delete-buddy request from the client.
void requestLogout(const GameSpy::Parameter ¶meter)
Process a logout request from the client.
void onRequest(const std::string &msg)
Event handler for incoming messages from the client.
static GPCM::Session findSessionByAuthtoken(const std::string &authtoken)
Finds a session by authentication token.
void requestAddBuddy(const GameSpy::Parameter ¶meter)
Process an add-buddy request from the client.
void requestLogin(const GameSpy::Parameter ¶meter)
Process a login request from the client.
void _SendNewStatus() const
Sends a new status to the client.
GPCM::Session GetSession() const
Get the session information of the client.
void UpdateLastRecievedTime()
Updates the last received time to the current system time.
struct sockaddr_in _address
std::vector< std::shared_ptr< Net::Socket > > GetClients()
Get the vector of client sockets connected to this server.
void onClientDisconnect(const Net::Socket &client)
Called when a client disconnects from the server.
Represents a session with a GPCM client.