First test version with network timeout. Only activity timeout and global timeout, no game admin timeout yet. Set to test values (will disconnect rapidly).

Modified method for init timeout (if session cannot be established) - now using one non-modifiable timer for each session, and an additional timer which is reset whenever session data is received.
This commit is contained in:
lotodore
2008-03-04 23:47:45 +00:00
parent 6d7e6d9a94
commit 9f0d204f56
21 changed files with 158 additions and 53 deletions
+6
View File
@@ -417,6 +417,12 @@ AbstractClientStateReceiving::Process(ClientThread &client)
client.GetCallback().SignalNetClientRemovedFromGame(removedData.removeReason);
client.SetState(ClientStateWaitJoin::Instance());
}
else if (tmpPacket->ToNetPacketTimeoutWarning())
{
NetPacketTimeoutWarning::Data warningData;
tmpPacket->ToNetPacketTimeoutWarning()->GetData(warningData);
client.GetCallback().SignalNetClientShowTimeoutDialog(warningData.timeoutReason, warningData.remainingSeconds);
}
else if (tmpPacket->ToNetPacketChatText())
{
// Chat message - display it in the GUI.
+8
View File
@@ -241,6 +241,14 @@ ClientThread::SendCreateGame(const GameData &gameData, const std::string &name,
}
}
void
ClientThread::SendResetTimeout()
{
boost::shared_ptr<NetPacket> reset(new NetPacketResetTimeout);
boost::mutex::scoped_lock lock(m_outPacketListMutex);
m_outPacketList.push_back(reset);
}
GameInfo
ClientThread::GetGameInfo(unsigned gameId) const
{
+2
View File
@@ -4354,6 +4354,7 @@ NetPacketTimeoutWarning::SetData(const NetPacketTimeoutWarning::Data &inData)
tmpData->timeoutReason = htons(NET_TIMEOUT_OTHER_REASON);
break;
}
tmpData->remainingSeconds = htons(inData.remainingSeconds);
// Check the packet - just in case.
Check(GetRawData());
@@ -4374,6 +4375,7 @@ NetPacketTimeoutWarning::GetData(NetPacketTimeoutWarning::Data &outData) const
outData.timeoutReason = NETWORK_TIMEOUT_GENERIC;
break;
}
outData.remainingSeconds = ntohs(tmpData->remainingSeconds);
}
const NetPacketTimeoutWarning *
+2
View File
@@ -175,6 +175,8 @@ AbstractServerGameStateReceiving::Process(ServerGameThread &server)
// Delegate to Lobby.
server.GetLobbyThread().HandleGameRetrieveAvatar(session, *packet->ToNetPacketRetrieveAvatar());
}
else if (packet->ToNetPacketResetTimeout())
{}
else if (packet->ToNetPacketLeaveCurrentGame())
{
server.MoveSessionToLobby(session, NTF_NET_REMOVED_ON_REQUEST);
+47 -38
View File
@@ -34,11 +34,15 @@
#include <boost/filesystem.hpp>
#include <boost/bind.hpp>
#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_SESSION_TIMEOUT_SEC 20
#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_STATISTICS_FILE_NAME "server_statistics.log"
#define SERVER_STATISTICS_STR_TOTAL_PLAYERS "TotalNumPlayersLoggedIn"
@@ -142,10 +146,6 @@ ServerLobbyThread::RemoveSessionFromGame(SessionWrapper session)
void
ServerLobbyThread::CloseSession(SessionWrapper session)
{
{
boost::mutex::scoped_lock lock(m_initTimerSessionMapMutex);
m_initTimerSessionMap.erase(session.sessionData->GetId());
}
m_sessionManager.RemoveSession(session.sessionData->GetId());
m_gameSessionManager.RemoveSession(session.sessionData->GetId());
@@ -308,12 +308,13 @@ ServerLobbyThread::Main()
NewSessionLoop();
// Main loop.
ProcessLoop();
// Close sessions.
CloseSessionLoop();
// Remove games.
RemoveGameLoop();
// Kick players.
KickPlayerLoop();
// 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));
// Update avatar limitation lock.
UpdateAvatarClientTimerLoop();
// Cleanup cache.
@@ -383,6 +384,8 @@ ServerLobbyThread::ProcessLoop()
HandleNetPacketRetrievePlayerInfo(session, *packet->ToNetPacketRetrievePlayerInfo());
else if (packet->ToNetPacketRetrieveAvatar())
HandleNetPacketRetrieveAvatar(session, *packet->ToNetPacketRetrieveAvatar());
else if (packet->ToNetPacketResetTimeout())
{}
else if (packet->ToNetPacketCreateGame())
HandleNetPacketCreateGame(session, *packet->ToNetPacketCreateGame());
else if (packet->ToNetPacketJoinGame())
@@ -697,10 +700,6 @@ ServerLobbyThread::EstablishSession(SessionWrapper session)
SendGameList(session.sessionData);
// Session is now established.
{
boost::mutex::scoped_lock lock(m_initTimerSessionMapMutex);
m_initTimerSessionMap.erase(session.sessionData->GetId());
}
session.sessionData->SetState(SessionData::Established);
{
@@ -764,27 +763,6 @@ ServerLobbyThread::NewSessionLoop()
HandleReAddedSession(tmpSession);
}
void
ServerLobbyThread::CloseSessionLoop()
{
boost::mutex::scoped_lock lock(m_initTimerSessionMapMutex);
TimerSessionMap::iterator i = m_initTimerSessionMap.begin();
TimerSessionMap::iterator end = m_initTimerSessionMap.end();
// Remove sessions if they do not initialize within a certain period.
while (i != end)
{
TimerSessionMap::iterator next = i;
++next;
if (i->second.elapsed().total_seconds() > SERVER_INIT_SESSION_TIMEOUT_SEC)
{
m_sessionManager.RemoveSession(i->first);
m_initTimerSessionMap.erase(i);
}
i = next;
}
}
void
ServerLobbyThread::RemoveGameLoop()
{
@@ -956,8 +934,6 @@ ServerLobbyThread::HandleNewConnection(boost::shared_ptr<ConnectData> connData)
tmpAddress[sizeof(tmpAddress) - 1] = 0; // paranoia
sessionData->SetClientAddr(tmpAddress);
}
boost::mutex::scoped_lock lock(m_initTimerSessionMapMutex);
m_initTimerSessionMap[sessionData->GetId()] = boost::timers::portable::microsec_timer();
}
else
{
@@ -987,6 +963,39 @@ ServerLobbyThread::HandleReAddedSession(SessionWrapper session)
}
}
bool
ServerLobbyThread::CheckSessionTimeouts(SessionWrapper session)
{
bool retVal = false;
if (session.sessionData.get())
{
if (session.sessionData->GetState() == SessionData::Init && session.sessionData->GetAutoDisconnectTimerElapsedSec() >= SERVER_INIT_SESSION_TIMEOUT_SEC)
retVal = true;
else if (session.sessionData->GetActivityTimerElapsedSec() >= SERVER_SESSION_ACTIVITY_TIMEOUT_SEC - SERVER_TIMEOUT_WARNING_REMAINING_SEC
&& !session.sessionData->HasActivityNoticeBeenSent())
{
session.sessionData->MarkActivityNotice();
boost::shared_ptr<NetPacket> packet(new NetPacketTimeoutWarning);
NetPacketTimeoutWarning::Data warningData;
warningData.timeoutReason = NETWORK_TIMEOUT_GENERIC;
warningData.remainingSeconds = SERVER_TIMEOUT_WARNING_REMAINING_SEC;
static_cast<NetPacketTimeoutWarning *>(packet.get())->SetData(warningData);
GetSender().Send(session.sessionData, packet);
}
else if (session.sessionData->GetActivityTimerElapsedSec() >= SERVER_SESSION_ACTIVITY_TIMEOUT_SEC)
{
// TODO SendError(session.sessionData, errorCode);
retVal = true;
}
else if (session.sessionData->GetAutoDisconnectTimerElapsedSec() >= SERVER_SESSION_FORCED_TIMEOUT_SEC)
{
// TODO SendError(session.sessionData, errorCode);
retVal = true;
}
}
return retVal;
}
void
ServerLobbyThread::CleanupConnectQueue()
{
+39 -1
View File
@@ -20,7 +20,8 @@
#include <net/sessiondata.h>
SessionData::SessionData(SOCKET sockfd, SessionId id)
: m_sockfd(sockfd), m_id(id), m_state(SessionData::Init), m_readyFlag(false)
: m_sockfd(sockfd), m_id(id), m_state(SessionData::Init), m_readyFlag(false),
m_activityTimeoutNoticeSent(false)
{
}
@@ -100,3 +101,40 @@ SessionData::GetReceiveBuffer()
return m_receiveBuffer;
}
void
SessionData::ResetActivityTimer()
{
boost::mutex::scoped_lock lock(m_dataMutex);
m_activityTimeoutNoticeSent = false;
m_activityTimer.reset();
m_activityTimer.start();
}
unsigned
SessionData::GetActivityTimerElapsedSec() const
{
boost::mutex::scoped_lock lock(m_dataMutex);
return m_activityTimer.elapsed().total_seconds();
}
bool
SessionData::HasActivityNoticeBeenSent() const
{
boost::mutex::scoped_lock lock(m_dataMutex);
return m_activityTimeoutNoticeSent;
}
void
SessionData::MarkActivityNotice()
{
boost::mutex::scoped_lock lock(m_dataMutex);
m_activityTimeoutNoticeSent = true;
}
unsigned
SessionData::GetAutoDisconnectTimerElapsedSec() const
{
boost::mutex::scoped_lock lock(m_dataMutex);
return m_autoDisconnectTimer.elapsed().total_seconds();
}
+20
View File
@@ -147,6 +147,8 @@ SessionManager::Select(unsigned timeoutMsec)
}
}
}
if (retSession.sessionData.get())
retSession.sessionData->ResetActivityTimer();
return retSession;
}
@@ -294,6 +296,24 @@ SessionManager::ForEach(boost::function<void (SessionWrapper)> func)
}
}
void
SessionManager::ForEachRemoveIf(boost::function<bool (SessionWrapper)> func)
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
SessionMap::iterator i = m_sessionMap.begin();
SessionMap::iterator end = m_sessionMap.end();
while (i != end)
{
SessionMap::iterator next = i;
next++;
if (func((*i).second))
m_sessionMap.erase(i);
i = next;
}
}
unsigned
SessionManager::CountReadySessions() const
{