1 /*****************************************************************************
2 * PokerTH - The open source texas holdem engine *
3 * Copyright (C) 2006-2012 Felix Hammer, Florian Thauer, Lothar May *
4 * *
5 * This program is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU Affero General Public License as *
7 * published by the Free Software Foundation, either version 3 of the *
8 * License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU Affero General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU Affero General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 * *
18 * *
19 * Additional permission under GNU AGPL version 3 section 7 *
20 * *
21 * If you modify this program, or any covered work, by linking or *
22 * combining it with the OpenSSL project's OpenSSL library (or a *
23 * modified version of that library), containing parts covered by the *
24 * terms of the OpenSSL or SSLeay licenses, the authors of PokerTH *
25 * (Felix Hammer, Florian Thauer, Lothar May) grant you additional *
26 * permission to convey the resulting work. *
27 * Corresponding Source for a non-source form of such a combination *
28 * shall include the source code for the parts of OpenSSL used as well *
29 * as that of the covered work. *
30 *****************************************************************************/
31
32 #include <net/serverlobbythread.h>
33 #include <net/servergame.h>
34 #include <net/serverbanmanager.h>
35 #include <net/serverexception.h>
36 #include <net/receivebuffer.h>
37 #include <net/senderhelper.h>
38 #include <net/serverircbotcallback.h>
39 #include <net/socket_msg.h>
40 #include <net/chatcleanermanager.h>
41 #include <net/net_helper.h>
42 #include <db/serverdbinterface.h>
43 #ifdef POKERTH_OFFICIAL_SERVER
44 #include <dbofficial/serverdbfactoryinternal.h>
45 #else
46 #include <db/serverdbfactorygeneric.h>
47 #endif
48 #include <core/avatarmanager.h>
49 #include <core/loghelper.h>
50 #include <core/openssl_wrapper.h>
51 #include <configfile.h>
52 #include <playerinterface.h>
53
54 #include <fstream>
55 #include <sstream>
56 #include <algorithm>
57 #include <cctype>
58 #include <boost/lambda/lambda.hpp>
59 #include <boost/filesystem.hpp>
60 #include <boost/bind.hpp>
61 #include <boost/foreach.hpp>
62 #include <boost/uuid/uuid.hpp>
63 #include <boost/algorithm/string.hpp>
64 #include <gsasl.h>
65
66 #define SERVER_MAX_NUM_LOBBY_SESSIONS 512 // Maximum number of idle users in lobby.
67 #define SERVER_MAX_NUM_TOTAL_SESSIONS 2000 // Total maximum of sessions, fitting a 2048 handle limit
68
69 #define SERVER_SAVE_STATISTICS_INTERVAL_SEC 60
70 #define SERVER_CHECK_SESSION_TIMEOUTS_INTERVAL_MSEC 500
71 #define SERVER_REMOVE_GAME_INTERVAL_MSEC 500
72 #define SERVER_REMOVE_PLAYER_INTERVAL_MSEC 100
73 #define SERVER_UPDATE_LOGIN_LOCK_INTERVAL_MSEC 1000
74 #define SERVER_PROCESS_SEND_INTERVAL_MSEC 10
75
76 #define SERVER_INIT_LOGIN_CLIENT_LOCK_SEC NetHelper::GetLoginLockSec()
77
78 #define SERVER_INIT_SESSION_TIMEOUT_SEC 60
79 #define SERVER_TIMEOUT_WARNING_REMAINING_SEC 60
80 #define SERVER_SESSION_ACTIVITY_TIMEOUT_SEC 1800 // 30 min, MUST be > SERVER_TIMEOUT_WARNING_REMAINING_SEC
81 #define SERVER_SESSION_FORCED_TIMEOUT_SEC 86400 // 1 day, should be quite large.
82
83 #define SERVER_ADDRESS_LOCALHOST_STR_V4 "127.0.0.1"
84 #define SERVER_ADDRESS_LOCALHOST_STR_V4V6 "::ffff:127.0.0.1"
85 #define SERVER_ADDRESS_LOCALHOST_STR "::1"
86
87 #define SERVER_STATISTICS_FILE_NAME "server_statistics.log"
88 #define SERVER_STATISTICS_STR_TOTAL_PLAYERS "TotalNumPlayersLoggedIn"
89 #define SERVER_STATISTICS_STR_TOTAL_GAMES "TotalNumGamesCreated"
90 #define SERVER_STATISTICS_STR_MAX_GAMES "MaxGamesOpen"
91 #define SERVER_STATISTICS_STR_MAX_PLAYERS "MaxPlayersLoggedIn"
92 #define SERVER_STATISTICS_STR_CUR_GAMES "CurGamesOpen"
93 #define SERVER_STATISTICS_STR_CUR_PLAYERS "CurPlayersLoggedIn"
94
95 using namespace std;
96 using boost::asio::ip::tcp;
97
98 #ifdef BOOST_ASIO_HAS_STD_CHRONO
99 using namespace std::chrono;
100 #else
101 using namespace boost::chrono;
102 #endif
103
104 class InternalServerCallback : public SessionDataCallback, public ChatCleanerCallback, public ServerDBCallback
105 {
106 public:
InternalServerCallback(ServerLobbyThread & server)107 InternalServerCallback(ServerLobbyThread &server) : m_server(server) {}
~InternalServerCallback()108 virtual ~InternalServerCallback() {}
109
CloseSession(boost::shared_ptr<SessionData> session)110 virtual void CloseSession(boost::shared_ptr<SessionData> session)
111 {
112 m_server.CloseSession(session);
113 }
114
SessionError(boost::shared_ptr<SessionData> session,int errorCode)115 virtual void SessionError(boost::shared_ptr<SessionData> session, int errorCode)
116 {
117 m_server.SessionError(session, errorCode);
118 }
119
SessionTimeoutWarning(boost::shared_ptr<SessionData> session,unsigned remainingSec)120 virtual void SessionTimeoutWarning(boost::shared_ptr<SessionData> session, unsigned remainingSec)
121 {
122 m_server.SessionTimeoutWarning(session, remainingSec);
123 }
124
HandlePacket(boost::shared_ptr<SessionData> session,boost::shared_ptr<NetPacket> packet)125 virtual void HandlePacket(boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet)
126 {
127 m_server.DispatchPacket(session, packet);
128 }
129
SignalChatBotMessage(const string & msg)130 virtual void SignalChatBotMessage(const string &msg)
131 {
132 m_server.SendChatBotMsg(msg);
133 }
134
SignalChatBotMessage(unsigned gameId,const std::string & msg)135 virtual void SignalChatBotMessage(unsigned gameId, const std::string &msg)
136 {
137 m_server.SendChatBotMsg(gameId, msg);
138 }
139
SignalKickPlayer(unsigned playerId)140 virtual void SignalKickPlayer(unsigned playerId)
141 {
142 m_server.RemovePlayer(playerId, ERR_NET_PLAYER_KICKED);
143 }
144
SignalBanPlayer(unsigned playerId)145 virtual void SignalBanPlayer(unsigned playerId)
146 {
147 string playerName(m_server.GetPlayerNameFromId(playerId));
148 if (!playerName.empty()) {
149 m_server.GetBanManager().BanPlayerName(playerName, 1);
150 m_server.RemovePlayer(playerId, ERR_NET_PLAYER_KICKED);
151 }
152 }
153
SignalMutePlayer(unsigned playerId)154 virtual void SignalMutePlayer(unsigned playerId)
155 {
156 m_server.MutePlayerInGame(playerId);
157 }
158
ConnectSuccess()159 virtual void ConnectSuccess()
160 {
161 LOG_MSG("Successfully connected to database.");
162 }
163
ConnectFailed(string error)164 virtual void ConnectFailed(string error)
165 {
166 LOG_ERROR("DB connect error: " << error);
167 }
168
QueryError(string error)169 virtual void QueryError(string error)
170 {
171 LOG_ERROR("DB query error: " << error);
172 }
173
PlayerLoginSuccess(unsigned requestId,boost::shared_ptr<DBPlayerData> dbPlayerData)174 virtual void PlayerLoginSuccess(unsigned requestId, boost::shared_ptr<DBPlayerData> dbPlayerData)
175 {
176 m_server.UserValid(requestId, *dbPlayerData);
177 }
178
PlayerLoginFailed(unsigned requestId)179 virtual void PlayerLoginFailed(unsigned requestId)
180 {
181 m_server.UserInvalid(requestId);
182 }
183
PlayerLoginBlocked(unsigned requestId)184 virtual void PlayerLoginBlocked(unsigned requestId)
185 {
186 m_server.UserBlocked(requestId);
187 }
188
AvatarIsBlacklisted(unsigned requestId)189 virtual void AvatarIsBlacklisted(unsigned requestId)
190 {
191 m_server.AvatarBlacklisted(requestId);
192 }
193
AvatarIsOK(unsigned requestId)194 virtual void AvatarIsOK(unsigned requestId)
195 {
196 m_server.AvatarOK(requestId);
197 }
198
CreateGameSuccess(unsigned)199 virtual void CreateGameSuccess(unsigned /*requestId*/)
200 {
201 // Nothing to do.
202 }
203
CreateGameFailed(unsigned requestId)204 virtual void CreateGameFailed(unsigned requestId)
205 {
206 // TODO maybe handle request id.
207 LOG_ERROR("DB create game failed for request " << requestId);
208 }
209
ReportAvatarSuccess(unsigned requestId,unsigned replyId)210 virtual void ReportAvatarSuccess(unsigned requestId, unsigned replyId)
211 {
212 m_server.SendReportAvatarResult(requestId, replyId, true);
213 }
214
ReportAvatarFailed(unsigned requestId,unsigned replyId)215 virtual void ReportAvatarFailed(unsigned requestId, unsigned replyId)
216 {
217 m_server.SendReportAvatarResult(requestId, replyId, false);
218 }
219
ReportGameSuccess(unsigned requestId,unsigned replyId)220 virtual void ReportGameSuccess(unsigned requestId, unsigned replyId)
221 {
222 m_server.SendReportGameResult(requestId, replyId, true);
223 }
224
ReportGameFailed(unsigned requestId,unsigned replyId)225 virtual void ReportGameFailed(unsigned requestId, unsigned replyId)
226 {
227 m_server.SendReportGameResult(requestId, replyId, false);
228 }
229
PlayerAdminList(unsigned,std::list<DB_id> adminList)230 virtual void PlayerAdminList(unsigned /*requestId*/, std::list<DB_id> adminList)
231 {
232 m_server.GetBanManager().SetAdminPlayerIds(adminList);
233 }
234
BlockPlayerSuccess(unsigned requestId,unsigned replyId)235 virtual void BlockPlayerSuccess(unsigned requestId, unsigned replyId)
236 {
237 m_server.SendAdminBanPlayerResult(requestId, replyId, true);
238 }
239
BlockPlayerFailed(unsigned requestId,unsigned replyId)240 virtual void BlockPlayerFailed(unsigned requestId, unsigned replyId)
241 {
242 m_server.SendAdminBanPlayerResult(requestId, replyId, false);
243 }
244
245 private:
246 ServerLobbyThread &m_server;
247 };
248
249
ServerLobbyThread(GuiInterface & gui,ServerMode mode,ServerIrcBotCallback & ircBotCb,ConfigFile & serverConfig,AvatarManager & avatarManager,boost::shared_ptr<boost::asio::io_service> ioService)250 ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ServerMode mode, ServerIrcBotCallback &ircBotCb, ConfigFile &serverConfig,
251 AvatarManager &avatarManager, boost::shared_ptr<boost::asio::io_service> ioService)
252 : m_ioService(ioService), m_authContext(NULL), m_gui(gui), m_ircBotCb(ircBotCb), m_avatarManager(avatarManager),
253 m_mode(mode), m_serverConfig(serverConfig), m_curGameId(0), m_curUniquePlayerId(0), m_curSessionId(INVALID_SESSION + 1),
254 m_statDataChanged(false), m_removeGameTimer(*ioService),
255 m_saveStatisticsTimer(*ioService), m_loginLockTimer(*ioService),
256 m_startTime(boost::posix_time::second_clock::local_time())
257 {
258 m_internalServerCallback.reset(new InternalServerCallback(*this));
259 m_sender.reset(new SenderHelper(m_ioService));
260 m_banManager.reset(new ServerBanManager(m_ioService));
261 m_chatCleanerManager.reset(new ChatCleanerManager(*m_internalServerCallback, m_ioService));
262 DBFactory dbFactory;
263 m_database = dbFactory.CreateServerDBObject(*m_internalServerCallback, m_ioService);
264 }
265
~ServerLobbyThread()266 ServerLobbyThread::~ServerLobbyThread()
267 {
268 }
269
270 void
Init(const string & logDir)271 ServerLobbyThread::Init(const string &logDir)
272 {
273 // Read previous server statistics.
274 if (!logDir.empty()) {
275 boost::filesystem::path logPath(logDir);
276 if (!logDir.empty()) {
277 logPath /= SERVER_STATISTICS_FILE_NAME;
278 m_statisticsFileName = logPath.directory_string();
279 ReadStatisticsFile();
280 }
281 }
282 m_database->Init(
283 m_serverConfig.readConfigString("DBServerAddress"),
284 m_serverConfig.readConfigString("DBServerUser"),
285 m_serverConfig.readConfigString("DBServerPassword"),
286 m_serverConfig.readConfigString("DBServerDatabaseName"),
287 m_serverConfig.readConfigString("DBServerEncryptionKey"));
288 m_database->AsyncQueryAdminPlayers(0);
289
290 GetBanManager().InitGameNameBadWordList(m_serverConfig.readConfigStringList("GameNameBadWordList"));
291 }
292
293 void
SignalTermination()294 ServerLobbyThread::SignalTermination()
295 {
296 Thread::SignalTermination();
297 m_ioService->stop();
298 }
299
300 void
AddConnection(boost::shared_ptr<SessionData> sessionData)301 ServerLobbyThread::AddConnection(boost::shared_ptr<SessionData> sessionData)
302 {
303 // Create a new session.
304 m_sessionManager.AddSession(sessionData);
305
306 LOG_VERBOSE("Accepted connection - session #" << sessionData->GetId() << ".");
307
308 sessionData->StartTimerInitTimeout(SERVER_INIT_SESSION_TIMEOUT_SEC);
309 sessionData->StartTimerGlobalTimeout(SERVER_SESSION_FORCED_TIMEOUT_SEC);
310 sessionData->StartTimerActivityTimeout(SERVER_SESSION_ACTIVITY_TIMEOUT_SEC, SERVER_TIMEOUT_WARNING_REMAINING_SEC);
311
312 unsigned numLobbySessions = m_sessionManager.GetRawSessionCount();
313 unsigned numGameSessions = m_gameSessionManager.GetRawSessionCount();
314 if (numLobbySessions <= SERVER_MAX_NUM_LOBBY_SESSIONS
315 && numLobbySessions + numGameSessions <= SERVER_MAX_NUM_TOTAL_SESSIONS) {
316 string ipAddress = sessionData->GetRemoteIPAddressFromSocket();
317 if (!ipAddress.empty()) {
318 sessionData->SetClientAddr(ipAddress);
319
320 boost::shared_ptr<NetPacket> packet(new NetPacket);
321 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_AnnounceMessage);
322 AnnounceMessage *netAnnounce = packet->GetMsg()->mutable_announcemessage();
323 netAnnounce->mutable_protocolversion()->set_majorversion(NET_VERSION_MAJOR);
324 netAnnounce->mutable_protocolversion()->set_minorversion(NET_VERSION_MINOR);
325 netAnnounce->mutable_latestgameversion()->set_majorversion(POKERTH_VERSION_MAJOR);
326 netAnnounce->mutable_latestgameversion()->set_minorversion(POKERTH_VERSION_MINOR);
327 netAnnounce->set_latestbetarevision(POKERTH_BETA_REVISION);
328 switch (GetServerMode()) {
329 case SERVER_MODE_LAN:
330 netAnnounce->set_servertype(AnnounceMessage::serverTypeLAN);
331 break;
332 case SERVER_MODE_INTERNET_NOAUTH:
333 netAnnounce->set_servertype(AnnounceMessage::serverTypeInternetNoAuth);
334 break;
335 case SERVER_MODE_INTERNET_AUTH:
336 netAnnounce->set_servertype(AnnounceMessage::serverTypeInternetAuth);
337 break;
338 }
339 {
340 boost::mutex::scoped_lock lock(m_statMutex);
341 netAnnounce->set_numplayersonserver(m_statData.numberOfPlayersOnServer);
342 }
343 GetSender().Send(sessionData, packet);
344 sessionData->GetReceiveBuffer().StartAsyncRead(sessionData);
345 } else {
346 // We do not accept sessions if we cannot
347 // retrieve the client address.
348 SessionError(sessionData, ERR_NET_INVALID_SESSION);
349 }
350 } else {
351 // Server is full.
352 // Gracefully close this session.
353 SessionError(sessionData, ERR_NET_SERVER_FULL);
354 }
355 }
356
357 void
ReAddSession(boost::shared_ptr<SessionData> session,int reason,unsigned gameId)358 ServerLobbyThread::ReAddSession(boost::shared_ptr<SessionData> session, int reason, unsigned gameId)
359 {
360 if (session && session->GetPlayerData()) {
361 boost::shared_ptr<NetPacket> packet(new NetPacket);
362 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_RemovedFromGameMessage);
363 RemovedFromGameMessage *removed = packet->GetMsg()->mutable_removedfromgamemessage();
364 removed->set_gameid(gameId);
365
366 switch (reason) {
367 case NTF_NET_REMOVED_GAME_FULL :
368 removed->set_removedfromgamereason(RemovedFromGameMessage::gameIsFull);
369 break;
370 case NTF_NET_REMOVED_ALREADY_RUNNING :
371 removed->set_removedfromgamereason(RemovedFromGameMessage::gameIsRunning);
372 break;
373 case NTF_NET_REMOVED_KICKED :
374 removed->set_removedfromgamereason(RemovedFromGameMessage::kickedFromGame);
375 break;
376 case NTF_NET_REMOVED_TIMEOUT :
377 removed->set_removedfromgamereason(RemovedFromGameMessage::gameTimeout);
378 break;
379 case NTF_NET_REMOVED_START_FAILED :
380 removed->set_removedfromgamereason(RemovedFromGameMessage::removedStartFailed);
381 break;
382 case NTF_NET_REMOVED_GAME_CLOSED :
383 removed->set_removedfromgamereason(RemovedFromGameMessage::gameClosed);
384 break;
385 default :
386 removed->set_removedfromgamereason(RemovedFromGameMessage::removedOnRequest);
387 break;
388 }
389 GetSender().Send(session, packet);
390
391 HandleReAddedSession(session);
392 }
393 }
394
395 void
MoveSessionToGame(boost::shared_ptr<ServerGame> game,boost::shared_ptr<SessionData> session,bool autoLeave,bool spectateOnly)396 ServerLobbyThread::MoveSessionToGame(boost::shared_ptr<ServerGame> game, boost::shared_ptr<SessionData> session, bool autoLeave, bool spectateOnly)
397 {
398 // Remove session from the lobby.
399 m_sessionManager.RemoveSession(session->GetId());
400 // Session is now in game state.
401 session->SetState(spectateOnly ? SessionData::Spectating : SessionData::Game);
402 // Store it in the list of game sessions.
403 m_gameSessionManager.AddSession(session);
404 // Set the game id of the session.
405 session->SetGame(game);
406 // Add session to the game.
407 game->AddSession(session, spectateOnly);
408 // Optionally enable auto leave after game finish.
409 if (autoLeave)
410 game->SetPlayerAutoLeaveOnFinish(session->GetPlayerData()->GetUniqueId());
411 }
412
413 void
CloseSession(boost::shared_ptr<SessionData> session)414 ServerLobbyThread::CloseSession(boost::shared_ptr<SessionData> session)
415 {
416 if (session && session->GetState() != SessionData::Closed) { // Make this call reentrant.
417 LOG_VERBOSE("Closing session #" << session->GetId() << ".");
418
419 boost::shared_ptr<ServerGame> tmpGame = session->GetGame();
420 if (tmpGame) {
421 tmpGame->RemoveSession(session, NTF_NET_INTERNAL);
422 }
423 session->SetGame(boost::shared_ptr<ServerGame>());
424 session->SetState(SessionData::Closed);
425
426 m_sessionManager.RemoveSession(session->GetId());
427 m_gameSessionManager.RemoveSession(session->GetId());
428
429 if (session->GetPlayerData()) {
430 NotifyPlayerLeftLobby(session->GetPlayerData()->GetUniqueId());
431 }
432 // Update stats (if needed).
433 UpdateStatisticsNumberOfPlayers();
434
435 // Ignore error when shutting down the socket.
436 boost::shared_ptr<boost::asio::ip::tcp::socket> sock = session->GetAsioSocket();
437 if (sock) {
438 boost::system::error_code ec;
439 session->GetAsioSocket()->shutdown(boost::asio::ip::tcp::socket::shutdown_receive, ec);
440 }
441 // Close this session after send.
442 GetSender().SetCloseAfterSend(session);
443 // Cancel all timers of the session.
444 session->CancelTimers();
445 }
446 }
447
448 void
ResubscribeLobbyMsg(boost::shared_ptr<SessionData> session)449 ServerLobbyThread::ResubscribeLobbyMsg(boost::shared_ptr<SessionData> session)
450 {
451 InternalResubscribeMsg(session);
452 }
453
454 void
NotifyPlayerJoinedLobby(unsigned playerId)455 ServerLobbyThread::NotifyPlayerJoinedLobby(unsigned playerId)
456 {
457 boost::shared_ptr<NetPacket> notify = CreateNetPacketPlayerListNew(playerId);
458 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), notify, SessionData::Established);
459 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), notify, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
460 }
461
462 void
NotifyPlayerLeftLobby(unsigned playerId)463 ServerLobbyThread::NotifyPlayerLeftLobby(unsigned playerId)
464 {
465 boost::shared_ptr<NetPacket> notify = CreateNetPacketPlayerListLeft(playerId);
466 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), notify, SessionData::Established);
467 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), notify, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
468 }
469
470 void
NotifyPlayerJoinedGame(unsigned gameId,unsigned playerId)471 ServerLobbyThread::NotifyPlayerJoinedGame(unsigned gameId, unsigned playerId)
472 {
473 // Send notification to players in lobby.
474 boost::shared_ptr<NetPacket> packet(new NetPacket);
475 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_GameListPlayerJoinedMessage);
476 GameListPlayerJoinedMessage *netListMsg = packet->GetMsg()->mutable_gamelistplayerjoinedmessage();
477 netListMsg->set_gameid(gameId);
478 netListMsg->set_playerid(playerId);
479
480 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established);
481 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
482 }
483
484 void
NotifyPlayerLeftGame(unsigned gameId,unsigned playerId)485 ServerLobbyThread::NotifyPlayerLeftGame(unsigned gameId, unsigned playerId)
486 {
487 // Send notification to players in lobby.
488 boost::shared_ptr<NetPacket> packet(new NetPacket);
489 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_GameListPlayerLeftMessage);
490 GameListPlayerLeftMessage *netListMsg = packet->GetMsg()->mutable_gamelistplayerleftmessage();
491 netListMsg->set_gameid(gameId);
492 netListMsg->set_playerid(playerId);
493
494 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established);
495 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
496 }
497
498 void
NotifySpectatorJoinedGame(unsigned gameId,unsigned playerId)499 ServerLobbyThread::NotifySpectatorJoinedGame(unsigned gameId, unsigned playerId)
500 {
501 // Send notification to players in lobby.
502 boost::shared_ptr<NetPacket> packet(new NetPacket);
503 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_GameListSpectatorJoinedMessage);
504 GameListSpectatorJoinedMessage *netListMsg = packet->GetMsg()->mutable_gamelistspectatorjoinedmessage();
505 netListMsg->set_gameid(gameId);
506 netListMsg->set_playerid(playerId);
507
508 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established);
509 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
510 }
511
512 void
NotifySpectatorLeftGame(unsigned gameId,unsigned playerId)513 ServerLobbyThread::NotifySpectatorLeftGame(unsigned gameId, unsigned playerId)
514 {
515 // Send notification to players in lobby.
516 boost::shared_ptr<NetPacket> packet(new NetPacket);
517 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_GameListSpectatorLeftMessage);
518 GameListSpectatorLeftMessage *netListMsg = packet->GetMsg()->mutable_gamelistspectatorleftmessage();
519 netListMsg->set_gameid(gameId);
520 netListMsg->set_playerid(playerId);
521
522 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established);
523 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
524 }
525
526 void
NotifyGameAdminChanged(unsigned gameId,unsigned newAdminPlayerId)527 ServerLobbyThread::NotifyGameAdminChanged(unsigned gameId, unsigned newAdminPlayerId)
528 {
529 // Send notification to players in lobby.
530 // Send notification to players in lobby.
531 boost::shared_ptr<NetPacket> packet(new NetPacket);
532 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_GameListAdminChangedMessage);
533 GameListAdminChangedMessage *netListMsg = packet->GetMsg()->mutable_gamelistadminchangedmessage();
534 netListMsg->set_gameid(gameId);
535 netListMsg->set_newadminplayerid(newAdminPlayerId);
536
537 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established);
538 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
539 }
540
541 void
NotifyStartingGame(unsigned gameId)542 ServerLobbyThread::NotifyStartingGame(unsigned gameId)
543 {
544 boost::shared_ptr<NetPacket> packet = CreateNetPacketGameListUpdate(gameId, GAME_MODE_STARTED);
545 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established);
546 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
547 }
548
549 void
NotifyReopeningGame(unsigned gameId)550 ServerLobbyThread::NotifyReopeningGame(unsigned gameId)
551 {
552 boost::shared_ptr<NetPacket> packet = CreateNetPacketGameListUpdate(gameId, GAME_MODE_CREATED);
553 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established);
554 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
555 }
556
557 void
HandleGameRetrievePlayerInfo(boost::shared_ptr<SessionData> session,const PlayerInfoRequestMessage & playerInfoRequest)558 ServerLobbyThread::HandleGameRetrievePlayerInfo(boost::shared_ptr<SessionData> session, const PlayerInfoRequestMessage &playerInfoRequest)
559 {
560 // Someone within a game requested player info.
561 HandleNetPacketRetrievePlayerInfo(session, playerInfoRequest);
562 }
563
564 void
HandleGameRetrieveAvatar(boost::shared_ptr<SessionData> session,const AvatarRequestMessage & retrieveAvatar)565 ServerLobbyThread::HandleGameRetrieveAvatar(boost::shared_ptr<SessionData> session, const AvatarRequestMessage &retrieveAvatar)
566 {
567 // Someone within a game requested an avatar.
568 HandleNetPacketRetrieveAvatar(session, retrieveAvatar);
569 }
570
571 void
HandleGameReportGame(boost::shared_ptr<SessionData> session,const ReportGameMessage & reportGame)572 ServerLobbyThread::HandleGameReportGame(boost::shared_ptr<SessionData> session, const ReportGameMessage &reportGame)
573 {
574 // Someone within a game reportet a game name.
575 HandleNetPacketReportGame(session, reportGame);
576 }
577
578 void
HandleChatRequest(boost::shared_ptr<SessionData> session,const ChatRequestMessage & chatRequest)579 ServerLobbyThread::HandleChatRequest(boost::shared_ptr<SessionData> session, const ChatRequestMessage &chatRequest)
580 {
581 // Someone within a game sent a lobby message.
582 HandleNetPacketChatRequest(session, chatRequest);
583 }
584
585 void
HandleAdminRemoveGame(boost::shared_ptr<SessionData> session,const AdminRemoveGameMessage & removeGame)586 ServerLobbyThread::HandleAdminRemoveGame(boost::shared_ptr<SessionData> session, const AdminRemoveGameMessage &removeGame)
587 {
588 // An admin within a game sent a remove game message.
589 HandleNetPacketAdminRemoveGame(session, removeGame);
590 }
591
592 void
HandleAdminBanPlayer(boost::shared_ptr<SessionData> session,const AdminBanPlayerMessage & banPlayer)593 ServerLobbyThread::HandleAdminBanPlayer(boost::shared_ptr<SessionData> session, const AdminBanPlayerMessage &banPlayer)
594 {
595 // An admin within a game sent a ban player message.
596 HandleNetPacketAdminBanPlayer(session, banPlayer);
597 }
598
599 bool
KickPlayerByName(const std::string & playerName)600 ServerLobbyThread::KickPlayerByName(const std::string &playerName)
601 {
602 bool retVal = false;
603 boost::shared_ptr<SessionData> session = m_sessionManager.GetSessionByPlayerName(playerName);
604 if (!session)
605 session = m_gameSessionManager.GetSessionByPlayerName(playerName);
606
607 if (session && session->GetPlayerData()) {
608 RemovePlayer(session->GetPlayerData()->GetUniqueId(), ERR_NET_PLAYER_KICKED);
609 retVal = true;
610 }
611
612 return retVal;
613 }
614
615 bool
RemoveGameByPlayerName(const std::string & playerName)616 ServerLobbyThread::RemoveGameByPlayerName(const std::string &playerName)
617 {
618 bool retVal = false;
619 boost::shared_ptr<SessionData> session = m_gameSessionManager.GetSessionByPlayerName(playerName);
620
621 if (session) {
622 boost::shared_ptr<ServerGame> game = session->GetGame();
623 if (game) {
624 m_ioService->post(boost::bind(&ServerLobbyThread::InternalRemoveGame, shared_from_this(), game));
625 retVal = true;
626 }
627 }
628
629 return retVal;
630 }
631
632 string
GetPlayerIPAddress(const std::string & playerName) const633 ServerLobbyThread::GetPlayerIPAddress(const std::string &playerName) const
634 {
635 string ipAddress;
636 boost::shared_ptr<SessionData> session = m_sessionManager.GetSessionByPlayerName(playerName);
637 if (!session)
638 session = m_gameSessionManager.GetSessionByPlayerName(playerName);
639
640 if (session)
641 ipAddress = session->GetClientAddr();
642
643 return ipAddress;
644 }
645
646 std::string
GetPlayerNameFromId(unsigned playerId) const647 ServerLobbyThread::GetPlayerNameFromId(unsigned playerId) const
648 {
649 string name;
650 boost::shared_ptr<SessionData> session = m_sessionManager.GetSessionByUniquePlayerId(playerId);
651 if (!session)
652 session = m_gameSessionManager.GetSessionByUniquePlayerId(playerId);
653
654 if (session && session->GetPlayerData())
655 name = session->GetPlayerData()->GetName();
656
657 return name;
658 }
659
660 void
RemovePlayer(unsigned playerId,unsigned errorCode)661 ServerLobbyThread::RemovePlayer(unsigned playerId, unsigned errorCode)
662 {
663 m_ioService->post(boost::bind(&ServerLobbyThread::InternalRemovePlayer, shared_from_this(), playerId, errorCode));
664 }
665
666 void
MutePlayerInGame(unsigned playerId)667 ServerLobbyThread::MutePlayerInGame(unsigned playerId)
668 {
669 m_ioService->post(boost::bind(&ServerLobbyThread::InternalMutePlayerInGame, shared_from_this(), playerId));
670 }
671
672 void
SendGlobalChat(const string & message)673 ServerLobbyThread::SendGlobalChat(const string &message)
674 {
675 boost::shared_ptr<NetPacket> packet(new NetPacket);
676 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_ChatMessage);
677 ChatMessage *netChat = packet->GetMsg()->mutable_chatmessage();
678 netChat->set_chattype(ChatMessage::chatTypeBroadcast);
679 netChat->set_chattext(message);
680
681 m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established);
682 m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
683 }
684
685 void
SendGlobalMsgBox(const string & message)686 ServerLobbyThread::SendGlobalMsgBox(const string &message)
687 {
688 boost::shared_ptr<NetPacket> packet(new NetPacket);
689 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_DialogMessage);
690 DialogMessage *netDialog = packet->GetMsg()->mutable_dialogmessage();
691 netDialog->set_notificationtext(message);
692
693 m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established);
694 m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
695 }
696
697 void
SendChatBotMsg(const std::string & message)698 ServerLobbyThread::SendChatBotMsg(const std::string &message)
699 {
700 boost::shared_ptr<NetPacket> packet(new NetPacket);
701 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_ChatMessage);
702 ChatMessage *netChat = packet->GetMsg()->mutable_chatmessage();
703 netChat->set_chattype(ChatMessage::chatTypeBot);
704 netChat->set_chattext(message);
705
706 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established);
707 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
708
709 GetIrcBotCallback().SignalLobbyMessage(
710 0,
711 "(chat bot)",
712 message);
713 }
714
715 void
SendChatBotMsg(unsigned gameId,const std::string & message)716 ServerLobbyThread::SendChatBotMsg(unsigned gameId, const std::string &message)
717 {
718 boost::shared_ptr<NetPacket> packet(new NetPacket);
719 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_ChatMessage);
720 ChatMessage *netChat = packet->GetMsg()->mutable_chatmessage();
721 netChat->set_chattype(ChatMessage::chatTypeBot);
722 netChat->set_gameid(gameId);
723 netChat->set_chattext(message);
724
725 GameMap::const_iterator pos = m_gameMap.find(gameId);
726 if (pos != m_gameMap.end()) {
727 pos->second->SendToAllPlayers(packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
728 }
729 }
730
731 void
ReconnectChatBot()732 ServerLobbyThread::ReconnectChatBot()
733 {
734 m_chatCleanerManager->ReInit();
735 }
736
737 void
AddComputerPlayer(boost::shared_ptr<PlayerData> player)738 ServerLobbyThread::AddComputerPlayer(boost::shared_ptr<PlayerData> player)
739 {
740 boost::mutex::scoped_lock lock(m_computerPlayersMutex);
741 m_computerPlayers.insert(PlayerDataMap::value_type(player->GetUniqueId(), player));
742 }
743
744 void
RemoveComputerPlayer(boost::shared_ptr<PlayerData> player)745 ServerLobbyThread::RemoveComputerPlayer(boost::shared_ptr<PlayerData> player)
746 {
747 boost::mutex::scoped_lock lock(m_computerPlayersMutex);
748 m_computerPlayers.erase(player->GetUniqueId());
749 }
750
751 bool
SendToLobbyPlayer(unsigned playerId,boost::shared_ptr<NetPacket> packet)752 ServerLobbyThread::SendToLobbyPlayer(unsigned playerId, boost::shared_ptr<NetPacket> packet)
753 {
754 bool retVal = false;
755 boost::shared_ptr<SessionData> tmpSession = m_sessionManager.GetSessionByUniquePlayerId(playerId);
756 if (tmpSession) {
757 GetSender().Send(tmpSession, packet);
758 retVal = true;
759 }
760 return retVal;
761 }
762
763 AvatarManager &
GetAvatarManager()764 ServerLobbyThread::GetAvatarManager()
765 {
766 return m_avatarManager;
767 }
768
769 ChatCleanerManager &
GetChatCleaner()770 ServerLobbyThread::GetChatCleaner()
771 {
772 assert(m_chatCleanerManager);
773 return *m_chatCleanerManager;
774 }
775
776 ServerStats
GetStats() const777 ServerLobbyThread::GetStats() const
778 {
779 boost::mutex::scoped_lock lock(m_statMutex);
780 return m_statData;
781 }
782
783 boost::posix_time::ptime
GetStartTime() const784 ServerLobbyThread::GetStartTime() const
785 {
786 return m_startTime;
787 }
788
789 ServerMode
GetServerMode() const790 ServerLobbyThread::GetServerMode() const
791 {
792 return m_mode;
793 }
794
795 SenderHelper &
GetSender()796 ServerLobbyThread::GetSender()
797 {
798 assert(m_sender);
799 return *m_sender;
800 }
801
802 boost::asio::io_service &
GetIOService()803 ServerLobbyThread::GetIOService()
804 {
805 assert(m_ioService);
806 return *m_ioService;
807 }
808
809 boost::shared_ptr<ServerDBInterface>
GetDatabase()810 ServerLobbyThread::GetDatabase()
811 {
812 return m_database;
813 }
814
815 ServerBanManager &
GetBanManager()816 ServerLobbyThread::GetBanManager()
817 {
818 assert(m_banManager);
819 return *m_banManager;
820 }
821
822 SessionDataCallback &
GetSessionDataCallback()823 ServerLobbyThread::GetSessionDataCallback()
824 {
825 return *m_internalServerCallback;
826 }
827
828 u_int32_t
GetNextSessionId()829 ServerLobbyThread::GetNextSessionId()
830 {
831 return m_curSessionId++;
832 }
833
834 u_int32_t
GetNextUniquePlayerId()835 ServerLobbyThread::GetNextUniquePlayerId()
836 {
837 boost::mutex::scoped_lock lock(m_curUniquePlayerIdMutex);
838 m_curUniquePlayerId++;
839 if (m_curUniquePlayerId == 0) // 0 is an invalid id.
840 m_curUniquePlayerId++;
841
842 return m_curUniquePlayerId;
843 }
844
845 u_int32_t
GetNextGameId()846 ServerLobbyThread::GetNextGameId()
847 {
848 m_curGameId++;
849 if (m_curGameId == 0) // 0 is an invalid id.
850 m_curGameId++;
851
852 return m_curGameId;
853 }
854
855 void
Main()856 ServerLobbyThread::Main()
857 {
858 try {
859 InitAuthContext();
860
861 InitChatCleaner();
862 // Start database engine.
863 m_database->Start();
864 // Register all timers.
865 RegisterTimers();
866
867 boost::asio::io_service::work ioWork(*m_ioService);
868 m_ioService->run(); // Will only be aborted asynchronously.
869
870 } catch (const PokerTHException &e) {
871 GetCallback().SignalNetServerError(e.GetErrorId(), e.GetOsErrorCode());
872 LOG_ERROR("Lobby exception: " << e.what());
873 }
874 // Clear all sessions and games.
875 m_sessionManager.Clear();
876 m_gameSessionManager.Clear();
877 BOOST_FOREACH(const GameMap::value_type& tmpGame, m_gameMap) {
878 tmpGame.second->Exit();
879 }
880 m_gameMap.clear();
881 // Cancel pending timer callbacks.
882 CancelTimers();
883 // Stop database engine.
884 m_database->Stop();
885
886 ClearAuthContext();
887 }
888
889 void
RegisterTimers()890 ServerLobbyThread::RegisterTimers()
891 {
892 // Remove closed games.
893 m_removeGameTimer.expires_from_now(
894 milliseconds(SERVER_REMOVE_GAME_INTERVAL_MSEC));
895 m_removeGameTimer.async_wait(
896 boost::bind(
897 &ServerLobbyThread::TimerRemoveGame, shared_from_this(), boost::asio::placeholders::error));
898 // Update the statistics file.
899 m_saveStatisticsTimer.expires_from_now(
900 seconds(SERVER_SAVE_STATISTICS_INTERVAL_SEC));
901 m_saveStatisticsTimer.async_wait(
902 boost::bind(
903 &ServerLobbyThread::TimerSaveStatisticsFile, shared_from_this(), boost::asio::placeholders::error));
904 // Update the avatar upload locks.
905 m_loginLockTimer.expires_from_now(
906 milliseconds(SERVER_UPDATE_LOGIN_LOCK_INTERVAL_MSEC));
907 m_loginLockTimer.async_wait(
908 boost::bind(
909 &ServerLobbyThread::TimerUpdateClientLoginLock, shared_from_this(), boost::asio::placeholders::error));
910 }
911
912 void
CancelTimers()913 ServerLobbyThread::CancelTimers()
914 {
915 m_removeGameTimer.cancel();
916 m_saveStatisticsTimer.cancel();
917 m_loginLockTimer.cancel();
918 }
919
920 void
InitAuthContext()921 ServerLobbyThread::InitAuthContext()
922 {
923 int res = gsasl_init(&m_authContext);
924 if (res != GSASL_OK)
925 throw ServerException(__FILE__, __LINE__, ERR_NET_GSASL_INIT_FAILED, 0);
926
927 if (!gsasl_server_support_p(m_authContext, "SCRAM-SHA-1")) {
928 gsasl_done(m_authContext);
929 throw ServerException(__FILE__, __LINE__, ERR_NET_GSASL_NO_SCRAM, 0);
930 }
931 }
932
933 void
ClearAuthContext()934 ServerLobbyThread::ClearAuthContext()
935 {
936 gsasl_done(m_authContext);
937 m_authContext = NULL;
938 }
939
940 void
InitChatCleaner()941 ServerLobbyThread::InitChatCleaner()
942 {
943 if (m_serverConfig.readConfigInt("UseChatCleaner") != 0) {
944 m_chatCleanerManager->Init(
945 m_serverConfig.readConfigString("ChatCleanerHostAddress"),
946 m_serverConfig.readConfigInt("ChatCleanerPort"),
947 m_serverConfig.readConfigInt("ChatCleanerUseIpv6") != 0,
948 m_serverConfig.readConfigString("ChatCleanerClientAuth"),
949 m_serverConfig.readConfigString("ChatCleanerServerAuth"));
950 }
951 }
952
953 void
DispatchPacket(boost::shared_ptr<SessionData> session,boost::shared_ptr<NetPacket> packet)954 ServerLobbyThread::DispatchPacket(boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet)
955 {
956 if (session) {
957 // Retrieve current game, if applicable.
958 boost::shared_ptr<ServerGame> game = session->GetGame();
959 if (game) {
960 // We need to catch game-specific exceptions, so that they do not affect the server.
961 try {
962 game->HandlePacket(session, packet);
963 } catch (const PokerTHException &e) {
964 LOG_ERROR("Game " << game->GetId() << " - Read handler exception: " << e.what());
965 game->RemoveAllSessions();
966 }
967 } else
968 HandlePacket(session, packet);
969 }
970 }
971
972 void
HandlePacket(boost::shared_ptr<SessionData> session,boost::shared_ptr<NetPacket> packet)973 ServerLobbyThread::HandlePacket(boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet)
974 {
975 if (session && packet) {
976 if (packet->IsClientActivity())
977 session->ResetActivityTimer();
978
979 if (session->GetState() == SessionData::Init) {
980 if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_InitMessage) {
981 HandleNetPacketInit(session, packet->GetMsg()->initmessage());
982 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_AuthClientResponseMessage) {
983 HandleNetPacketAuthClientResponse(session, packet->GetMsg()->authclientresponsemessage());
984 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_AvatarHeaderMessage) {
985 HandleNetPacketAvatarHeader(session, packet->GetMsg()->avatarheadermessage());
986 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_UnknownAvatarMessage) {
987 HandleNetPacketUnknownAvatar(session, packet->GetMsg()->unknownavatarmessage());
988 } else {
989 SessionError(session, ERR_SOCK_INVALID_STATE);
990 }
991 } else if (session->GetState() == SessionData::ReceivingAvatar) {
992 if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_AvatarDataMessage) {
993 HandleNetPacketAvatarFile(session, packet->GetMsg()->avatardatamessage());
994 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_AvatarEndMessage) {
995 HandleNetPacketAvatarEnd(session, packet->GetMsg()->avatarendmessage());
996 } else {
997 SessionError(session, ERR_SOCK_INVALID_STATE);
998 }
999 } else {
1000 if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_PlayerInfoRequestMessage)
1001 HandleNetPacketRetrievePlayerInfo(session, packet->GetMsg()->playerinforequestmessage());
1002 else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_AvatarRequestMessage)
1003 HandleNetPacketRetrieveAvatar(session, packet->GetMsg()->avatarrequestmessage());
1004 else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_ResetTimeoutMessage) {
1005 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_SubscriptionRequestMessage) {
1006 const SubscriptionRequestMessage &subscriptionRequest = packet->GetMsg()->subscriptionrequestmessage();
1007 if (subscriptionRequest.subscriptionaction() == SubscriptionRequestMessage::resubscribeGameList)
1008 InternalResubscribeMsg(session);
1009 else
1010 session->ResetWantsLobbyMsg();
1011 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_JoinNewGameMessage) {
1012 HandleNetPacketCreateGame(session, packet->GetMsg()->joinnewgamemessage());
1013 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_JoinExistingGameMessage) {
1014 HandleNetPacketJoinGame(session, packet->GetMsg()->joinexistinggamemessage());
1015 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_RejoinExistingGameMessage) {
1016 HandleNetPacketRejoinGame(session, packet->GetMsg()->rejoinexistinggamemessage());
1017 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_ChatRequestMessage) {
1018 HandleNetPacketChatRequest(session, packet->GetMsg()->chatrequestmessage());
1019 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_RejectGameInvitationMessage) {
1020 HandleNetPacketRejectGameInvitation(session, packet->GetMsg()->rejectgameinvitationmessage());
1021 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_ReportGameMessage) {
1022 HandleNetPacketReportGame(session, packet->GetMsg()->reportgamemessage());
1023 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_LeaveGameRequestMessage) {
1024 // Ignore "leave game" in this state.
1025 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_AdminRemoveGameMessage) {
1026 HandleNetPacketAdminRemoveGame(session, packet->GetMsg()->adminremovegamemessage());
1027 } else if (packet->GetMsg()->messagetype() == PokerTHMessage::Type_AdminBanPlayerMessage) {
1028 HandleNetPacketAdminBanPlayer(session, packet->GetMsg()->adminbanplayermessage());
1029 } else {
1030 SessionError(session, ERR_SOCK_INVALID_STATE);
1031 }
1032 }
1033 }
1034 }
1035
1036 void
HandleNetPacketInit(boost::shared_ptr<SessionData> session,const InitMessage & initMessage)1037 ServerLobbyThread::HandleNetPacketInit(boost::shared_ptr<SessionData> session, const InitMessage &initMessage)
1038 {
1039 LOG_VERBOSE("Received init for session #" << session->GetId() << ".");
1040
1041 // Before any other processing, perform some denial of service and
1042 // brute force attack prevention by checking whether the user recently sent an
1043 // Init packet.
1044 if (m_serverConfig.readConfigInt("ServerBruteForceProtection") != 0) {
1045 bool recentlySentInit = false;
1046 {
1047 boost::mutex::scoped_lock lock(m_timerClientAddressMapMutex);
1048 if (m_timerClientAddressMap.find(session->GetClientAddr()) != m_timerClientAddressMap.end())
1049 recentlySentInit = true;
1050 else
1051 m_timerClientAddressMap[session->GetClientAddr()] = boost::timers::portable::microsec_timer();
1052 }
1053 if (recentlySentInit) {
1054 SessionError(session, ERR_NET_INIT_BLOCKED);
1055 return;
1056 }
1057 }
1058
1059 // Check the protocol version.
1060 if (initMessage.requestedversion().majorversion() != NET_VERSION_MAJOR
1061 || session->GetPlayerData()) { // Has this session already sent an init?
1062 SessionError(session, ERR_NET_VERSION_NOT_SUPPORTED);
1063 return;
1064 }
1065 #ifndef POKERTH_OFFICIAL_SERVER
1066 // Check (clear text) server password (skip for official server, they are open to everyone).
1067 string serverPassword;
1068 if (initMessage.has_authserverpassword()) {
1069 serverPassword = initMessage.authserverpassword();
1070 }
1071 if (serverPassword != m_serverConfig.readConfigString("ServerPassword")) {
1072 SessionError(session, ERR_NET_INVALID_PASSWORD);
1073 return;
1074 }
1075 #endif
1076
1077 string playerName;
1078 MD5Buf avatarMD5;
1079 bool noAuth = false;
1080 bool validGuest = false;
1081 // productive: if (initMessage.login() == InitMessage::guestLogin) {
1082 // debug: if (initMessage.login() == InitMessage::unauthenticatedLogin) {
1083 if (initMessage.login() == InitMessage::guestLogin) {
1084 playerName = initMessage.nickname();
1085 // Verify guest player name.
1086 if (playerName.length() > sizeof(SERVER_GUEST_PLAYER_NAME - 1)
1087 && playerName.substr(0, sizeof(SERVER_GUEST_PLAYER_NAME) - 1) == SERVER_GUEST_PLAYER_NAME) {
1088 string guestId(playerName.substr(sizeof(SERVER_GUEST_PLAYER_NAME)));
1089 if ((size_t)count_if(guestId.begin(), guestId.end(), ::isdigit) == guestId.size()) {
1090 validGuest = true;
1091 noAuth = true;
1092 }
1093 // check if a guest session in lobby with same ip is already connected and
1094 // if number of lobby guests >= SERVER_MAX_GUEST_USERS_LOBBY
1095 if(m_serverConfig.readConfigInt("ServerRestrictGuestLogin") != 0
1096 && !m_sessionManager.IsGuestAllowedToConnect(session->GetClientAddr())) {
1097 SessionError(session, ERR_NET_SERVER_FULL);
1098 return;
1099 }
1100 }
1101
1102 if (!validGuest) {
1103 SessionError(session, ERR_NET_INVALID_PLAYER_NAME);
1104 return;
1105 }
1106 }
1107 #ifdef POKERTH_OFFICIAL_SERVER
1108 else if (initMessage.login() == InitMessage::authenticatedLogin) {
1109 string inAuthData(initMessage.clientuserdata());
1110 if (initMessage.has_avatarhash()) {
1111 memcpy(avatarMD5.GetData(), initMessage.avatarhash().data(), MD5_DATA_SIZE);
1112 }
1113 session->CreateServerAuthSession(m_authContext);
1114 if (session->AuthStep(1, inAuthData))
1115 playerName = session->AuthGetUser();
1116 }
1117 #else
1118 else if (initMessage.login() == InitMessage::unauthenticatedLogin) {
1119 playerName = initMessage.nickname();
1120 if (initMessage.has_avatarhash()) {
1121 memcpy(avatarMD5.GetData(), initMessage.avatarhash().data(), MD5_DATA_SIZE);
1122 }
1123 noAuth = true;
1124 }
1125 #endif
1126 else {
1127 SessionError(session, ERR_NET_INVALID_PASSWORD);
1128 return;
1129 }
1130
1131 // Check whether the player name is correct.
1132 // Partly, this is also done in netpacket.
1133 // However, some disallowed names are checked only here.
1134 if (playerName.empty()
1135 || playerName[0] == '#'
1136 || playerName[0] == ' '
1137 || playerName.substr(0, sizeof(SERVER_COMPUTER_PLAYER_NAME) - 1) == SERVER_COMPUTER_PLAYER_NAME) {
1138 SessionError(session, ERR_NET_INVALID_PLAYER_NAME);
1139 return;
1140 }
1141
1142 // Check whether the player name is banned.
1143 if (GetBanManager().IsPlayerBanned(playerName)) {
1144 SessionError(session, ERR_NET_PLAYER_BANNED);
1145 return;
1146 }
1147 // Check whether the peer IP address is banned.
1148 if (GetBanManager().IsIPAddressBanned(session->GetClientAddr())) {
1149 SessionError(session, ERR_NET_PLAYER_BANNED);
1150 return;
1151 }
1152
1153 // Create player data object.
1154 boost::shared_ptr<PlayerData> tmpPlayerData(
1155 new PlayerData(GetNextUniquePlayerId(), 0, PLAYER_TYPE_HUMAN, validGuest ? PLAYER_RIGHTS_GUEST : PLAYER_RIGHTS_NORMAL, false));
1156 tmpPlayerData->SetName(playerName);
1157 tmpPlayerData->SetAvatarMD5(avatarMD5);
1158 if (initMessage.has_mylastsessionid()) {
1159 tmpPlayerData->SetOldGuid(initMessage.mylastsessionid());
1160 }
1161
1162 // Set player data for session.
1163 m_sessionManager.SetSessionPlayerData(session->GetId(), tmpPlayerData);
1164 session->SetPlayerData(tmpPlayerData);
1165
1166 if (noAuth)
1167 InitAfterLogin(session);
1168 else
1169 AuthenticatePlayer(session);
1170 }
1171
1172 void
HandleNetPacketAuthClientResponse(boost::shared_ptr<SessionData> session,const AuthClientResponseMessage & clientResponse)1173 ServerLobbyThread::HandleNetPacketAuthClientResponse(boost::shared_ptr<SessionData> session, const AuthClientResponseMessage &clientResponse)
1174 {
1175 if (session && session->GetPlayerData() && session->AuthGetCurStepNum() == 1) {
1176 string authData = clientResponse.clientresponse();
1177 if (session->AuthStep(2, authData)) {
1178 string outVerification(session->AuthGetNextOutMsg());
1179
1180 boost::shared_ptr<NetPacket> packet(new NetPacket);
1181 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_AuthServerVerificationMessage);
1182 AuthServerVerificationMessage *verification = packet->GetMsg()->mutable_authserververificationmessage();
1183 verification->set_serververification(outVerification);
1184 GetSender().Send(session, packet);
1185 // The last message is only for server verification.
1186 // We are done now, the user has logged in.
1187 boost::shared_ptr<PlayerData> tmpPlayerData = session->GetPlayerData();
1188 if (GetBanManager().IsAdminPlayer(tmpPlayerData->GetDBId())) {
1189 session->GetPlayerData()->SetRights(PLAYER_RIGHTS_ADMIN);
1190 }
1191 CheckAvatarBlacklist(session);
1192 } else
1193 SessionError(session, ERR_NET_INVALID_PASSWORD);
1194 }
1195 }
1196
1197 void
HandleNetPacketAvatarHeader(boost::shared_ptr<SessionData> session,const AvatarHeaderMessage & avatarHeader)1198 ServerLobbyThread::HandleNetPacketAvatarHeader(boost::shared_ptr<SessionData> session, const AvatarHeaderMessage &avatarHeader)
1199 {
1200 if (session->GetPlayerData()) {
1201 if (avatarHeader.avatarsize() >= MIN_AVATAR_FILE_SIZE && avatarHeader.avatarsize() <= MAX_AVATAR_FILE_SIZE) {
1202 boost::shared_ptr<AvatarFile> tmpAvatarFile(new AvatarFile);
1203 tmpAvatarFile->fileData.reserve(avatarHeader.avatarsize());
1204 tmpAvatarFile->fileType = static_cast<AvatarFileType>(avatarHeader.avatartype());
1205 tmpAvatarFile->reportedSize = avatarHeader.avatarsize();
1206 // Ignore request id for now.
1207
1208 session->GetPlayerData()->SetNetAvatarFile(tmpAvatarFile);
1209
1210 // Session is now receiving an avatar.
1211 session->SetState(SessionData::ReceivingAvatar);
1212 } else
1213 SessionError(session, ERR_NET_AVATAR_TOO_LARGE);
1214 }
1215 }
1216
1217 void
HandleNetPacketUnknownAvatar(boost::shared_ptr<SessionData> session,const UnknownAvatarMessage &)1218 ServerLobbyThread::HandleNetPacketUnknownAvatar(boost::shared_ptr<SessionData> session, const UnknownAvatarMessage &/*unknownAvatar*/)
1219 {
1220 if (session->GetPlayerData()) {
1221 // Free memory (just in case).
1222 session->GetPlayerData()->SetNetAvatarFile(boost::shared_ptr<AvatarFile>());
1223 session->GetPlayerData()->SetAvatarMD5(MD5Buf());
1224 // Start session.
1225 EstablishSession(session);
1226 }
1227 }
1228
1229 void
HandleNetPacketAvatarFile(boost::shared_ptr<SessionData> session,const AvatarDataMessage & avatarData)1230 ServerLobbyThread::HandleNetPacketAvatarFile(boost::shared_ptr<SessionData> session, const AvatarDataMessage &avatarData)
1231 {
1232 if (session->GetPlayerData()) {
1233 boost::shared_ptr<AvatarFile> tmpAvatar = session->GetPlayerData()->GetNetAvatarFile();
1234 const string &avatarBlock = avatarData.avatarblock();
1235 if (tmpAvatar && tmpAvatar->fileData.size() + avatarBlock.size() <= tmpAvatar->reportedSize) {
1236 std::copy(&avatarBlock[0], &avatarBlock[avatarBlock.size()], back_inserter(tmpAvatar->fileData));
1237 }
1238 }
1239 }
1240
1241 void
HandleNetPacketAvatarEnd(boost::shared_ptr<SessionData> session,const AvatarEndMessage &)1242 ServerLobbyThread::HandleNetPacketAvatarEnd(boost::shared_ptr<SessionData> session, const AvatarEndMessage &/*avatarEnd*/)
1243 {
1244 if (session->GetPlayerData()) {
1245 boost::shared_ptr<AvatarFile> tmpAvatar = session->GetPlayerData()->GetNetAvatarFile();
1246 MD5Buf avatarMD5 = session->GetPlayerData()->GetAvatarMD5();
1247 if (!avatarMD5.IsZero() && tmpAvatar.get()) {
1248 unsigned avatarSize = (unsigned)tmpAvatar->fileData.size();
1249 if (avatarSize == tmpAvatar->reportedSize) {
1250 if (!GetAvatarManager().StoreAvatarInCache(avatarMD5, tmpAvatar->fileType, &tmpAvatar->fileData[0], avatarSize, true)) {
1251 session->GetPlayerData()->SetAvatarMD5(MD5Buf());
1252 LOG_ERROR("Failed to store avatar in cache directory.");
1253 }
1254
1255 // Free memory.
1256 session->GetPlayerData()->SetNetAvatarFile(boost::shared_ptr<AvatarFile>());
1257 // Set avatar file name.
1258 string avatarFileName;
1259 if (GetAvatarManager().GetAvatarFileName(avatarMD5, avatarFileName))
1260 session->GetPlayerData()->SetAvatarFile(avatarFileName);
1261 // Init finished - start session.
1262 EstablishSession(session);
1263 LOG_MSG("Client \"" << session->GetClientAddr() << "\" uploaded avatar \""
1264 << boost::filesystem::path(avatarFileName).file_string() << "\".");
1265 } else
1266 SessionError(session, ERR_NET_WRONG_AVATAR_SIZE);
1267 }
1268 }
1269 }
1270
1271 void
HandleNetPacketRetrievePlayerInfo(boost::shared_ptr<SessionData> session,const PlayerInfoRequestMessage & playerInfoRequest)1272 ServerLobbyThread::HandleNetPacketRetrievePlayerInfo(boost::shared_ptr<SessionData> session, const PlayerInfoRequestMessage &playerInfoRequest)
1273 {
1274 BOOST_FOREACH(unsigned playerId, playerInfoRequest.playerid()) {
1275 // Find player in lobby or in a game.
1276 boost::shared_ptr<SessionData> tmpSession = m_sessionManager.GetSessionByUniquePlayerId(playerId);
1277 if (!tmpSession) {
1278 tmpSession = m_gameSessionManager.GetSessionByUniquePlayerId(playerId);
1279 }
1280 boost::shared_ptr<PlayerData> tmpPlayer;
1281 if (tmpSession) {
1282 tmpPlayer = tmpSession->GetPlayerData();
1283 }
1284
1285 if (!tmpPlayer) {
1286 boost::mutex::scoped_lock lock(m_computerPlayersMutex);
1287 PlayerDataMap::const_iterator pos = m_computerPlayers.find(playerId);
1288 if (pos != m_computerPlayers.end())
1289 tmpPlayer = pos->second;
1290 }
1291
1292 boost::shared_ptr<NetPacket> packet(new NetPacket);
1293 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_PlayerInfoReplyMessage);
1294 PlayerInfoReplyMessage *netPlayerInfoReply = packet->GetMsg()->mutable_playerinforeplymessage();
1295 netPlayerInfoReply->set_playerid(playerId);
1296
1297 if (tmpPlayer) {
1298 // Send player info to client.
1299 PlayerInfoReplyMessage::PlayerInfoData *data = netPlayerInfoReply->mutable_playerinfodata();
1300
1301 data->set_playername(tmpPlayer->GetName());
1302 data->set_ishuman(tmpPlayer->GetType() == PLAYER_TYPE_HUMAN);
1303 data->set_playerrights(static_cast<NetPlayerInfoRights>(tmpPlayer->GetRights()));
1304 if (!tmpPlayer->GetCountry().empty()) {
1305 data->set_countrycode(tmpPlayer->GetCountry());
1306 }
1307 if (!tmpPlayer->GetAvatarMD5().IsZero()) {
1308 PlayerInfoReplyMessage::PlayerInfoData::AvatarData *avatarData = data->mutable_avatardata();
1309 avatarData->set_avatartype(static_cast<NetAvatarType>(AvatarManager::GetAvatarFileType(tmpPlayer->GetAvatarFile())));
1310 avatarData->set_avatarhash(tmpPlayer->GetAvatarMD5().GetData(), MD5_DATA_SIZE);
1311 }
1312 } else {
1313 // Unknown player id - do not set any data.
1314 }
1315 GetSender().Send(session, packet);
1316 }
1317 }
1318
1319 void
HandleNetPacketRetrieveAvatar(boost::shared_ptr<SessionData> session,const AvatarRequestMessage & retrieveAvatar)1320 ServerLobbyThread::HandleNetPacketRetrieveAvatar(boost::shared_ptr<SessionData> session, const AvatarRequestMessage &retrieveAvatar)
1321 {
1322 bool avatarFound = false;
1323
1324 string tmpFile;
1325 MD5Buf tmpMD5;
1326 memcpy(tmpMD5.GetData(), retrieveAvatar.avatarhash().data(), MD5_DATA_SIZE);
1327 if (GetAvatarManager().GetAvatarFileName(tmpMD5, tmpFile)) {
1328 NetPacketList tmpPackets;
1329 if (GetAvatarManager().AvatarFileToNetPackets(tmpFile, retrieveAvatar.requestid(), tmpPackets) == 0) {
1330 avatarFound = true;
1331 GetSender().Send(session, tmpPackets);
1332 } else
1333 LOG_ERROR("Failed to read avatar file for network transmission.");
1334 }
1335
1336 if (!avatarFound) {
1337 // Notify client we didn't find the avatar.
1338 boost::shared_ptr<NetPacket> unknownAvatar(new NetPacket);
1339 unknownAvatar->GetMsg()->set_messagetype(PokerTHMessage::Type_UnknownAvatarMessage);
1340 UnknownAvatarMessage *netAvatarReply = unknownAvatar->GetMsg()->mutable_unknownavatarmessage();
1341 netAvatarReply->set_requestid(retrieveAvatar.requestid());
1342
1343 GetSender().Send(session, unknownAvatar);
1344 }
1345 }
1346
1347 void
HandleNetPacketCreateGame(boost::shared_ptr<SessionData> session,const JoinNewGameMessage & newGame)1348 ServerLobbyThread::HandleNetPacketCreateGame(boost::shared_ptr<SessionData> session, const JoinNewGameMessage &newGame)
1349 {
1350 LOG_VERBOSE("Creating new game, initiated by session #" << session->GetId() << ".");
1351
1352 string password;
1353 if (newGame.has_password())
1354 password = newGame.password();
1355
1356 // Create a new game.
1357 GameData tmpData;
1358 NetPacket::GetGameData(newGame.gameinfo(), tmpData);
1359 string gameName(newGame.gameinfo().gamename());
1360 // Always trim the game name.
1361 boost::trim(gameName);
1362 boost::replace_all(gameName, "\n", " ");
1363 boost::replace_all(gameName, "\r", " ");
1364 boost::replace_all(gameName, "\t", " ");
1365 boost::replace_all(gameName, "\v", " ");
1366 boost::replace_all(gameName, "\f", " ");
1367 unsigned gameId = GetNextGameId();
1368
1369 if (gameName.empty() || !isprint(gameName[0])) {
1370 SendJoinGameFailed(session, gameId, NTF_NET_JOIN_GAME_BAD_NAME);
1371 } else if (IsGameNameInUse(gameName)) {
1372 SendJoinGameFailed(session, gameId, NTF_NET_JOIN_GAME_NAME_IN_USE);
1373 } else if (GetBanManager().IsBadGameName(gameName)) {
1374 SendJoinGameFailed(session, gameId, NTF_NET_JOIN_GAME_BAD_NAME);
1375 } else if (session->GetPlayerData()->GetRights() == PLAYER_RIGHTS_GUEST
1376 && tmpData.gameType != GAME_TYPE_NORMAL) {
1377 SendJoinGameFailed(session, gameId, NTF_NET_JOIN_GUEST_FORBIDDEN);
1378 } else if (!ServerGame::CheckSettings(tmpData, password, GetServerMode())) {
1379 SendJoinGameFailed(session, gameId, NTF_NET_JOIN_INVALID_SETTINGS);
1380 } else {
1381 boost::shared_ptr<ServerGame> game(
1382 new ServerGame(
1383 shared_from_this(),
1384 gameId,
1385 gameName,
1386 password,
1387 tmpData,
1388 session->GetPlayerData()->GetUniqueId(),
1389 session->GetPlayerData()->GetDBId(),
1390 GetGui(),
1391 m_serverConfig));
1392 game->Init();
1393
1394 // Add game to list of games.
1395 InternalAddGame(game);
1396
1397 MoveSessionToGame(game, session, newGame.autoleave(), false);
1398 }
1399 }
1400
1401 void
HandleNetPacketJoinGame(boost::shared_ptr<SessionData> session,const JoinExistingGameMessage & joinGame)1402 ServerLobbyThread::HandleNetPacketJoinGame(boost::shared_ptr<SessionData> session, const JoinExistingGameMessage &joinGame)
1403 {
1404 string password;
1405 if (joinGame.has_password())
1406 password = joinGame.password();
1407
1408 // Join an existing game.
1409 GameMap::iterator pos = m_gameMap.find(joinGame.gameid());
1410
1411 if (pos != m_gameMap.end()) {
1412 boost::shared_ptr<ServerGame> game = pos->second;
1413 const GameData &tmpData = game->GetGameData();
1414 if (joinGame.spectateonly()) {
1415 if (!tmpData.allowSpectators) {
1416 SendJoinGameFailed(session, joinGame.gameid(), NTF_NET_JOIN_NO_SPECTATORS);
1417 } else {
1418 MoveSessionToGame(game, session, joinGame.autoleave(), true);
1419 }
1420 } else {
1421 // As guest, you are only allowed to join normal games.
1422 if (session->GetPlayerData()->GetRights() == PLAYER_RIGHTS_GUEST
1423 && tmpData.gameType != GAME_TYPE_NORMAL) {
1424 SendJoinGameFailed(session, joinGame.gameid(), NTF_NET_JOIN_GUEST_FORBIDDEN);
1425 } else if (tmpData.gameType == GAME_TYPE_INVITE_ONLY
1426 && !game->IsPlayerInvited(session->GetPlayerData()->GetUniqueId())) {
1427 SendJoinGameFailed(session, joinGame.gameid(), NTF_NET_JOIN_NOT_INVITED);
1428 } else if (!game->CheckPassword(password)) {
1429 SendJoinGameFailed(session, joinGame.gameid(), NTF_NET_JOIN_INVALID_PASSWORD);
1430 } else if (tmpData.gameType == GAME_TYPE_RANKING
1431 && !joinGame.spectateonly()
1432 && session->GetClientAddr() != SERVER_ADDRESS_LOCALHOST_STR
1433 && session->GetClientAddr() != SERVER_ADDRESS_LOCALHOST_STR_V4V6
1434 && session->GetClientAddr() != SERVER_ADDRESS_LOCALHOST_STR_V4
1435 && game->IsClientAddressConnected(session->GetClientAddr())) {
1436 SendJoinGameFailed(session, joinGame.gameid(), NTF_NET_JOIN_IP_BLOCKED);
1437
1438 } else {
1439 MoveSessionToGame(game, session, joinGame.autoleave(), false);
1440 }
1441 }
1442 } else {
1443 SendJoinGameFailed(session, joinGame.gameid(), NTF_NET_JOIN_GAME_INVALID);
1444 }
1445 }
1446
1447 void
HandleNetPacketRejoinGame(boost::shared_ptr<SessionData> session,const RejoinExistingGameMessage & rejoinGame)1448 ServerLobbyThread::HandleNetPacketRejoinGame(boost::shared_ptr<SessionData> session, const RejoinExistingGameMessage &rejoinGame)
1449 {
1450 // Rejoin a running game.
1451 GameMap::iterator pos = m_gameMap.find(rejoinGame.gameid());
1452
1453 if (pos != m_gameMap.end()) {
1454 boost::shared_ptr<ServerGame> game = pos->second;
1455 MoveSessionToGame(game, session, rejoinGame.autoleave(), false);
1456 } else {
1457 SendJoinGameFailed(session, rejoinGame.gameid(), NTF_NET_JOIN_GAME_INVALID);
1458 }
1459 }
1460
1461 void
HandleNetPacketChatRequest(boost::shared_ptr<SessionData> session,const ChatRequestMessage & chatRequest)1462 ServerLobbyThread::HandleNetPacketChatRequest(boost::shared_ptr<SessionData> session, const ChatRequestMessage &chatRequest)
1463 {
1464 bool chatSent = false;
1465 // Guests are not allowed to chat.
1466 if (session->GetPlayerData() && session->GetPlayerData()->GetRights() != PLAYER_RIGHTS_GUEST) {
1467 if (!chatRequest.has_targetgameid() && !chatRequest.has_targetplayerid()) {
1468 string chatMsg(chatRequest.chattext());
1469
1470 boost::shared_ptr<NetPacket> packet(new NetPacket);
1471 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_ChatMessage);
1472 ChatMessage *netChat = packet->GetMsg()->mutable_chatmessage();
1473 netChat->set_chattype(ChatMessage::chatTypeLobby);
1474 netChat->set_playerid(session->GetPlayerData()->GetUniqueId());
1475 netChat->set_chattext(chatMsg);
1476
1477 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established);
1478 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
1479
1480 // Send the message to the chat cleaner bot.
1481 m_chatCleanerManager->HandleLobbyChatText(
1482 session->GetPlayerData()->GetUniqueId(),
1483 session->GetPlayerData()->GetName(),
1484 chatMsg);
1485 // Send the message to the irc bot.
1486 GetIrcBotCallback().SignalLobbyMessage(
1487 session->GetPlayerData()->GetUniqueId(),
1488 session->GetPlayerData()->GetName(),
1489 chatMsg);
1490 chatSent = true;
1491 } else if (!chatRequest.has_targetgameid() && chatRequest.has_targetplayerid()) {
1492 boost::shared_ptr<SessionData> targetSession = m_sessionManager.GetSessionByUniquePlayerId(chatRequest.targetplayerid());
1493 if (!targetSession)
1494 targetSession = m_gameSessionManager.GetSessionByUniquePlayerId(chatRequest.targetplayerid());
1495
1496 if (targetSession && targetSession->GetPlayerData()) {
1497 // Only allow private messages to players which are not in running games.
1498 boost::shared_ptr<ServerGame> tmpGame = targetSession->GetGame();
1499 if (!tmpGame || !tmpGame->IsRunning()) {
1500 boost::shared_ptr<NetPacket> packet(new NetPacket);
1501 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_ChatMessage);
1502 ChatMessage *netChat = packet->GetMsg()->mutable_chatmessage();
1503 netChat->set_chattype(ChatMessage::chatTypePrivate);
1504 netChat->set_playerid(session->GetPlayerData()->GetUniqueId());
1505 netChat->set_chattext(chatRequest.chattext());
1506
1507 GetSender().Send(targetSession, packet);
1508 chatSent = true;
1509 }
1510 }
1511 }
1512 }
1513 // Other chat types are not allowed in the lobby.
1514 if (!chatSent) {
1515 boost::shared_ptr<NetPacket> packet(new NetPacket);
1516 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_ChatRejectMessage);
1517 ChatRejectMessage *netReject = packet->GetMsg()->mutable_chatrejectmessage();
1518 netReject->set_chattext(chatRequest.chattext());
1519 GetSender().Send(session, packet);
1520 }
1521 }
1522
1523 void
HandleNetPacketRejectGameInvitation(boost::shared_ptr<SessionData> session,const RejectGameInvitationMessage & reject)1524 ServerLobbyThread::HandleNetPacketRejectGameInvitation(boost::shared_ptr<SessionData> session, const RejectGameInvitationMessage &reject)
1525 {
1526 GameMap::iterator pos = m_gameMap.find(reject.gameid());
1527
1528 if (pos != m_gameMap.end() && session->GetPlayerData()) {
1529 ServerGame &game = *pos->second;
1530 unsigned tmpPlayerId = session->GetPlayerData()->GetUniqueId();
1531 if (game.IsPlayerInvited(tmpPlayerId)) {
1532 // If he actively rejects, he is no longer invited.
1533 if (reject.myrejectreason() == RejectGameInvitationMessage::rejectReasonNo) {
1534 game.RemovePlayerInvitation(tmpPlayerId);
1535 }
1536 // Send reject notification.
1537 boost::shared_ptr<NetPacket> packet(new NetPacket);
1538 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_RejectInvNotifyMessage);
1539 RejectInvNotifyMessage *netReject = packet->GetMsg()->mutable_rejectinvnotifymessage();
1540 netReject->set_gameid(reject.gameid());
1541 netReject->set_playerid(tmpPlayerId);
1542 netReject->set_playerrejectreason(reject.myrejectreason());
1543
1544 game.SendToAllPlayers(packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
1545 }
1546 }
1547 }
1548
1549 void
HandleNetPacketReportGame(boost::shared_ptr<SessionData> session,const ReportGameMessage & report)1550 ServerLobbyThread::HandleNetPacketReportGame(boost::shared_ptr<SessionData> session, const ReportGameMessage &report)
1551 {
1552 GameMap::iterator pos = m_gameMap.find(report.reportedgameid());
1553
1554 if (pos != m_gameMap.end() && session->GetPlayerData()) {
1555 boost::shared_ptr<ServerGame> tmpGame(pos->second);
1556 if (!tmpGame->IsNameReported()) {
1557 // Temporarily note that this game was reported.
1558 // This prevents spamming of the game report.
1559 tmpGame->SetNameReported();
1560 unsigned creatorDBId = tmpGame->GetCreatorDBId();
1561 unsigned reporterDBId = session->GetPlayerData()->GetDBId();
1562 GetDatabase()->AsyncReportGame(
1563 session->GetPlayerData()->GetUniqueId(),
1564 tmpGame->GetId(),
1565 creatorDBId != 0 ? &creatorDBId : NULL,
1566 tmpGame->GetId(),
1567 tmpGame->GetName(),
1568 reporterDBId != 0 ? &reporterDBId : NULL
1569 );
1570 } else {
1571 boost::shared_ptr<NetPacket> packet(new NetPacket);
1572 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_ReportGameAckMessage);
1573 ReportGameAckMessage *netReportAck = packet->GetMsg()->mutable_reportgameackmessage();
1574 netReportAck->set_reportedgameid(report.reportedgameid());
1575 netReportAck->set_reportgameresult(ReportGameAckMessage::gameReportDuplicate);
1576 GetSender().Send(session, packet);
1577 }
1578 } else {
1579 boost::shared_ptr<NetPacket> packet(new NetPacket);
1580 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_ReportGameAckMessage);
1581 ReportGameAckMessage *netReportAck = packet->GetMsg()->mutable_reportgameackmessage();
1582 netReportAck->set_reportedgameid(report.reportedgameid());
1583 netReportAck->set_reportgameresult(ReportGameAckMessage::gameReportInvalid);
1584 GetSender().Send(session, packet);
1585 }
1586 }
1587
1588 void
HandleNetPacketAdminRemoveGame(boost::shared_ptr<SessionData> session,const AdminRemoveGameMessage & removeGame)1589 ServerLobbyThread::HandleNetPacketAdminRemoveGame(boost::shared_ptr<SessionData> session, const AdminRemoveGameMessage &removeGame)
1590 {
1591 GameMap::iterator pos = m_gameMap.find(removeGame.removegameid());
1592
1593 // Create Ack-Packet.
1594 boost::shared_ptr<NetPacket> packet(new NetPacket);
1595 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_AdminRemoveGameAckMessage);
1596 AdminRemoveGameAckMessage *netRemoveAck = packet->GetMsg()->mutable_adminremovegameackmessage();
1597 netRemoveAck->set_removegameid(removeGame.removegameid());
1598
1599 // Check whether game id is valid and whether the player is an admin.
1600 if (pos != m_gameMap.end() && session->GetPlayerData() && GetBanManager().IsAdminPlayer(session->GetPlayerData()->GetDBId())) {
1601 LOG_ERROR("Player " << session->GetPlayerData()->GetName() << "(" << session->GetPlayerData()->GetDBId() << ") removes game '" << pos->second->GetName() << "'");
1602 InternalRemoveGame(pos->second);
1603 netRemoveAck->set_removegameresult(AdminRemoveGameAckMessage::gameRemoveAccepted);
1604 } else {
1605 netRemoveAck->set_removegameresult(AdminRemoveGameAckMessage::gameRemoveInvalid);
1606 }
1607 GetSender().Send(session, packet);
1608 }
1609
1610 void
HandleNetPacketAdminBanPlayer(boost::shared_ptr<SessionData> session,const AdminBanPlayerMessage & banPlayer)1611 ServerLobbyThread::HandleNetPacketAdminBanPlayer(boost::shared_ptr<SessionData> session, const AdminBanPlayerMessage &banPlayer)
1612 {
1613 // Create Ack-Packet.
1614 boost::shared_ptr<NetPacket> packet(new NetPacket);
1615 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_AdminBanPlayerAckMessage);
1616 AdminBanPlayerAckMessage *netBanAck = packet->GetMsg()->mutable_adminbanplayerackmessage();
1617 netBanAck->set_banplayerid(banPlayer.banplayerid());
1618
1619 if (session && session->GetPlayerData() && GetBanManager().IsAdminPlayer(session->GetPlayerData()->GetDBId())) {
1620
1621 boost::shared_ptr<SessionData> tmpSession = m_sessionManager.GetSessionByUniquePlayerId(banPlayer.banplayerid());
1622 if (!tmpSession) {
1623 tmpSession = m_gameSessionManager.GetSessionByUniquePlayerId(banPlayer.banplayerid());
1624 }
1625 boost::shared_ptr<PlayerData> tmpPlayer;
1626 if (tmpSession) {
1627 tmpPlayer = tmpSession->GetPlayerData();
1628 }
1629 if (tmpPlayer && !GetBanManager().IsAdminPlayer(tmpPlayer->GetDBId())) {
1630 // Ban the player's IP address for 24 hours.
1631 GetBanManager().BanIPAddress(tmpSession->GetClientAddr(), 24);
1632 // Kick the player.
1633 RemovePlayer(tmpPlayer->GetUniqueId(), ERR_NET_PLAYER_KICKED);
1634 // Permanently ban the player in the database.
1635 if (tmpPlayer->GetDBId() != DB_ID_INVALID) {
1636 LOG_ERROR("Player " << session->GetPlayerData()->GetName() << "(" << session->GetPlayerData()->GetDBId()
1637 << ") bans player " << tmpPlayer->GetName() << "(" << tmpPlayer->GetDBId()
1638 << ") who has IP " << tmpSession->GetClientAddr());
1639 GetDatabase()->AsyncBlockPlayer(session->GetPlayerData()->GetUniqueId(), tmpPlayer->GetUniqueId(), tmpPlayer->GetDBId(), 0, 4);
1640 netBanAck->set_banplayerresult(AdminBanPlayerAckMessage::banPlayerPending);
1641 } else {
1642 netBanAck->set_banplayerresult(AdminBanPlayerAckMessage::banPlayerNoDB);
1643 }
1644 } else {
1645 netBanAck->set_banplayerresult(AdminBanPlayerAckMessage::banPlayerInvalid);
1646 }
1647 } else {
1648 netBanAck->set_banplayerresult(AdminBanPlayerAckMessage::banPlayerInvalid);
1649 }
1650 GetSender().Send(session, packet);
1651 }
1652
1653 void
AuthChallenge(boost::shared_ptr<SessionData> session,const string & secret)1654 ServerLobbyThread::AuthChallenge(boost::shared_ptr<SessionData> session, const string &secret)
1655 {
1656 if (session && session->GetPlayerData() && session->AuthGetCurStepNum() == 1) {
1657 session->AuthSetPassword(secret); // For this auth session.
1658 string outChallenge(session->AuthGetNextOutMsg());
1659
1660 boost::shared_ptr<NetPacket> packet(new NetPacket);
1661 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_AuthServerChallengeMessage);
1662 AuthServerChallengeMessage *challenge = packet->GetMsg()->mutable_authserverchallengemessage();
1663 challenge->set_serverchallenge(outChallenge);
1664 GetSender().Send(session, packet);
1665 }
1666 }
1667
1668 void
CheckAvatarBlacklist(boost::shared_ptr<SessionData> session)1669 ServerLobbyThread::CheckAvatarBlacklist(boost::shared_ptr<SessionData> session)
1670 {
1671 if (session && session->GetPlayerData()) {
1672 const MD5Buf &avatarMD5 = session->GetPlayerData()->GetAvatarMD5();
1673 if (!avatarMD5.IsZero())
1674 m_database->AsyncCheckAvatarBlacklist(session->GetPlayerData()->GetUniqueId(), avatarMD5.ToString());
1675 else
1676 InitAfterLogin(session);
1677 }
1678 }
1679
1680 void
AvatarBlacklisted(unsigned playerId)1681 ServerLobbyThread::AvatarBlacklisted(unsigned playerId)
1682 {
1683 boost::shared_ptr<SessionData> tmpSession = m_sessionManager.GetSessionByUniquePlayerId(playerId, true);
1684 if (tmpSession && tmpSession->GetPlayerData()) {
1685 tmpSession->GetPlayerData()->SetAvatarMD5(MD5Buf()); // Reset avatar if blacklisted.
1686 InitAfterLogin(tmpSession);
1687 }
1688 }
1689
1690 void
AvatarOK(unsigned playerId)1691 ServerLobbyThread::AvatarOK(unsigned playerId)
1692 {
1693 boost::shared_ptr<SessionData> tmpSession = m_sessionManager.GetSessionByUniquePlayerId(playerId, true);
1694 InitAfterLogin(tmpSession);
1695 }
1696
1697 void
InitAfterLogin(boost::shared_ptr<SessionData> session)1698 ServerLobbyThread::InitAfterLogin(boost::shared_ptr<SessionData> session)
1699 {
1700 if (session && session->GetPlayerData()) {
1701 const MD5Buf &avatarMD5 = session->GetPlayerData()->GetAvatarMD5();
1702 string avatarFileName;
1703 if (!avatarMD5.IsZero()
1704 && !GetAvatarManager().GetAvatarFileName(avatarMD5, avatarFileName)) {
1705 RequestPlayerAvatar(session);
1706 } else {
1707 if (!avatarFileName.empty())
1708 session->GetPlayerData()->SetAvatarFile(avatarFileName);
1709 EstablishSession(session);
1710 }
1711 }
1712 }
1713
1714 void
EstablishSession(boost::shared_ptr<SessionData> session)1715 ServerLobbyThread::EstablishSession(boost::shared_ptr<SessionData> session)
1716 {
1717 if (!session->GetPlayerData())
1718 throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
1719
1720 unsigned rejoinPlayerId = 0;
1721 u_int32_t rejoinGameId = GetRejoinGameIdForPlayer(session->GetPlayerData()->GetName(), session->GetPlayerData()->GetOldGuid(), rejoinPlayerId);
1722 if (rejoinGameId != 0) {
1723 // Offer rejoin, and disconnect current player with the same name.
1724 InternalRemovePlayer(rejoinPlayerId, ERR_NET_PLAYER_NAME_IN_USE);
1725 } else {
1726 // Check whether this player is already connected.
1727 unsigned previousPlayerId = GetPlayerId(session->GetPlayerData()->GetName());
1728 if (previousPlayerId != 0 && previousPlayerId != session->GetPlayerData()->GetUniqueId()) {
1729 #ifdef POKERTH_OFFICIAL_SERVER
1730 // If this is a login server with a websocket connection, decline connection.
1731 if (session->GetWebData()) {
1732 SessionError(session, ERR_NET_PLAYER_NAME_IN_USE);
1733 return;
1734 } else {
1735 // If this is not a websocket connection, disconnect the already connected player.
1736 InternalRemovePlayer(previousPlayerId, ERR_NET_PLAYER_NAME_IN_USE);
1737 }
1738 #else
1739 // If this is a server without password protection, close this new session and return.
1740 SessionError(session, ERR_NET_PLAYER_NAME_IN_USE);
1741 return;
1742 #endif
1743 }
1744 }
1745
1746 // Run postlogin for DB
1747 string tmpAvatarHash;
1748 string tmpAvatarType;
1749 if (!session->GetPlayerData()->GetAvatarMD5().IsZero()) {
1750 tmpAvatarHash = session->GetPlayerData()->GetAvatarMD5().ToString();
1751 tmpAvatarType = AvatarManager::GetAvatarFileExtension(AvatarManager::GetAvatarFileType(session->GetPlayerData()->GetAvatarFile()));
1752 if (!tmpAvatarType.empty())
1753 tmpAvatarType.erase(0, 1); // Only store extension without the "."
1754 }
1755 m_database->PlayerPostLogin(session->GetPlayerData()->GetDBId(), tmpAvatarHash, tmpAvatarType);
1756
1757 // Generate a new GUID.
1758 boost::uuids::uuid sessionGuid(m_sessionIdGenerator());
1759 session->GetPlayerData()->SetGuid(string((char *)&sessionGuid, boost::uuids::uuid::static_size()));
1760
1761 // Send ACK to client.
1762 boost::shared_ptr<NetPacket> ack(new NetPacket);
1763 ack->GetMsg()->set_messagetype(PokerTHMessage::Type_InitAckMessage);
1764 InitAckMessage *netInitAck = ack->GetMsg()->mutable_initackmessage();
1765 netInitAck->set_yoursessionid(session->GetPlayerData()->GetGuid());
1766 netInitAck->set_yourplayerid(session->GetPlayerData()->GetUniqueId());
1767 if (rejoinGameId != 0) {
1768 netInitAck->set_rejoingameid(rejoinGameId);
1769 }
1770 GetSender().Send(session, ack);
1771
1772 // Send the connected players list to the client.
1773 SendPlayerList(session);
1774 // Send the game list to the client.
1775 SendGameList(session);
1776
1777 // Session is now established.
1778 session->SetState(SessionData::Established);
1779
1780 {
1781 boost::mutex::scoped_lock lock(m_statMutex);
1782 ++m_statData.totalPlayersEverLoggedIn;
1783 m_statDataChanged = true;
1784 }
1785 // Notify all players.
1786 NotifyPlayerJoinedLobby(session->GetPlayerData()->GetUniqueId());
1787
1788 UpdateStatisticsNumberOfPlayers();
1789 }
1790
1791 void
AuthenticatePlayer(boost::shared_ptr<SessionData> session)1792 ServerLobbyThread::AuthenticatePlayer(boost::shared_ptr<SessionData> session)
1793 {
1794 if(session->GetPlayerData()) {
1795 m_database->AsyncPlayerLogin(session->GetPlayerData()->GetUniqueId(), session->GetPlayerData()->GetName());
1796 }
1797 }
1798
1799 void
UserValid(unsigned playerId,const DBPlayerData & dbPlayerData)1800 ServerLobbyThread::UserValid(unsigned playerId, const DBPlayerData &dbPlayerData)
1801 {
1802 boost::shared_ptr<SessionData> tmpSession = m_sessionManager.GetSessionByUniquePlayerId(playerId, true);
1803 if (tmpSession && tmpSession->GetPlayerData()) {
1804 tmpSession->GetPlayerData()->SetDBId(dbPlayerData.id);
1805 tmpSession->GetPlayerData()->SetCountry(dbPlayerData.country);
1806 this->AuthChallenge(tmpSession, dbPlayerData.secret);
1807 }
1808 }
1809
1810 void
UserInvalid(unsigned playerId)1811 ServerLobbyThread::UserInvalid(unsigned playerId)
1812 {
1813 SessionError(m_sessionManager.GetSessionByUniquePlayerId(playerId, true), ERR_NET_INVALID_PASSWORD);
1814 }
1815
1816 void
SendReportAvatarResult(unsigned byPlayerId,unsigned reportedPlayerId,bool success)1817 ServerLobbyThread::SendReportAvatarResult(unsigned byPlayerId, unsigned reportedPlayerId, bool success)
1818 {
1819 boost::shared_ptr<SessionData> session = m_sessionManager.GetSessionByUniquePlayerId(byPlayerId);
1820 if (!session)
1821 session = m_gameSessionManager.GetSessionByUniquePlayerId(byPlayerId);
1822 if (session) {
1823 boost::shared_ptr<NetPacket> packet(new NetPacket);
1824 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_ReportAvatarAckMessage);
1825 ReportAvatarAckMessage *netReportAck = packet->GetMsg()->mutable_reportavatarackmessage();
1826 netReportAck->set_reportedplayerid(reportedPlayerId);
1827 netReportAck->set_reportavatarresult(success ? ReportAvatarAckMessage::avatarReportAccepted : ReportAvatarAckMessage::avatarReportInvalid);
1828 GetSender().Send(session, packet);
1829 }
1830 }
1831
1832 void
SendReportGameResult(unsigned byPlayerId,unsigned reportedGameId,bool success)1833 ServerLobbyThread::SendReportGameResult(unsigned byPlayerId, unsigned reportedGameId, bool success)
1834 {
1835 boost::shared_ptr<SessionData> session = m_sessionManager.GetSessionByUniquePlayerId(byPlayerId);
1836 if (!session)
1837 session = m_gameSessionManager.GetSessionByUniquePlayerId(byPlayerId);
1838 if (session) {
1839 boost::shared_ptr<NetPacket> packet(new NetPacket);
1840 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_ReportGameAckMessage);
1841 ReportGameAckMessage *netReportAck = packet->GetMsg()->mutable_reportgameackmessage();
1842 netReportAck->set_reportedgameid(reportedGameId);
1843 netReportAck->set_reportgameresult(success ? ReportGameAckMessage::gameReportAccepted : ReportGameAckMessage::gameReportInvalid);
1844 GetSender().Send(session, packet);
1845 }
1846 }
1847
1848 void
SendAdminBanPlayerResult(unsigned byPlayerId,unsigned reportedPlayerId,bool success)1849 ServerLobbyThread::SendAdminBanPlayerResult(unsigned byPlayerId, unsigned reportedPlayerId, bool success)
1850 {
1851 boost::shared_ptr<SessionData> session = m_sessionManager.GetSessionByUniquePlayerId(byPlayerId);
1852 if (!session)
1853 session = m_gameSessionManager.GetSessionByUniquePlayerId(byPlayerId);
1854 if (session) {
1855 boost::shared_ptr<NetPacket> packet(new NetPacket);
1856 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_AdminBanPlayerAckMessage);
1857 AdminBanPlayerAckMessage *netBanAck = packet->GetMsg()->mutable_adminbanplayerackmessage();
1858 netBanAck->set_banplayerid(reportedPlayerId);
1859 netBanAck->set_banplayerresult(success ? AdminBanPlayerAckMessage::banPlayerAccepted : AdminBanPlayerAckMessage::banPlayerDBError);
1860 GetSender().Send(session, packet);
1861 }
1862 }
1863
1864 void
UserBlocked(unsigned playerId)1865 ServerLobbyThread::UserBlocked(unsigned playerId)
1866 {
1867 SessionError(m_sessionManager.GetSessionByUniquePlayerId(playerId, true), ERR_NET_PLAYER_BLOCKED);
1868 }
1869
1870 void
RequestPlayerAvatar(boost::shared_ptr<SessionData> session)1871 ServerLobbyThread::RequestPlayerAvatar(boost::shared_ptr<SessionData> session)
1872 {
1873 if (!session->GetPlayerData())
1874 throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
1875 // Ask the client to send its avatar.
1876 boost::shared_ptr<NetPacket> packet(new NetPacket);
1877 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_AvatarRequestMessage);
1878 AvatarRequestMessage *netAvatarRequest = packet->GetMsg()->mutable_avatarrequestmessage();
1879 netAvatarRequest->set_requestid(session->GetPlayerData()->GetUniqueId());
1880 netAvatarRequest->set_avatarhash(session->GetPlayerData()->GetAvatarMD5().GetData(), MD5_DATA_SIZE);
1881
1882 GetSender().Send(session, packet);
1883 }
1884
1885 void
TimerRemoveGame(const boost::system::error_code & ec)1886 ServerLobbyThread::TimerRemoveGame(const boost::system::error_code &ec)
1887 {
1888 if (!ec) {
1889 // Synchronously remove games which have been closed.
1890 GameMap::iterator i = m_gameMap.begin();
1891 GameMap::iterator end = m_gameMap.end();
1892 while (i != end) {
1893 GameMap::iterator next = i;
1894 ++next;
1895 boost::shared_ptr<ServerGame> tmpGame = i->second;
1896 if (!tmpGame->GetSessionManager().HasSessionWithState(SessionData::Game)) {
1897 tmpGame->MoveSpectatorsToLobby();
1898 InternalRemoveGame(tmpGame); // This will delete the game.
1899 }
1900 i = next;
1901 }
1902 // Restart timer
1903 m_removeGameTimer.expires_from_now(
1904 milliseconds(SERVER_REMOVE_GAME_INTERVAL_MSEC));
1905 m_removeGameTimer.async_wait(
1906 boost::bind(
1907 &ServerLobbyThread::TimerRemoveGame, shared_from_this(), boost::asio::placeholders::error));
1908 }
1909 }
1910
1911 void
TimerUpdateClientLoginLock(const boost::system::error_code & ec)1912 ServerLobbyThread::TimerUpdateClientLoginLock(const boost::system::error_code &ec)
1913 {
1914 if (!ec) {
1915 boost::mutex::scoped_lock lock(m_timerClientAddressMapMutex);
1916
1917 TimerClientAddressMap::iterator i = m_timerClientAddressMap.begin();
1918 TimerClientAddressMap::iterator end = m_timerClientAddressMap.end();
1919
1920 while (i != end) {
1921 TimerClientAddressMap::iterator next = i;
1922 ++next;
1923 if (i->second.elapsed().total_seconds() > (int)SERVER_INIT_LOGIN_CLIENT_LOCK_SEC)
1924 m_timerClientAddressMap.erase(i);
1925 i = next;
1926 }
1927 // Restart timer
1928 m_loginLockTimer.expires_from_now(
1929 milliseconds(SERVER_UPDATE_LOGIN_LOCK_INTERVAL_MSEC));
1930 m_loginLockTimer.async_wait(
1931 boost::bind(
1932 &ServerLobbyThread::TimerUpdateClientLoginLock, shared_from_this(), boost::asio::placeholders::error));
1933 }
1934 }
1935
1936 bool
IsGameNameInUse(const std::string & gameName) const1937 ServerLobbyThread::IsGameNameInUse(const std::string &gameName) const
1938 {
1939 bool found = false;
1940 GameMap::const_iterator i = m_gameMap.begin();
1941 GameMap::const_iterator end = m_gameMap.end();
1942
1943 while (i != end) {
1944 if ((*i).second->GetName() == gameName) {
1945 found = true;
1946 break;
1947 }
1948 ++i;
1949 }
1950 return found;
1951 }
1952
1953 boost::shared_ptr<ServerGame>
InternalGetGameFromId(unsigned gameId)1954 ServerLobbyThread::InternalGetGameFromId(unsigned gameId)
1955 {
1956 boost::shared_ptr<ServerGame> game;
1957 if (gameId) {
1958 GameMap::iterator pos = m_gameMap.find(gameId);
1959
1960 if (pos != m_gameMap.end())
1961 game = pos->second;
1962 }
1963 return game;
1964 }
1965
1966 void
InternalAddGame(boost::shared_ptr<ServerGame> game)1967 ServerLobbyThread::InternalAddGame(boost::shared_ptr<ServerGame> game)
1968 {
1969 // Add game to list.
1970 m_gameMap.insert(GameMap::value_type(game->GetId(), game));
1971 // Notify all players.
1972 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Established);
1973 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
1974
1975 {
1976 boost::mutex::scoped_lock lock(m_statMutex);
1977 ++m_statData.totalGamesEverCreated;
1978 ++m_statData.numberOfGamesOpen;
1979 unsigned numGames = static_cast<unsigned>(m_gameMap.size());
1980 if (numGames > m_statData.maxGamesOpen)
1981 m_statData.maxGamesOpen = numGames;
1982 m_statDataChanged = true;
1983 }
1984 }
1985
1986 void
InternalRemoveGame(boost::shared_ptr<ServerGame> game)1987 ServerLobbyThread::InternalRemoveGame(boost::shared_ptr<ServerGame> game)
1988 {
1989 {
1990 boost::mutex::scoped_lock lock(m_statMutex);
1991 if (m_statData.numberOfGamesOpen) {
1992 --m_statData.numberOfGamesOpen;
1993 m_statDataChanged = true;
1994 }
1995 }
1996 // Remove game from list.
1997 m_gameMap.erase(game->GetId());
1998 // Remove all sessions left in the game.
1999 game->ResetComputerPlayerList();
2000 game->RemoveAllSessions();
2001 game->Exit();
2002 // Notify all players.
2003 boost::shared_ptr<NetPacket> packet = CreateNetPacketGameListUpdate(game->GetId(), GAME_MODE_CLOSED);
2004 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established);
2005 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
2006 }
2007
2008 void
InternalRemovePlayer(unsigned playerId,unsigned errorCode)2009 ServerLobbyThread::InternalRemovePlayer(unsigned playerId, unsigned errorCode)
2010 {
2011 boost::shared_ptr<SessionData> session = m_sessionManager.GetSessionByUniquePlayerId(playerId, true);
2012 if (session)
2013 SessionError(session, errorCode);
2014 else {
2015 // Remove player from game.
2016 boost::shared_ptr<SessionData> session = m_gameSessionManager.GetSessionByUniquePlayerId(playerId);
2017 if (session) {
2018 boost::shared_ptr<ServerGame> tmpGame = session->GetGame();
2019 if (tmpGame) {
2020 tmpGame->RemovePlayer(playerId, errorCode);
2021 }
2022 }
2023 }
2024 }
2025
2026 void
InternalMutePlayerInGame(unsigned playerId)2027 ServerLobbyThread::InternalMutePlayerInGame(unsigned playerId)
2028 {
2029 boost::shared_ptr<SessionData> session = m_gameSessionManager.GetSessionByUniquePlayerId(playerId);
2030 if (session) {
2031 boost::shared_ptr<ServerGame> tmpGame = session->GetGame();
2032 if (tmpGame) {
2033 tmpGame->MutePlayer(playerId, true);
2034 }
2035 }
2036 }
2037
2038 void
InternalResubscribeMsg(boost::shared_ptr<SessionData> session)2039 ServerLobbyThread::InternalResubscribeMsg(boost::shared_ptr<SessionData> session)
2040 {
2041 if (!session->WantsLobbyMsg()) {
2042 session->SetWantsLobbyMsg();
2043 SendPlayerList(session);
2044 SendGameList(session);
2045 // Send new statistics information.
2046 /* boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
2047 packet->GetMsg()->present = PokerTHMessage_PR_statisticsMessage;
2048 StatisticsMessage_t *netStatistics = &packet->GetMsg()->choice.statisticsMessage;
2049
2050 StatisticsData_t *data = (StatisticsData_t *)calloc(1, sizeof(struct StatisticsData));
2051 data->statisticsType = statisticsType_statNumberOfPlayers;
2052 data->statisticsValue = m_sessionManager.GetRawSessionCount() + m_gameSessionManager.GetRawSessionCount();
2053 ASN_SEQUENCE_ADD(&netStatistics->statisticsData.list, data);
2054
2055 GetSender().Send(session, packet);*/
2056 }
2057 }
2058
2059 void
HandleReAddedSession(boost::shared_ptr<SessionData> session)2060 ServerLobbyThread::HandleReAddedSession(boost::shared_ptr<SessionData> session)
2061 {
2062 // Remove session from game session list.
2063 m_gameSessionManager.RemoveSession(session->GetId());
2064
2065 if (m_sessionManager.GetRawSessionCount() <= SERVER_MAX_NUM_LOBBY_SESSIONS) {
2066 // Set state (back) to established.
2067 session->SetState(SessionData::Established);
2068 session->SetGame(boost::shared_ptr<ServerGame>());
2069 // Add session to lobby list.
2070 m_sessionManager.AddSession(session);
2071 } else {
2072 // Gracefully close this session.
2073 SessionError(session, ERR_NET_SERVER_FULL);
2074 }
2075 }
2076
2077 void
SessionTimeoutWarning(boost::shared_ptr<SessionData> session,unsigned remainingSec)2078 ServerLobbyThread::SessionTimeoutWarning(boost::shared_ptr<SessionData> session, unsigned remainingSec)
2079 {
2080 boost::shared_ptr<NetPacket> packet(new NetPacket);
2081 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_TimeoutWarningMessage);
2082 TimeoutWarningMessage *netWarning = packet->GetMsg()->mutable_timeoutwarningmessage();
2083 netWarning->set_timeoutreason(TimeoutWarningMessage::timeoutNoDataReceived);
2084 netWarning->set_remainingseconds(remainingSec);
2085 GetSender().Send(session, packet);
2086
2087 if (session->GetGame() && session->GetPlayerData()) {
2088 session->GetGame()->MarkPlayerAsInactive(session->GetPlayerData()->GetUniqueId());
2089 }
2090 }
2091
2092 void
SessionError(boost::shared_ptr<SessionData> session,int errorCode)2093 ServerLobbyThread::SessionError(boost::shared_ptr<SessionData> session, int errorCode)
2094 {
2095 if (session) {
2096 if (errorCode == ERR_NET_PLAYER_KICKED || errorCode == ERR_NET_SESSION_TIMED_OUT) {
2097 if (session->GetGame() && session->GetPlayerData()) {
2098 session->GetGame()->MarkPlayerAsKicked(session->GetPlayerData()->GetUniqueId());
2099 }
2100 }
2101
2102 SendError(session, errorCode);
2103 CloseSession(session);
2104 }
2105 }
2106
2107 void
SendError(boost::shared_ptr<SessionData> s,int errorCode)2108 ServerLobbyThread::SendError(boost::shared_ptr<SessionData> s, int errorCode)
2109 {
2110 LOG_VERBOSE("Sending error code " << errorCode << " to session #" << s->GetId() << ".");
2111 boost::shared_ptr<NetPacket> packet(new NetPacket);
2112 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_ErrorMessage);
2113 ErrorMessage *netError = packet->GetMsg()->mutable_errormessage();
2114 netError->set_errorreason(NetPacket::GameErrorToNetError(errorCode));
2115 GetSender().Send(s, packet);
2116 }
2117
2118 void
SendJoinGameFailed(boost::shared_ptr<SessionData> s,unsigned gameId,int reason)2119 ServerLobbyThread::SendJoinGameFailed(boost::shared_ptr<SessionData> s, unsigned gameId, int reason)
2120 {
2121 boost::shared_ptr<NetPacket> packet(new NetPacket);
2122 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_JoinGameFailedMessage);
2123 JoinGameFailedMessage *netJoinFailed = packet->GetMsg()->mutable_joingamefailedmessage();
2124 netJoinFailed->set_gameid(gameId);
2125
2126 switch (reason) {
2127 case NTF_NET_JOIN_GAME_FULL :
2128 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::gameIsFull);
2129 break;
2130 case NTF_NET_JOIN_ALREADY_RUNNING :
2131 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::gameIsRunning);
2132 break;
2133 case NTF_NET_JOIN_INVALID_PASSWORD :
2134 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::invalidPassword);
2135 break;
2136 case NTF_NET_JOIN_GUEST_FORBIDDEN :
2137 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::notAllowedAsGuest);
2138 break;
2139 case NTF_NET_JOIN_NOT_INVITED :
2140 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::notInvited);
2141 break;
2142 case NTF_NET_JOIN_GAME_NAME_IN_USE :
2143 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::gameNameInUse);
2144 break;
2145 case NTF_NET_JOIN_GAME_BAD_NAME :
2146 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::badGameName);
2147 break;
2148 case NTF_NET_JOIN_INVALID_SETTINGS :
2149 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::invalidSettings);
2150 break;
2151 case NTF_NET_JOIN_IP_BLOCKED :
2152 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::ipAddressBlocked);
2153 break;
2154 case NTF_NET_JOIN_REJOIN_FAILED :
2155 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::rejoinFailed);
2156 break;
2157 case NTF_NET_JOIN_NO_SPECTATORS :
2158 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::noSpectatorsAllowed);
2159 break;
2160 default :
2161 netJoinFailed->set_joingamefailurereason(JoinGameFailedMessage::invalidGame);
2162 break;
2163 }
2164 GetSender().Send(s, packet);
2165 }
2166
2167 void
SendPlayerList(boost::shared_ptr<SessionData> s)2168 ServerLobbyThread::SendPlayerList(boost::shared_ptr<SessionData> s)
2169 {
2170 // Retrieve all player ids.
2171 PlayerIdList idList(m_sessionManager.GetPlayerIdList(SessionData::Established));
2172 PlayerIdList gameIdList(m_gameSessionManager.GetPlayerIdList(SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting));
2173 idList.splice(idList.begin(), gameIdList);
2174 // Send all player ids to client.
2175 PlayerIdList::const_iterator i = idList.begin();
2176 PlayerIdList::const_iterator end = idList.end();
2177 while (i != end) {
2178 GetSender().Send(s, CreateNetPacketPlayerListNew(*i));
2179 ++i;
2180 }
2181 }
2182
2183 void
SendGameList(boost::shared_ptr<SessionData> s)2184 ServerLobbyThread::SendGameList(boost::shared_ptr<SessionData> s)
2185 {
2186 GameMap::const_iterator game_i = m_gameMap.begin();
2187 GameMap::const_iterator game_end = m_gameMap.end();
2188 while (game_i != game_end) {
2189 GetSender().Send(s, CreateNetPacketGameListNew(*game_i->second));
2190 ++game_i;
2191 }
2192 }
2193
2194 void
UpdateStatisticsNumberOfPlayers()2195 ServerLobbyThread::UpdateStatisticsNumberOfPlayers()
2196 {
2197 ServerStats stats;
2198 // Get all logged-in sessions and all sessions within a game.
2199 unsigned curNumberOfPlayersOnServer = m_sessionManager.GetSessionCountWithState(SessionData::Established) + m_gameSessionManager.GetRawSessionCount();
2200 {
2201 boost::mutex::scoped_lock lock(m_statMutex);
2202 if (curNumberOfPlayersOnServer != m_statData.numberOfPlayersOnServer) {
2203 m_statData.numberOfPlayersOnServer = stats.numberOfPlayersOnServer = curNumberOfPlayersOnServer;
2204 if (curNumberOfPlayersOnServer > m_statData.maxPlayersLoggedIn)
2205 m_statData.maxPlayersLoggedIn = curNumberOfPlayersOnServer;
2206 m_statDataChanged = true;
2207 }
2208 }
2209 // Do not send other stats than number of players for now.
2210 //BroadcastStatisticsUpdate(stats);
2211 }
2212
2213 void
BroadcastStatisticsUpdate(const ServerStats & stats)2214 ServerLobbyThread::BroadcastStatisticsUpdate(const ServerStats &stats)
2215 {
2216 if (stats.numberOfPlayersOnServer) {
2217 boost::shared_ptr<NetPacket> packet(new NetPacket);
2218 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_StatisticsMessage);
2219 StatisticsMessage *netStatistics = packet->GetMsg()->mutable_statisticsmessage();
2220
2221 StatisticsMessage::StatisticsData *data = netStatistics->add_statisticsdata();
2222 data->set_statisticstype(StatisticsMessage::StatisticsData::statNumberOfPlayers);
2223 data->set_statisticsvalue(m_sessionManager.GetRawSessionCount() + m_gameSessionManager.GetRawSessionCount());
2224
2225 m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established);
2226 m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game | SessionData::Spectating | SessionData::SpectatorWaiting);
2227 }
2228 }
2229
2230 void
ReadStatisticsFile()2231 ServerLobbyThread::ReadStatisticsFile()
2232 {
2233 ifstream i(m_statisticsFileName.c_str(), ios_base::in);
2234
2235 if (!i.fail() && !i.eof()) {
2236 boost::mutex::scoped_lock lock(m_statMutex);
2237 do {
2238 string statisticsType;
2239 unsigned statisticsValue;
2240 i >> statisticsType;
2241 i >> statisticsValue;
2242 if (statisticsType == SERVER_STATISTICS_STR_TOTAL_PLAYERS)
2243 m_statData.totalPlayersEverLoggedIn = statisticsValue;
2244 else if (statisticsType == SERVER_STATISTICS_STR_TOTAL_GAMES)
2245 m_statData.totalGamesEverCreated = statisticsValue;
2246 else if (statisticsType == SERVER_STATISTICS_STR_MAX_PLAYERS)
2247 m_statData.maxPlayersLoggedIn = statisticsValue;
2248 else if (statisticsType == SERVER_STATISTICS_STR_MAX_GAMES)
2249 m_statData.maxGamesOpen = statisticsValue;
2250 // other statistics are non-persistant and not read.
2251 } while (!i.fail() && !i.eof());
2252 m_statDataChanged = false;
2253 }
2254 }
2255
2256 void
TimerSaveStatisticsFile(const boost::system::error_code & ec)2257 ServerLobbyThread::TimerSaveStatisticsFile(const boost::system::error_code &ec)
2258 {
2259 if (!ec) {
2260 LOG_VERBOSE("Saving statistics.");
2261 boost::mutex::scoped_lock lock(m_statMutex);
2262 if (m_statDataChanged) {
2263 ofstream o(m_statisticsFileName.c_str(), ios_base::out | ios_base::trunc);
2264 if (!o.fail()) {
2265 o << SERVER_STATISTICS_STR_TOTAL_PLAYERS " " << m_statData.totalPlayersEverLoggedIn << endl;
2266 o << SERVER_STATISTICS_STR_TOTAL_GAMES " " << m_statData.totalGamesEverCreated << endl;
2267 o << SERVER_STATISTICS_STR_MAX_PLAYERS " " << m_statData.maxPlayersLoggedIn << endl;
2268 o << SERVER_STATISTICS_STR_MAX_GAMES " " << m_statData.maxGamesOpen << endl;
2269 o << SERVER_STATISTICS_STR_CUR_PLAYERS " " << m_statData.numberOfPlayersOnServer << endl;
2270 o << SERVER_STATISTICS_STR_CUR_GAMES " " << m_statData.numberOfGamesOpen << endl;
2271 m_statDataChanged = false;
2272 }
2273 }
2274 // Restart timer
2275 m_saveStatisticsTimer.expires_from_now(
2276 seconds(SERVER_SAVE_STATISTICS_INTERVAL_SEC));
2277 m_saveStatisticsTimer.async_wait(
2278 boost::bind(
2279 &ServerLobbyThread::TimerSaveStatisticsFile, shared_from_this(), boost::asio::placeholders::error));
2280 }
2281 }
2282
2283 ServerCallback &
GetCallback()2284 ServerLobbyThread::GetCallback()
2285 {
2286 return m_gui;
2287 }
2288
2289 ServerIrcBotCallback &
GetIrcBotCallback()2290 ServerLobbyThread::GetIrcBotCallback()
2291 {
2292 return m_ircBotCb;
2293 }
2294
2295 InternalServerCallback &
GetSenderCallback()2296 ServerLobbyThread::GetSenderCallback()
2297 {
2298 assert(m_internalServerCallback.get());
2299 return *m_internalServerCallback;
2300 }
2301
2302 GuiInterface &
GetGui()2303 ServerLobbyThread::GetGui()
2304 {
2305 return m_gui;
2306 }
2307
2308 unsigned
GetPlayerId(const string & name) const2309 ServerLobbyThread::GetPlayerId(const string &name) const
2310 {
2311 unsigned playerId = 0;
2312
2313 boost::shared_ptr<SessionData> tmpSession(m_sessionManager.GetSessionByPlayerName(name));
2314
2315 if (!tmpSession)
2316 tmpSession = m_gameSessionManager.GetSessionByPlayerName(name);
2317
2318 if (tmpSession && tmpSession->GetPlayerData())
2319 playerId = tmpSession->GetPlayerData()->GetUniqueId();
2320
2321 return playerId;
2322 }
2323
2324 boost::shared_ptr<NetPacket>
CreateNetPacketPlayerListNew(unsigned playerId)2325 ServerLobbyThread::CreateNetPacketPlayerListNew(unsigned playerId)
2326 {
2327 boost::shared_ptr<NetPacket> packet(new NetPacket);
2328 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_PlayerListMessage);
2329 PlayerListMessage *netPlayerList = packet->GetMsg()->mutable_playerlistmessage();
2330 netPlayerList->set_playerid(playerId);
2331 netPlayerList->set_playerlistnotification(PlayerListMessage::playerListNew);
2332 return packet;
2333 }
2334
2335 boost::shared_ptr<NetPacket>
CreateNetPacketPlayerListLeft(unsigned playerId)2336 ServerLobbyThread::CreateNetPacketPlayerListLeft(unsigned playerId)
2337 {
2338 boost::shared_ptr<NetPacket> packet(new NetPacket);
2339 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_PlayerListMessage);
2340 PlayerListMessage *netPlayerList = packet->GetMsg()->mutable_playerlistmessage();
2341 netPlayerList->set_playerid(playerId);
2342 netPlayerList->set_playerlistnotification(PlayerListMessage::playerListLeft);
2343 return packet;
2344 }
2345
2346 boost::shared_ptr<NetPacket>
CreateNetPacketGameListNew(const ServerGame & game)2347 ServerLobbyThread::CreateNetPacketGameListNew(const ServerGame &game)
2348 {
2349 boost::shared_ptr<NetPacket> packet(new NetPacket);
2350 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_GameListNewMessage);
2351 GameListNewMessage *netGameList = packet->GetMsg()->mutable_gamelistnewmessage();
2352 netGameList->set_gameid(game.GetId());
2353 netGameList->set_adminplayerid(game.GetAdminPlayerId());
2354 netGameList->set_gamemode(game.IsRunning() ? netGameStarted : netGameCreated);
2355 NetPacket::SetGameData(game.GetGameData(), *netGameList->mutable_gameinfo());
2356 netGameList->mutable_gameinfo()->set_gamename(game.GetName());
2357 netGameList->set_isprivate(game.IsPasswordProtected());
2358
2359 PlayerIdList tmpList = game.GetPlayerIdList();
2360 PlayerIdList::const_iterator i = tmpList.begin();
2361 PlayerIdList::const_iterator end = tmpList.end();
2362 while (i != end) {
2363 netGameList->add_playerids(*i);
2364 ++i;
2365 }
2366
2367 tmpList = game.GetSpectatorIdList();
2368 i = tmpList.begin();
2369 end = tmpList.end();
2370 while (i != end) {
2371 netGameList->add_spectatorids(*i);
2372 ++i;
2373 }
2374
2375 return packet;
2376 }
2377
2378 boost::shared_ptr<NetPacket>
CreateNetPacketGameListUpdate(unsigned gameId,GameMode mode)2379 ServerLobbyThread::CreateNetPacketGameListUpdate(unsigned gameId, GameMode mode)
2380 {
2381 boost::shared_ptr<NetPacket> packet(new NetPacket);
2382 packet->GetMsg()->set_messagetype(PokerTHMessage::Type_GameListUpdateMessage);
2383 GameListUpdateMessage *netGameList = packet->GetMsg()->mutable_gamelistupdatemessage();
2384 netGameList->set_gameid(gameId);
2385 netGameList->set_gamemode(static_cast<NetGameMode>(mode));
2386 return packet;
2387 }
2388
2389 u_int32_t
GetRejoinGameIdForPlayer(const std::string & playerName,const std::string & guid,unsigned & outPlayerUniqueId)2390 ServerLobbyThread::GetRejoinGameIdForPlayer(const std::string &playerName, const std::string &guid, unsigned &outPlayerUniqueId)
2391 {
2392 u_int32_t retGameId = 0;
2393 if (!guid.empty()) {
2394 GameMap::iterator i = m_gameMap.begin();
2395 GameMap::iterator end = m_gameMap.end();
2396 while (i != end) {
2397 boost::shared_ptr<ServerGame> tmpGame = i->second;
2398 boost::shared_ptr<PlayerInterface> tmpPlayer = tmpGame->GetPlayerInterfaceFromGame(playerName);
2399 if (tmpPlayer && tmpPlayer->getMyGuid() == guid && tmpPlayer->getMyCash() > 0) {
2400 retGameId = tmpGame->GetId();
2401 outPlayerUniqueId = tmpPlayer->getMyUniqueID();
2402 break;
2403 }
2404 ++i;
2405 }
2406 }
2407 return retGameId;
2408 }
2409