diff --git a/src/net/common/servergamethread.cpp b/src/net/common/servergamethread.cpp index c8cd57b0..123f1402 100644 --- a/src/net/common/servergamethread.cpp +++ b/src/net/common/servergamethread.cpp @@ -68,10 +68,10 @@ ServerGameThread::AddSession(SessionWrapper session) } void -ServerGameThread::KickPlayer(unsigned playerId) +ServerGameThread::RemovePlayer(unsigned playerId, unsigned errorCode) { - boost::mutex::scoped_lock lock(m_kickPlayerListMutex); - m_kickPlayerList.push_back(playerId); + boost::mutex::scoped_lock lock(m_removePlayerListMutex); + m_removePlayerList.push_back(RemovePlayerList::value_type(playerId, errorCode)); } GameState @@ -127,7 +127,7 @@ ServerGameThread::Main() } // Process current state. GetState().Process(*this); - KickPlayerLoop(); + RemovePlayerLoop(); } while (!ShouldTerminate() && GetSessionManager().HasSessions()); } catch (const PokerTHException &e) { @@ -140,22 +140,22 @@ ServerGameThread::Main() } void -ServerGameThread::KickPlayerLoop() +ServerGameThread::RemovePlayerLoop() { - boost::mutex::scoped_lock lock(m_kickPlayerListMutex); + boost::mutex::scoped_lock lock(m_removePlayerListMutex); - PlayerIdList::iterator i = m_kickPlayerList.begin(); - PlayerIdList::iterator end = m_kickPlayerList.end(); + RemovePlayerList::iterator i = m_removePlayerList.begin(); + RemovePlayerList::iterator end = m_removePlayerList.end(); while (i != end) { - SessionWrapper tmpSession = GetSessionManager().GetSessionByUniquePlayerId(*i); + SessionWrapper tmpSession = GetSessionManager().GetSessionByUniquePlayerId(i->first); // Only kick if the player was found. if (tmpSession.sessionData.get()) - SessionError(tmpSession, ERR_NET_PLAYER_KICKED); + SessionError(tmpSession, i->second); ++i; } - m_kickPlayerList.clear(); + m_removePlayerList.clear(); } void diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index 4675d3ba..bf5e3d3b 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -34,21 +34,23 @@ #include #include -#define SERVER_MAX_NUM_SESSIONS 512 // Maximum number of idle users in lobby. -#define SERVER_CACHE_CLEANUP_INTERVAL_SEC 86400 // 1 day -#define SERVER_SAVE_STATISTICS_INTERVAL_SEC 60 -#define SERVER_INIT_AVATAR_CLIENT_LOCK_SEC 30 // Forbid a client to send an additional avatar. +#define SERVER_MAX_NUM_SESSIONS 512 // Maximum number of idle users in lobby. +#define SERVER_CACHE_CLEANUP_INTERVAL_SEC 86400 // 1 day +#define SERVER_SAVE_STATISTICS_INTERVAL_SEC 60 +#define SERVER_INIT_AVATAR_CLIENT_LOCK_SEC 30 // Forbid a client to send an additional avatar. -#define SERVER_INIT_SESSION_TIMEOUT_SEC 20 -#define SERVER_TIMEOUT_WARNING_REMAINING_SEC 60 -#define SERVER_SESSION_ACTIVITY_TIMEOUT_SEC 90 // MUST be > SERVER_TIMEOUT_WARNING_REMAINING_SEC -#define SERVER_SESSION_FORCED_TIMEOUT_SEC 300 // Should be quite large. +#define SERVER_INIT_SESSION_TIMEOUT_SEC 20 +#define SERVER_TIMEOUT_WARNING_REMAINING_SEC 60 +#define SERVER_SESSION_ACTIVITY_TIMEOUT_SEC 90 // MUST be > SERVER_TIMEOUT_WARNING_REMAINING_SEC +#define SERVER_SESSION_FORCED_TIMEOUT_SEC 300 // Should be quite large. -#define SERVER_STATISTICS_FILE_NAME "server_statistics.log" -#define SERVER_STATISTICS_STR_TOTAL_PLAYERS "TotalNumPlayersLoggedIn" -#define SERVER_STATISTICS_STR_TOTAL_GAMES "TotalNumGamesCreated" -#define SERVER_STATISTICS_STR_MAX_GAMES "MaxGamesOpen" -#define SERVER_STATISTICS_STR_MAX_PLAYERS "MaxPlayersLoggedIn" +#define SERVER_CHECK_SESSION_TIMEOUTS_INTERVAL_MSEC 500 + +#define SERVER_STATISTICS_FILE_NAME "server_statistics.log" +#define SERVER_STATISTICS_STR_TOTAL_PLAYERS "TotalNumPlayersLoggedIn" +#define SERVER_STATISTICS_STR_TOTAL_GAMES "TotalNumGamesCreated" +#define SERVER_STATISTICS_STR_MAX_GAMES "MaxGamesOpen" +#define SERVER_STATISTICS_STR_MAX_PLAYERS "MaxPlayersLoggedIn" using namespace std; @@ -232,14 +234,20 @@ ServerLobbyThread::KickPlayerByName(const std::string &playerName) if (session.sessionData.get() && session.playerData.get()) { - boost::mutex::scoped_lock lock(m_kickPlayerListMutex); - m_kickPlayerList.push_back(session.playerData->GetUniqueId()); + RemovePlayer(session.playerData->GetUniqueId(), ERR_NET_PLAYER_KICKED); retVal = true; } return retVal; } +void +ServerLobbyThread::RemovePlayer(unsigned playerId, unsigned errorCode) +{ + boost::mutex::scoped_lock lock(m_removePlayerListMutex); + m_removePlayerList.push_back(RemovePlayerList::value_type(playerId, errorCode)); +} + void ServerLobbyThread::AddComputerPlayer(boost::shared_ptr player) { @@ -311,10 +319,9 @@ ServerLobbyThread::Main() // Remove games. RemoveGameLoop(); // Kick players. - KickPlayerLoop(); + RemovePlayerLoop(); // Check session timeouts. - m_sessionManager.ForEachRemoveIf(boost::bind(&ServerLobbyThread::CheckSessionTimeouts, boost::ref(*this), _1)); - m_gameSessionManager.ForEachRemoveIf(boost::bind(&ServerLobbyThread::CheckSessionTimeouts, boost::ref(*this), _1)); + CheckSessionTimeoutsLoop(); // Update avatar limitation lock. UpdateAvatarClientTimerLoop(); // Cleanup cache. @@ -792,19 +799,31 @@ ServerLobbyThread::RemoveGameLoop() } void -ServerLobbyThread::KickPlayerLoop() +ServerLobbyThread::RemovePlayerLoop() { - boost::mutex::scoped_lock lock(m_kickPlayerListMutex); + boost::mutex::scoped_lock lock(m_removePlayerListMutex); - PlayerIdList::iterator i = m_kickPlayerList.begin(); - PlayerIdList::iterator end = m_kickPlayerList.end(); + RemovePlayerList::iterator i = m_removePlayerList.begin(); + RemovePlayerList::iterator end = m_removePlayerList.end(); while (i != end) { - InternalKickPlayer(*i); + InternalRemovePlayer(i->first, i->second); ++i; } - m_kickPlayerList.clear(); + m_removePlayerList.clear(); +} + +void +ServerLobbyThread::CheckSessionTimeoutsLoop() +{ + if (m_checkSessionTimeoutsTimer.elapsed().total_milliseconds() >= SERVER_CHECK_SESSION_TIMEOUTS_INTERVAL_MSEC) + { + m_sessionManager.ForEach(boost::bind(&ServerLobbyThread::InternalCheckSessionTimeouts, boost::ref(*this), _1)); + m_gameSessionManager.ForEach(boost::bind(&ServerLobbyThread::InternalCheckSessionTimeouts, boost::ref(*this), _1)); + m_checkSessionTimeoutsTimer.reset(); + m_checkSessionTimeoutsTimer.start(); + } } void @@ -829,7 +848,7 @@ void ServerLobbyThread::CleanupAvatarCache() { // Only act on timer and if there are no sessions. - if (m_cacheCleanupTimer.elapsed().total_seconds() > SERVER_CACHE_CLEANUP_INTERVAL_SEC + if (m_cacheCleanupTimer.elapsed().total_seconds() >= SERVER_CACHE_CLEANUP_INTERVAL_SEC && !m_sessionManager.HasSessions() && !m_gameSessionManager.HasSessions()) { m_avatarManager.RemoveOldAvatarCacheEntries(); @@ -871,11 +890,11 @@ ServerLobbyThread::InternalRemoveGame(boost::shared_ptr game) } void -ServerLobbyThread::InternalKickPlayer(unsigned playerId) +ServerLobbyThread::InternalRemovePlayer(unsigned playerId, unsigned errorCode) { SessionWrapper session = m_sessionManager.GetSessionByUniquePlayerId(playerId); if (session.sessionData.get()) - SessionError(session, ERR_NET_PLAYER_KICKED); + SessionError(session, errorCode); else { // Scan games for the player. @@ -887,7 +906,7 @@ ServerLobbyThread::InternalKickPlayer(unsigned playerId) boost::shared_ptr tmpGame = i->second; if (tmpGame->GetPlayerDataByUniqueId(playerId).get()) { - tmpGame->KickPlayer(playerId); + tmpGame->RemovePlayer(playerId, errorCode); break; } ++i; @@ -966,14 +985,14 @@ ServerLobbyThread::HandleReAddedSession(SessionWrapper session) } } -bool -ServerLobbyThread::CheckSessionTimeouts(SessionWrapper session) +void +ServerLobbyThread::InternalCheckSessionTimeouts(SessionWrapper session) { - bool retVal = false; - if (session.sessionData.get()) + bool closeSession = false; + if (session.sessionData.get() && session.playerData.get()) { if (session.sessionData->GetState() == SessionData::Init && session.sessionData->GetAutoDisconnectTimerElapsedSec() >= SERVER_INIT_SESSION_TIMEOUT_SEC) - retVal = true; + closeSession = true; else if (session.sessionData->GetActivityTimerElapsedSec() >= SERVER_SESSION_ACTIVITY_TIMEOUT_SEC - SERVER_TIMEOUT_WARNING_REMAINING_SEC && !session.sessionData->HasActivityNoticeBeenSent()) { @@ -987,16 +1006,15 @@ ServerLobbyThread::CheckSessionTimeouts(SessionWrapper session) } else if (session.sessionData->GetActivityTimerElapsedSec() >= SERVER_SESSION_ACTIVITY_TIMEOUT_SEC) { - // TODO SendError(session.sessionData, errorCode); - retVal = true; + closeSession = true; } else if (session.sessionData->GetAutoDisconnectTimerElapsedSec() >= SERVER_SESSION_FORCED_TIMEOUT_SEC) { - // TODO SendError(session.sessionData, errorCode); - retVal = true; + closeSession = true; } } - return retVal; + if (closeSession) + RemovePlayer(session.playerData->GetUniqueId(), ERR_NET_PLAYER_KICKED); // TODO new error code } void @@ -1120,7 +1138,7 @@ ServerLobbyThread::ReadStatisticsFile() void ServerLobbyThread::SaveStatisticsFile() { - if (m_saveStatisticsTimer.elapsed().total_seconds() > SERVER_SAVE_STATISTICS_INTERVAL_SEC) + if (m_saveStatisticsTimer.elapsed().total_seconds() >= SERVER_SAVE_STATISTICS_INTERVAL_SEC) { { boost::mutex::scoped_lock lock(m_statMutex); diff --git a/src/net/common/sessionmanager.cpp b/src/net/common/sessionmanager.cpp index 1ea20992..8e3c6c4e 100644 --- a/src/net/common/sessionmanager.cpp +++ b/src/net/common/sessionmanager.cpp @@ -37,7 +37,7 @@ SessionManager::~SessionManager() bool SessionManager::HasSessions() const { - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); return !m_sessionMap.empty(); } @@ -50,7 +50,7 @@ SessionManager::AddSession(boost::shared_ptr sessionData) void SessionManager::AddSession(SessionWrapper session) { - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::iterator pos = m_sessionMap.lower_bound(session.sessionData->GetId()); @@ -66,7 +66,7 @@ SessionManager::AddSession(SessionWrapper session) void SessionManager::SetSessionPlayerData(SessionId session, boost::shared_ptr playerData) { - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::iterator pos = m_sessionMap.find(session); if (pos != m_sessionMap.end()) @@ -76,7 +76,7 @@ SessionManager::SetSessionPlayerData(SessionId session, boost::shared_ptr 0) // one (or more) of the sockets is readable { // Check which socket is readable, return the first. - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::iterator i = m_sessionMap.begin(); SessionMap::iterator end = m_sessionMap.end(); @@ -154,7 +154,7 @@ SessionWrapper SessionManager::GetSessionByPlayerName(const string playerName) const { SessionWrapper tmpSession; - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::const_iterator session_i = m_sessionMap.begin(); SessionMap::const_iterator session_end = m_sessionMap.end(); @@ -183,7 +183,7 @@ SessionWrapper SessionManager::GetSessionByUniquePlayerId(unsigned uniqueId) const { SessionWrapper tmpSession; - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::const_iterator session_i = m_sessionMap.begin(); SessionMap::const_iterator session_end = m_sessionMap.end(); @@ -212,7 +212,7 @@ PlayerDataList SessionManager::GetPlayerDataList() const { PlayerDataList playerList; - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::const_iterator session_i = m_sessionMap.begin(); SessionMap::const_iterator session_end = m_sessionMap.end(); @@ -236,7 +236,7 @@ PlayerIdList SessionManager::GetPlayerIdList() const { PlayerIdList playerList; - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::const_iterator session_i = m_sessionMap.begin(); SessionMap::const_iterator session_end = m_sessionMap.end(); @@ -282,22 +282,7 @@ SessionManager::IsPlayerConnected(unsigned uniqueId) const void SessionManager::ForEach(boost::function func) { - boost::mutex::scoped_lock lock(m_sessionMapMutex); - - SessionMap::iterator i = m_sessionMap.begin(); - SessionMap::iterator end = m_sessionMap.end(); - - while (i != end) - { - func((*i).second); - ++i; - } -} - -void -SessionManager::ForEachRemoveIf(boost::function func) -{ - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::iterator i = m_sessionMap.begin(); SessionMap::iterator end = m_sessionMap.end(); @@ -306,8 +291,7 @@ SessionManager::ForEachRemoveIf(boost::function func) { SessionMap::iterator next = i; next++; - if (func((*i).second)) - m_sessionMap.erase(i); + func((*i).second); i = next; } } @@ -316,7 +300,7 @@ unsigned SessionManager::CountReadySessions() const { unsigned counter = 0; - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::const_iterator i = m_sessionMap.begin(); SessionMap::const_iterator end = m_sessionMap.end(); @@ -333,7 +317,7 @@ SessionManager::CountReadySessions() const void SessionManager::ResetAllReadyFlags() { - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::iterator i = m_sessionMap.begin(); SessionMap::iterator end = m_sessionMap.end(); @@ -348,7 +332,7 @@ SessionManager::ResetAllReadyFlags() void SessionManager::Clear() { - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); // Sockets will be closed automatically. m_sessionMap.clear(); @@ -357,14 +341,14 @@ SessionManager::Clear() unsigned SessionManager::GetRawSessionCount() { - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); return m_sessionMap.size(); } void SessionManager::SendToAllSessions(SenderThread &sender, boost::shared_ptr packet, SessionData::State state) { - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::iterator i = m_sessionMap.begin(); SessionMap::iterator end = m_sessionMap.end(); @@ -384,7 +368,7 @@ SessionManager::SendToAllSessions(SenderThread &sender, boost::shared_ptr packet, SessionId except, SessionData::State state) { - boost::mutex::scoped_lock lock(m_sessionMapMutex); + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::iterator i = m_sessionMap.begin(); SessionMap::iterator end = m_sessionMap.end(); diff --git a/src/net/servergamethread.h b/src/net/servergamethread.h index 992880f0..8f6c07ff 100644 --- a/src/net/servergamethread.h +++ b/src/net/servergamethread.h @@ -49,7 +49,7 @@ public: const std::string &GetName() const; void AddSession(SessionWrapper session); - void KickPlayer(unsigned playerId); + void RemovePlayer(unsigned playerId, unsigned errorCode); ServerCallback &GetCallback(); GameState GetCurRound() const; @@ -80,7 +80,7 @@ protected: // Main function of the thread. virtual void Main(); - void KickPlayerLoop(); + void RemovePlayerLoop(); void InternalStartGame(); void ResetGame(); @@ -132,8 +132,8 @@ private: PlayerDataList m_computerPlayerList; mutable boost::mutex m_computerPlayerListMutex; - PlayerIdList m_kickPlayerList; - mutable boost::mutex m_kickPlayerListMutex; + RemovePlayerList m_removePlayerList; + mutable boost::mutex m_removePlayerListMutex; unsigned m_adminPlayerId; mutable boost::mutex m_adminPlayerIdMutex; diff --git a/src/net/serverlobbythread.h b/src/net/serverlobbythread.h index 51c867d4..a61124ce 100644 --- a/src/net/serverlobbythread.h +++ b/src/net/serverlobbythread.h @@ -68,6 +68,7 @@ public: void HandleGameRetrieveAvatar(SessionWrapper session, const NetPacketRetrieveAvatar &tmpPacket); bool KickPlayerByName(const std::string &playerName); + void RemovePlayer(unsigned playerId, unsigned errorCode); void AddComputerPlayer(boost::shared_ptr player); void RemoveComputerPlayer(boost::shared_ptr player); @@ -114,20 +115,21 @@ protected: void NewConnectionLoop(); void NewSessionLoop(); void RemoveGameLoop(); - void KickPlayerLoop(); + void RemovePlayerLoop(); + void CheckSessionTimeoutsLoop(); void UpdateAvatarClientTimerLoop(); void CleanupAvatarCache(); void InternalAddGame(boost::shared_ptr game); void InternalRemoveGame(boost::shared_ptr game); - void InternalKickPlayer(unsigned playerId); + void InternalRemovePlayer(unsigned playerId, unsigned errorCode); void TerminateGames(); void HandleNewConnection(boost::shared_ptr connData); void HandleReAddedSession(SessionWrapper session); - bool CheckSessionTimeouts(SessionWrapper session); + void InternalCheckSessionTimeouts(SessionWrapper session); void CleanupConnectQueue(); void CleanupSessionMap(); @@ -171,8 +173,8 @@ private: RemoveGameList m_removeGameList; mutable boost::mutex m_removeGameListMutex; - PlayerIdList m_kickPlayerList; - mutable boost::mutex m_kickPlayerListMutex; + RemovePlayerList m_removePlayerList; + mutable boost::mutex m_removePlayerListMutex; PlayerDataMap m_computerPlayers; mutable boost::mutex m_computerPlayersMutex; @@ -202,6 +204,7 @@ private: boost::timers::portable::microsec_timer m_cacheCleanupTimer; boost::timers::portable::microsec_timer m_saveStatisticsTimer; + boost::timers::portable::microsec_timer m_checkSessionTimeoutsTimer; const boost::posix_time::ptime m_startTime; }; diff --git a/src/net/sessionmanager.h b/src/net/sessionmanager.h index 24db2461..e4c1c74a 100644 --- a/src/net/sessionmanager.h +++ b/src/net/sessionmanager.h @@ -66,7 +66,6 @@ public: bool IsPlayerConnected(unsigned uniqueId) const; void ForEach(boost::function func); - void ForEachRemoveIf(boost::function func); unsigned CountReadySessions() const; void ResetAllReadyFlags(); @@ -84,7 +83,7 @@ protected: private: SessionMap m_sessionMap; - mutable boost::mutex m_sessionMapMutex; + mutable boost::recursive_mutex m_sessionMapMutex; }; #endif diff --git a/src/playerdata.h b/src/playerdata.h index 8cc0ab4f..c8395fa1 100644 --- a/src/playerdata.h +++ b/src/playerdata.h @@ -110,6 +110,7 @@ private: }; typedef std::list PlayerIdList; +typedef std::list > RemovePlayerList; typedef std::list > PlayerDataList; typedef std::map > PlayerDataMap;