From fa7af40a497edc62565440384d6c9969bb822c99 Mon Sep 17 00:00:00 2001 From: lotodore Date: Sun, 28 Oct 2007 12:53:54 +0000 Subject: [PATCH] Fixed a very nasty bug concerning the sender thread. SOCKETs were assumed to be kind of unique, but Windows tends to return the socket number of a socket which was just closed as new socket number in accept. This led to very strange behavior when the server was flooded with inits, because the sender thread still had entries for this socket number (which were not removed because they should just fail). No longer use socket as key in maps, instead, use the session id. Only use the session id in the sender thread, "resolve" it to the socket only in the moment when it is needed. Outstanding requests will be detected to have an invalid session id then. Also, as side effect, fixed an issue with two callback classes which were named the same and caused unexpected behavior. --- src/net/clientcontext.h | 8 +- src/net/clientthread.h | 1 + src/net/common/clientcontext.cpp | 9 +-- src/net/common/clientstate.cpp | 6 +- src/net/common/clientthread.cpp | 15 ++-- src/net/common/senderthread.cpp | 117 +++++++++++++++------------ src/net/common/servercontext.cpp | 7 -- src/net/common/servergamestate.cpp | 8 +- src/net/common/servergamethread.cpp | 18 +++-- src/net/common/serverlobbythread.cpp | 95 ++++++++++++---------- src/net/common/sessiondata.cpp | 4 +- src/net/common/sessionmanager.cpp | 31 +++++-- src/net/netcontext.h | 1 - src/net/sendercallback.h | 4 +- src/net/senderthread.h | 17 ++-- src/net/servercontext.h | 1 - src/net/servergamethread.h | 7 +- src/net/serverlobbythread.h | 13 +-- src/net/sessiondata.h | 17 +++- src/net/sessionmanager.h | 10 ++- 20 files changed, 223 insertions(+), 166 deletions(-) diff --git a/src/net/clientcontext.h b/src/net/clientcontext.h index 0d200842..1cae21cc 100644 --- a/src/net/clientcontext.h +++ b/src/net/clientcontext.h @@ -23,6 +23,7 @@ #include #include +#include class ClientContext : public NetContext { @@ -31,10 +32,12 @@ public: virtual ~ClientContext(); virtual SOCKET GetSocket() const; - virtual u_int32_t GetId() const; - void SetSocket(SOCKET sockfd); + SessionId GetSessionId() const + {return m_sessionId;} + void SetSessionId(SessionId sessionId) + {m_sessionId = sessionId;} int GetProtocol() const {return m_protocol;} void SetProtocol(int protocol) @@ -76,6 +79,7 @@ public: private: SOCKET m_sockfd; + SessionId m_sessionId; int m_protocol; int m_addrFamily; std::string m_serverAddr; diff --git a/src/net/clientthread.h b/src/net/clientthread.h index 7b90b826..4cbaf3f0 100644 --- a/src/net/clientthread.h +++ b/src/net/clientthread.h @@ -194,6 +194,7 @@ friend class ClientStateWaitStart; friend class ClientStateWaitHand; friend class ClientStateRunHand; friend class ClientStateFinal; +friend class ClientSenderCallback; }; #endif diff --git a/src/net/common/clientcontext.cpp b/src/net/common/clientcontext.cpp index 5ebdf5f5..b671be17 100644 --- a/src/net/common/clientcontext.cpp +++ b/src/net/common/clientcontext.cpp @@ -20,7 +20,7 @@ #include ClientContext::ClientContext() -: m_sockfd(INVALID_SOCKET), m_protocol(0), m_addrFamily(AF_INET), m_serverPort(0) +: m_sockfd(INVALID_SOCKET), m_sessionId(SESSION_ID_GENERIC), m_protocol(0), m_addrFamily(AF_INET), m_serverPort(0) { bzero(&m_clientSockaddr, sizeof(m_clientSockaddr)); } @@ -37,13 +37,6 @@ ClientContext::GetSocket() const return m_sockfd; } -u_int32_t -ClientContext::GetId() const -{ - // Id is unused for clients. - return 0; -} - void ClientContext::SetSocket(SOCKET sockfd) { diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 362298ec..73dbee14 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -362,7 +362,7 @@ ClientStateStartSession::Process(ClientThread &client) boost::shared_ptr packet(new NetPacketInit); ((NetPacketInit *)packet.get())->SetData(initData); - client.GetSender().Send(context.GetSocket(), packet); + client.GetSender().Send(context.GetSessionId(), packet); client.SetState(ClientStateWaitSession::Instance()); @@ -592,7 +592,7 @@ ClientStateWaitSession::InternalProcess(ClientThread &client, boost::shared_ptr< tmpList); if (!avatarError) - client.GetSender().SendLowPrio(client.GetContext().GetSocket(), tmpList); + client.GetSender().SendLowPrio(client.GetContext().GetSessionId(), tmpList); else throw ClientException(__FILE__, __LINE__, avatarError, 0); } @@ -740,7 +740,7 @@ ClientStateSynchronizeStart::Process(ClientThread &client) if (client.IsSynchronized()) { boost::shared_ptr startAck(new NetPacketStartEventAck); - client.GetSender().Send(client.GetContext().GetSocket(), startAck); + client.GetSender().Send(client.GetContext().GetSessionId(), startAck); client.SetState(ClientStateWaitStart::Instance()); } diff --git a/src/net/common/clientthread.cpp b/src/net/common/clientthread.cpp index b45908de..633b1fc6 100644 --- a/src/net/common/clientthread.cpp +++ b/src/net/common/clientthread.cpp @@ -42,9 +42,14 @@ public: ClientSenderCallback(ClientThread &client) : m_client(client) {} virtual ~ClientSenderCallback() {} - virtual void SignalNetError(SOCKET /*sock*/, int errorID, int osErrorID) + virtual bool GetSocketForSession(SessionId session, SOCKET &outSocket) + { + assert(session == m_client.GetContext().GetSessionId()); + outSocket = m_client.GetContext().GetSocket(); + return true; + } + virtual void SignalNetError(SessionId /*session*/, int errorID, int osErrorID) { - // For now, we ignore the socket. // Just signal the error. // We assume that the client thread will be terminated. m_client.GetCallback().SignalNetClientError(errorID, osErrorID); @@ -369,7 +374,7 @@ ClientThread::SendPacketLoop() while (i != end) { - GetSender().Send(GetContext().GetSocket(), *i); + GetSender().Send(GetContext().GetSessionId(), *i); ++i; } m_outPacketList.clear(); @@ -400,7 +405,7 @@ ClientThread::RequestPlayerInfo(unsigned id) NetPacketRetrievePlayerInfo::Data reqData; reqData.playerId = id; static_cast(req.get())->SetData(reqData); - GetSender().Send(GetContext().GetSocket(), req); + GetSender().Send(GetContext().GetSessionId(), req); m_playerInfoRequestList.push_back(id); } @@ -438,7 +443,7 @@ ClientThread::SetPlayerInfo(unsigned id, const PlayerInfo &info, bool retrieveAv retrieveAvatarData.requestId = id; retrieveAvatarData.avatar = info.avatar; static_cast(retrieveAvatar.get())->SetData(retrieveAvatarData); - GetSender().Send(GetContext().GetSocket(), retrieveAvatar); + GetSender().Send(GetContext().GetSessionId(), retrieveAvatar); // Insert empty value in list to synchronize waiting. m_tempAvatarMap[id] = boost::shared_ptr(); diff --git a/src/net/common/senderthread.cpp b/src/net/common/senderthread.cpp index 50d84a13..17d96cd4 100644 --- a/src/net/common/senderthread.cpp +++ b/src/net/common/senderthread.cpp @@ -28,7 +28,7 @@ using namespace std; SenderThread::SenderThread(SenderCallback &cb) -: m_curSocket(INVALID_SOCKET), m_tmpOutBufSize(0), m_callback(cb) +: m_curSession(INVALID_SESSION), m_tmpOutBufSize(0), m_callback(cb) { } @@ -37,55 +37,55 @@ SenderThread::~SenderThread() } void -SenderThread::Send(SOCKET sock, boost::shared_ptr packet) +SenderThread::Send(SessionId session, boost::shared_ptr packet) { - if (packet.get() && IS_VALID_SOCKET(sock)) + if (packet.get() && session != INVALID_SESSION) { boost::mutex::scoped_lock lock(m_outBufMutex); - InternalStore(m_outBuf, SEND_QUEUE_SIZE, sock, packet); + InternalStore(m_outBuf, SEND_QUEUE_SIZE, session, packet); } } void -SenderThread::Send(SOCKET sock, const NetPacketList &packetList) +SenderThread::Send(SessionId session, const NetPacketList &packetList) { - if (!packetList.empty() && IS_VALID_SOCKET(sock)) + if (!packetList.empty() && session != INVALID_SESSION) { boost::mutex::scoped_lock lock(m_outBufMutex); - InternalStore(m_outBuf, SEND_QUEUE_SIZE, sock, packetList); + InternalStore(m_outBuf, SEND_QUEUE_SIZE, session, packetList); } } void -SenderThread::SendLowPrio(SOCKET sock, boost::shared_ptr packet) +SenderThread::SendLowPrio(SessionId session, boost::shared_ptr packet) { - if (packet.get() && IS_VALID_SOCKET(sock)) + if (packet.get() && session != INVALID_SESSION) { boost::mutex::scoped_lock lock(m_lowPrioOutBufMutex); - InternalStore(m_lowPrioOutBuf, SEND_LOW_PRIO_QUEUE_SIZE, sock, packet); + InternalStore(m_lowPrioOutBuf, SEND_LOW_PRIO_QUEUE_SIZE, session, packet); } } void -SenderThread::SendLowPrio(SOCKET sock, const NetPacketList &packetList) +SenderThread::SendLowPrio(SessionId session, const NetPacketList &packetList) { - if (!packetList.empty() && IS_VALID_SOCKET(sock)) + if (!packetList.empty() && session != INVALID_SESSION) { boost::mutex::scoped_lock lock(m_lowPrioOutBufMutex); - InternalStore(m_lowPrioOutBuf, SEND_LOW_PRIO_QUEUE_SIZE, sock, packetList); + InternalStore(m_lowPrioOutBuf, SEND_LOW_PRIO_QUEUE_SIZE, session, packetList); } } void -SenderThread::InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, SOCKET sock, boost::shared_ptr packet) +SenderThread::InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, SessionId session, boost::shared_ptr packet) { if (sendQueue.size() < maxQueueSize) // Queue is limited in size. - sendQueue.push_back(std::make_pair(packet, sock)); + sendQueue.push_back(std::make_pair(packet, session)); // TODO: Throw exception if failed. } void -SenderThread::InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, SOCKET sock, const NetPacketList &packetList) +SenderThread::InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, SessionId session, const NetPacketList &packetList) { if (sendQueue.size() + packetList.size() < maxQueueSize) { @@ -93,7 +93,7 @@ SenderThread::InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, SOC NetPacketList::const_iterator end = packetList.end(); while (i != end) { - sendQueue.push_back(std::make_pair(*i, sock)); + sendQueue.push_back(std::make_pair(*i, session)); ++i; } } @@ -134,8 +134,8 @@ SenderThread::Main() if (tmpData.first.get()) { - if (IS_VALID_SOCKET(tmpData.second)) - m_curSocket = tmpData.second; + if (tmpData.second != INVALID_SESSION) + m_curSession = tmpData.second; u_int16_t tmpLen = tmpData.first->GetLen(); if (tmpLen <= MAX_PACKET_SIZE) @@ -147,35 +147,25 @@ SenderThread::Main() } if (m_tmpOutBufSize) { - fd_set writeSet; - struct timeval timeout; - - FD_ZERO(&writeSet); - FD_SET(m_curSocket, &writeSet); - - timeout.tv_sec = 0; - timeout.tv_usec = SEND_TIMEOUT_MSEC * 1000; - int selectResult = select(m_curSocket + 1, NULL, &writeSet, NULL, &timeout); - if (!IS_VALID_SELECT(selectResult)) + SOCKET tmpSocket; + if (!m_callback.GetSocketForSession(m_curSession, tmpSocket)) { - // Never assume that this is a fatal error. - int errCode = SOCKET_ERRNO(); - if (errCode != SOCKET_ERR_WOULDBLOCK) - { - // Skip this packet - this is bad, and is therefore reported. - // Ignore invalid or not connected sockets. - if (errCode != SOCKET_ERR_NOTCONN && errCode != SOCKET_ERR_NOTSOCK) - m_callback.SignalNetError(m_curSocket, ERR_SOCK_SELECT_FAILED, errCode); - m_tmpOutBufSize = 0; - } - Msleep(SEND_TIMEOUT_MSEC); + // Invalid session - skip. + m_tmpOutBufSize = 0; + m_curSession = INVALID_SESSION; } - if (selectResult > 0) // send is possible + else { - // send next chunk of data - int bytesSent = send(m_curSocket, m_tmpOutBuf, m_tmpOutBufSize, 0); + fd_set writeSet; + struct timeval timeout; - if (!IS_VALID_SEND(bytesSent)) + FD_ZERO(&writeSet); + FD_SET(tmpSocket, &writeSet); + + timeout.tv_sec = 0; + timeout.tv_usec = SEND_TIMEOUT_MSEC * 1000; + int selectResult = select(tmpSocket + 1, NULL, &writeSet, NULL, &timeout); + if (!IS_VALID_SELECT(selectResult)) { // Never assume that this is a fatal error. int errCode = SOCKET_ERRNO(); @@ -184,19 +174,42 @@ SenderThread::Main() // Skip this packet - this is bad, and is therefore reported. // Ignore invalid or not connected sockets. if (errCode != SOCKET_ERR_NOTCONN && errCode != SOCKET_ERR_NOTSOCK) - m_callback.SignalNetError(m_curSocket, ERR_SOCK_SEND_FAILED, errCode); + m_callback.SignalNetError(m_curSession, ERR_SOCK_SELECT_FAILED, errCode); m_tmpOutBufSize = 0; + m_curSession = INVALID_SESSION; } Msleep(SEND_TIMEOUT_MSEC); } - else if ((unsigned)bytesSent < m_tmpOutBufSize) + if (selectResult > 0) // send is possible { - m_tmpOutBufSize -= (unsigned)bytesSent; - memmove(m_tmpOutBuf, m_tmpOutBuf + bytesSent, m_tmpOutBufSize); - } - else - { - m_tmpOutBufSize = 0; + // send next chunk of data + int bytesSent = send(tmpSocket, m_tmpOutBuf, m_tmpOutBufSize, 0); + + if (!IS_VALID_SEND(bytesSent)) + { + // Never assume that this is a fatal error. + int errCode = SOCKET_ERRNO(); + if (errCode != SOCKET_ERR_WOULDBLOCK) + { + // Skip this packet - this is bad, and is therefore reported. + // Ignore invalid or not connected sockets. + if (errCode != SOCKET_ERR_NOTCONN && errCode != SOCKET_ERR_NOTSOCK) + m_callback.SignalNetError(m_curSession, ERR_SOCK_SEND_FAILED, errCode); + m_tmpOutBufSize = 0; + m_curSession = INVALID_SESSION; + } + Msleep(SEND_TIMEOUT_MSEC); + } + else if ((unsigned)bytesSent < m_tmpOutBufSize) + { + m_tmpOutBufSize -= (unsigned)bytesSent; + memmove(m_tmpOutBuf, m_tmpOutBuf + bytesSent, m_tmpOutBufSize); + } + else + { + m_tmpOutBufSize = 0; + m_curSession = INVALID_SESSION; + } } } } diff --git a/src/net/common/servercontext.cpp b/src/net/common/servercontext.cpp index 7044ca67..f6bb554b 100644 --- a/src/net/common/servercontext.cpp +++ b/src/net/common/servercontext.cpp @@ -37,13 +37,6 @@ ServerContext::GetSocket() const return m_sockfd; } -u_int32_t -ServerContext::GetId() const -{ - // Id is unused for main server thread. - return 0; -} - void ServerContext::SetSocket(SOCKET sockfd) { diff --git a/src/net/common/servergamestate.cpp b/src/net/common/servergamestate.cpp index 2e63871e..a46ee5ab 100644 --- a/src/net/common/servergamestate.cpp +++ b/src/net/common/servergamestate.cpp @@ -271,7 +271,7 @@ ServerGameStateInit::HandleNewSession(ServerGameThread &server, SessionWrapper s joinGameAckData.prights = session.playerData->GetRights(); joinGameAckData.gameData = server.GetGameData(); static_cast(joinGameAck.get())->SetData(joinGameAckData); - server.GetSender().Send(session.sessionData->GetSocket(), joinGameAck); + server.GetSender().Send(session.sessionData->GetId(), joinGameAck); // Send notifications for connected players to client. PlayerDataList tmpPlayerList = server.GetFullPlayerDataList(); @@ -279,7 +279,7 @@ ServerGameStateInit::HandleNewSession(ServerGameThread &server, SessionWrapper s PlayerDataList::iterator player_end = tmpPlayerList.end(); while (player_i != player_end) { - server.GetSender().Send(session.sessionData->GetSocket(), CreateNetPacketPlayerJoined(*(*player_i))); + server.GetSender().Send(session.sessionData->GetId(), CreateNetPacketPlayerJoined(*(*player_i))); ++player_i; } @@ -538,7 +538,7 @@ ServerGameStateStartHand::Process(ServerGameThread &server) handStartData.smallBlind = curGame.getCurrentHand()->getSmallBlind(); static_cast(notifyCards.get())->SetData(handStartData); - server.GetSender().Send(tmpPlayer->getNetSessionData()->GetSocket(), notifyCards); + server.GetSender().Send(tmpPlayer->getNetSessionData()->GetId(), notifyCards); } ++i; } @@ -908,7 +908,7 @@ ServerGameStateWaitPlayerAction::InternalProcess(ServerGameThread &server, Sessi rejectData.playerBet = actionData.playerBet; rejectData.rejectionReason = code; static_cast(reject.get())->SetData(rejectData); - server.GetSender().Send(session.sessionData->GetSocket(), reject); + server.GetSender().Send(session.sessionData->GetId(), reject); } } diff --git a/src/net/common/servergamethread.cpp b/src/net/common/servergamethread.cpp index 9b9e12aa..b3f3f6fb 100644 --- a/src/net/common/servergamethread.cpp +++ b/src/net/common/servergamethread.cpp @@ -34,13 +34,17 @@ using namespace std; -class ServerSenderCallback : public SenderCallback +class GameSenderCallback : public SenderCallback { public: - ServerSenderCallback(ServerGameThread &server) : m_server(server) {} - virtual ~ServerSenderCallback() {} + GameSenderCallback(ServerGameThread &server) : m_server(server) {} + virtual ~GameSenderCallback() {} - virtual void SignalNetError(SOCKET /*sock*/, int /*errorID*/, int /*osErrorID*/) + virtual bool GetSocketForSession(SessionId session, SOCKET &outSocket) + { + return m_server.GetSessionManager().GetSocketForSession(session, outSocket); + } + virtual void SignalNetError(SessionId /*session*/, int /*errorID*/, int /*osErrorID*/) { // We just ignore send errors for now, on server side. // A serious send error should trigger a read error or a read @@ -57,7 +61,7 @@ ServerGameThread::ServerGameThread(ServerLobbyThread &lobbyThread, u_int32_t id, m_name(name), m_password(pwd), m_gameData(gameData), m_playerConfig(playerConfig), m_curState(NULL), m_gameNum(1) { - m_senderCallback.reset(new ServerSenderCallback(*this)); + m_senderCallback.reset(new GameSenderCallback(*this)); m_sender.reset(new SenderThread(GetSenderCallback())); m_receiver.reset(new ReceiverHelper); } @@ -319,7 +323,7 @@ void ServerGameThread::GracefulRemoveSession(SessionWrapper session) { assert(session.sessionData.get()); - GetSessionManager().RemoveSession(session.sessionData->GetSocket()); + GetSessionManager().RemoveSession(session.sessionData->GetId()); boost::shared_ptr tmpPlayerData = session.playerData; if (tmpPlayerData.get() && !tmpPlayerData->GetName().empty()) @@ -526,7 +530,7 @@ ServerGameThread::CheckPassword(const string &password) const return (password == m_password); } -ServerSenderCallback & +GameSenderCallback & ServerGameThread::GetSenderCallback() { assert(m_senderCallback.get()); diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index e41d8a82..71b986c7 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -46,7 +46,11 @@ public: ServerSenderCallback(ServerLobbyThread &server) : m_server(server) {} virtual ~ServerSenderCallback() {} - virtual void SignalNetError(SOCKET /*sock*/, int /*errorID*/, int /*osErrorID*/) + virtual bool GetSocketForSession(SessionId session, SOCKET &outSocket) + { + return m_server.GetSocketForSession(session, outSocket); + } + virtual void SignalNetError(SessionId /*session*/, int /*errorID*/, int /*osErrorID*/) { // We just ignore send errors for now, on server side. // A serious send error should trigger a read error or a read @@ -60,7 +64,8 @@ private: ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig, AvatarManager &avatarManager) : m_gui(gui), m_avatarManager(avatarManager), m_playerConfig(playerConfig), - m_curGameId(0), m_curUniquePlayerId(0), m_totalPlayersLoggedIn(0), m_totalGamesStarted(0) + m_curGameId(0), m_curUniquePlayerId(0), m_curSessionId(INVALID_SESSION + 1), + m_totalPlayersLoggedIn(0), m_totalGamesStarted(0) { m_senderCallback.reset(new ServerSenderCallback(*this)); m_sender.reset(new SenderThread(GetSenderCallback())); @@ -92,7 +97,7 @@ ServerLobbyThread::ReAddSession(SessionWrapper session, int reason) NetPacketRemovedFromGame::Data removedData; removedData.removeReason = reason; static_cast(packet.get())->SetData(removedData); - GetSender().Send(session.sessionData->GetSocket(), packet); + GetSender().Send(session.sessionData->GetId(), packet); boost::mutex::scoped_lock lock(m_sessionQueueMutex); m_sessionQueue.push_back(session); @@ -102,7 +107,7 @@ void ServerLobbyThread::MoveSessionToGame(ServerGameThread &game, SessionWrapper session) { // Remove session from the lobby. - m_sessionManager.RemoveSession(session.sessionData->GetSocket()); + m_sessionManager.RemoveSession(session.sessionData->GetId()); // Session is now in game state. session.sessionData->SetState(SessionData::Game); // Store it in the list of game sessions. @@ -115,7 +120,7 @@ void ServerLobbyThread::RemoveSessionFromGame(SessionWrapper session) { // Just remove the session. Only for fatal errors. - m_gameSessionManager.RemoveSession(session.sessionData->GetSocket()); + m_gameSessionManager.RemoveSession(session.sessionData->GetId()); // Update stats (if needed). BroadcastStatisticsUpdate(); } @@ -123,9 +128,9 @@ ServerLobbyThread::RemoveSessionFromGame(SessionWrapper session) void ServerLobbyThread::CloseSessionDelayed(SessionWrapper session) { - m_initTimerSessionMap.erase(session.sessionData->GetSocket()); - m_sessionManager.RemoveSession(session.sessionData->GetSocket()); - m_gameSessionManager.RemoveSession(session.sessionData->GetSocket()); + m_initTimerSessionMap.erase(session.sessionData->GetId()); + m_sessionManager.RemoveSession(session.sessionData->GetId()); + m_gameSessionManager.RemoveSession(session.sessionData->GetId()); boost::timers::portable::microsec_timer closeTimer; CloseSessionList::value_type closeSessionData(closeTimer, session.sessionData); @@ -227,6 +232,15 @@ ServerLobbyThread::RemoveGame(unsigned id) m_removeGameList.push_back(id); } +bool +ServerLobbyThread::GetSocketForSession(SessionId session, SOCKET &outSocket) +{ + bool retVal = m_sessionManager.GetSocketForSession(session, outSocket); + if (!retVal) + retVal = m_gameSessionManager.GetSocketForSession(session, outSocket); + return retVal; +} + AvatarManager & ServerLobbyThread::GetAvatarManager() { @@ -298,8 +312,8 @@ ServerLobbyThread::ProcessLoop() } catch (const NetException &) { // On error: Close this session. - m_initTimerSessionMap.erase(session.sessionData->GetSocket()); - m_sessionManager.RemoveSession(session.sessionData->GetSocket()); + m_initTimerSessionMap.erase(session.sessionData->GetId()); + m_sessionManager.RemoveSession(session.sessionData->GetId()); // Update stats (if needed). BroadcastStatisticsUpdate(); return; @@ -391,7 +405,7 @@ ServerLobbyThread::HandleNetPacketInit(SessionWrapper session, const NetPacketIn tmpPlayerData->SetAvatarMD5(initData.avatar); // Set player data for session. - m_sessionManager.SetSessionPlayerData(session.sessionData->GetSocket(), tmpPlayerData); + m_sessionManager.SetSessionPlayerData(session.sessionData->GetId(), tmpPlayerData); session.playerData = tmpPlayerData; if (initData.showAvatar && !GetAvatarManager().HasAvatar(initData.avatar)) @@ -510,7 +524,7 @@ ServerLobbyThread::HandleNetPacketRetrievePlayerInfo(SessionWrapper session, con if (infoData.playerInfo.hasAvatar) infoData.playerInfo.avatar = tmpPlayer->GetAvatarMD5(); static_cast(info.get())->SetData(infoData); - GetSender().Send(session.sessionData->GetSocket(), info); + GetSender().Send(session.sessionData->GetId(), info); } else { @@ -519,7 +533,7 @@ ServerLobbyThread::HandleNetPacketRetrievePlayerInfo(SessionWrapper session, con NetPacketUnknownPlayerId::Data unknownData; unknownData.playerId = request.playerId; static_cast(unknown.get())->SetData(unknownData); - GetSender().Send(session.sessionData->GetSocket(), unknown); + GetSender().Send(session.sessionData->GetId(), unknown); } } @@ -537,7 +551,7 @@ ServerLobbyThread::HandleNetPacketRetrieveAvatar(SessionWrapper session, const N if (GetAvatarManager().AvatarFileToNetPackets(tmpFile, request.requestId, tmpPackets) == 0) { avatarFound = true; - GetSender().SendLowPrio(session.sessionData->GetSocket(), tmpPackets); + GetSender().SendLowPrio(session.sessionData->GetId(), tmpPackets); } else LOG_ERROR("Failed to read avatar file for network transmission."); @@ -550,7 +564,7 @@ ServerLobbyThread::HandleNetPacketRetrieveAvatar(SessionWrapper session, const N NetPacketUnknownAvatar::Data unknownData; unknownData.requestId = request.requestId; static_cast(unknown.get())->SetData(unknownData); - GetSender().Send(session.sessionData->GetSocket(), unknown); + GetSender().Send(session.sessionData->GetId(), unknown); } } @@ -599,7 +613,7 @@ ServerLobbyThread::HandleNetPacketJoinGame(SessionWrapper session, const NetPack } else { - SendJoinGameFailed(session.sessionData->GetSocket(), NTF_NET_JOIN_INVALID_PASSWORD); + SendJoinGameFailed(session.sessionData->GetId(), NTF_NET_JOIN_INVALID_PASSWORD); } } else @@ -620,13 +634,13 @@ ServerLobbyThread::EstablishSession(SessionWrapper session) initAckData.sessionId = session.sessionData->GetId(); // TODO: currently unused. initAckData.playerId = session.playerData->GetUniqueId(); static_cast(initAck.get())->SetData(initAckData); - GetSender().Send(session.sessionData->GetSocket(), initAck); + GetSender().Send(session.sessionData->GetId(), initAck); // Send the game list to the client. - SendGameList(session.sessionData->GetSocket()); + SendGameList(session.sessionData->GetId()); // Session is now established. - m_initTimerSessionMap.erase(session.sessionData->GetSocket()); + m_initTimerSessionMap.erase(session.sessionData->GetId()); session.sessionData->SetState(SessionData::Established); ++m_totalPlayersLoggedIn; @@ -644,7 +658,7 @@ ServerLobbyThread::RequestPlayerAvatar(SessionWrapper session) retrieveAvatarData.requestId = session.playerData->GetUniqueId(); retrieveAvatarData.avatar = session.playerData->GetAvatarMD5(); static_cast(retrieveAvatar.get())->SetData(retrieveAvatarData); - GetSender().Send(session.sessionData->GetSocket(), retrieveAvatar); + GetSender().Send(session.sessionData->GetId(), retrieveAvatar); } void @@ -798,28 +812,27 @@ ServerLobbyThread::TerminateGames() void ServerLobbyThread::HandleNewConnection(boost::shared_ptr connData) { + // Create a random session id. + // This id can be used to reconnect to the server if the connection was lost. + //unsigned sessionId; + + // TODO: use randomized method. + //if(!RAND_bytes((unsigned char *)&sessionId, sizeof(sessionId))) + //{ + // RAND_pseudo_bytes((unsigned char *)&sessionId, sizeof(sessionId)); + //} + + // Create a new session. + boost::shared_ptr sessionData(new SessionData(connData->ReleaseSocket(), m_curSessionId++)); + m_sessionManager.AddSession(sessionData); + if (m_sessionManager.GetRawSessionCount() <= SERVER_MAX_NUM_SESSIONS) { - // Create a random session id. - // This id can be used to reconnect to the server if the connection was lost. - unsigned sessionId; - - // TODO: check for collisions. - if(!RAND_bytes((unsigned char *)&sessionId, sizeof(sessionId))) - { - RAND_pseudo_bytes((unsigned char *)&sessionId, sizeof(sessionId)); - } - - // Create a new session. - boost::shared_ptr sessionData(new SessionData(connData->ReleaseSocket(), sessionId)); - m_sessionManager.AddSession(sessionData); - m_initTimerSessionMap[sessionData->GetSocket()] = boost::timers::portable::microsec_timer(); + m_initTimerSessionMap[sessionData->GetId()] = boost::timers::portable::microsec_timer(); } else { // Server is full. - // Create a generic session with Id 0. - boost::shared_ptr sessionData(new SessionData(connData->ReleaseSocket(), 0)); // Gracefully close this session. SessionError(SessionWrapper(sessionData, boost::shared_ptr()), ERR_NET_SERVER_FULL); } @@ -829,7 +842,7 @@ void ServerLobbyThread::HandleReAddedSession(SessionWrapper session) { // Remove session from game session list. - m_gameSessionManager.RemoveSession(session.sessionData->GetSocket()); + m_gameSessionManager.RemoveSession(session.sessionData->GetId()); if (m_sessionManager.GetRawSessionCount() <= SERVER_MAX_NUM_SESSIONS) { @@ -859,13 +872,13 @@ ServerLobbyThread::SessionError(SessionWrapper session, int errorCode) { if (session.sessionData.get()) { - SendError(session.sessionData->GetSocket(), errorCode); + SendError(session.sessionData->GetId(), errorCode); CloseSessionDelayed(session); } } void -ServerLobbyThread::SendError(SOCKET s, int errorCode) +ServerLobbyThread::SendError(SessionId s, int errorCode) { boost::shared_ptr packet(new NetPacketError); NetPacketError::Data errorData; @@ -875,7 +888,7 @@ ServerLobbyThread::SendError(SOCKET s, int errorCode) } void -ServerLobbyThread::SendJoinGameFailed(SOCKET s, int reason) +ServerLobbyThread::SendJoinGameFailed(SessionId s, int reason) { boost::shared_ptr packet(new NetPacketJoinGameFailed); NetPacketJoinGameFailed::Data failedData; @@ -885,7 +898,7 @@ ServerLobbyThread::SendJoinGameFailed(SOCKET s, int reason) } void -ServerLobbyThread::SendGameList(SOCKET s) +ServerLobbyThread::SendGameList(SessionId s) { GameMap::const_iterator game_i = m_gameMap.begin(); GameMap::const_iterator game_end = m_gameMap.end(); diff --git a/src/net/common/sessiondata.cpp b/src/net/common/sessiondata.cpp index d761926d..a5ae3d31 100644 --- a/src/net/common/sessiondata.cpp +++ b/src/net/common/sessiondata.cpp @@ -19,7 +19,7 @@ #include -SessionData::SessionData(SOCKET sockfd, unsigned id) +SessionData::SessionData(SOCKET sockfd, SessionId id) : m_sockfd(sockfd), m_id(id), m_state(SessionData::Init), m_readyFlag(false) { } @@ -30,7 +30,7 @@ SessionData::~SessionData() CLOSESOCKET(m_sockfd); } -unsigned +SessionId SessionData::GetId() const { // const value - no mutex needed. diff --git a/src/net/common/sessionmanager.cpp b/src/net/common/sessionmanager.cpp index c83f08fb..ac27874f 100644 --- a/src/net/common/sessionmanager.cpp +++ b/src/net/common/sessionmanager.cpp @@ -52,19 +52,19 @@ SessionManager::AddSession(SessionWrapper session) { boost::mutex::scoped_lock lock(m_sessionMapMutex); - SessionMap::iterator pos = m_sessionMap.lower_bound(session.sessionData->GetSocket()); + SessionMap::iterator pos = m_sessionMap.lower_bound(session.sessionData->GetId()); // If pos points to a pair whose key is equivalent to the socket, this handle // already exists within the list. - if (pos != m_sessionMap.end() && session.sessionData->GetSocket() == pos->first) + if (pos != m_sessionMap.end() && session.sessionData->GetId() == pos->first) { throw ServerException(__FILE__, __LINE__, ERR_SOCK_CONN_EXISTS, 0); } - m_sessionMap.insert(pos, SessionMap::value_type(session.sessionData->GetSocket(), session)); + m_sessionMap.insert(pos, SessionMap::value_type(session.sessionData->GetId(), session)); } void -SessionManager::SetSessionPlayerData(SOCKET session, boost::shared_ptr playerData) +SessionManager::SetSessionPlayerData(SessionId session, boost::shared_ptr playerData) { boost::mutex::scoped_lock lock(m_sessionMapMutex); SessionMap::iterator pos = m_sessionMap.find(session); @@ -74,7 +74,7 @@ SessionManager::SetSessionPlayerData(SOCKET session, boost::shared_ptrfirst; + SOCKET tmpSock = i->second.sessionData->GetSocket(); FD_SET(tmpSock, &rdset); if (tmpSock > maxSock || maxSock == INVALID_SOCKET) maxSock = tmpSock; @@ -137,7 +137,7 @@ SessionManager::Select(unsigned timeoutMsec) while (i != end) { - if (FD_ISSET(i->first, &rdset)) + if (FD_ISSET(i->second.sessionData->GetSocket(), &rdset)) { retSession = i->second; break; @@ -206,6 +206,21 @@ SessionManager::GetSessionByUniquePlayerId(unsigned uniqueId) const return tmpSession; } +bool +SessionManager::GetSocketForSession(SessionId session, SOCKET &outSocket) +{ + bool retVal = false; + boost::mutex::scoped_lock lock(m_sessionMapMutex); + SessionMap::iterator pos = m_sessionMap.find(session); + + if (pos != m_sessionMap.end()) + { + outSocket = pos->second.sessionData->GetSocket(); + retVal = true; + } + return retVal; +} + PlayerDataList SessionManager::GetPlayerDataList() const { @@ -361,7 +376,7 @@ SessionManager::SendToAllSessions(SenderThread &sender, boost::shared_ptr packet, SOCKET except, SessionData::State state) +SessionManager::SendToAllButOneSessions(SenderThread &sender, boost::shared_ptr packet, SessionId except, SessionData::State state) { boost::mutex::scoped_lock lock(m_sessionMapMutex); diff --git a/src/net/netcontext.h b/src/net/netcontext.h index 7087d9bd..04e5c7db 100644 --- a/src/net/netcontext.h +++ b/src/net/netcontext.h @@ -31,7 +31,6 @@ public: virtual ~NetContext(); virtual SOCKET GetSocket() const = 0; - virtual u_int32_t GetId() const = 0; }; #endif diff --git a/src/net/sendercallback.h b/src/net/sendercallback.h index a4f37f05..d09961dc 100644 --- a/src/net/sendercallback.h +++ b/src/net/sendercallback.h @@ -21,6 +21,7 @@ #ifndef _SENDERCALLBACK_H_ #define _SENDERCALLBACK_H_ +#include #include class SenderCallback @@ -28,7 +29,8 @@ class SenderCallback public: virtual ~SenderCallback(); - virtual void SignalNetError(SOCKET sock, int errorID, int osErrorID) = 0; + virtual bool GetSocketForSession(SessionId session, SOCKET &outSocket) = 0; + virtual void SignalNetError(SessionId session, int errorID, int osErrorID) = 0; }; #endif diff --git a/src/net/senderthread.h b/src/net/senderthread.h index b370443c..5cfcaad1 100644 --- a/src/net/senderthread.h +++ b/src/net/senderthread.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -40,25 +41,25 @@ public: SenderThread(SenderCallback &cb); virtual ~SenderThread(); - void Send(SOCKET sock, boost::shared_ptr packet); - void Send(SOCKET sock, const NetPacketList &packetList); + void Send(SessionId session, boost::shared_ptr packet); + void Send(SessionId session, const NetPacketList &packetList); - void SendLowPrio(SOCKET sock, boost::shared_ptr packet); - void SendLowPrio(SOCKET sock, const NetPacketList &packetList); + void SendLowPrio(SessionId session, boost::shared_ptr packet); + void SendLowPrio(SessionId session, const NetPacketList &packetList); protected: - typedef std::pair, SOCKET> SendData; + typedef std::pair, SessionId> SendData; typedef std::deque SendDataDeque; // Main function of the thread. virtual void Main(); - void InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, SOCKET sock, boost::shared_ptr packet); - void InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, SOCKET sock, const NetPacketList &packetList); + void InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, SessionId session, boost::shared_ptr packet); + void InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, SessionId session, const NetPacketList &packetList); private: - SOCKET m_curSocket; + SessionId m_curSession; std::deque m_outBuf; mutable boost::mutex m_outBufMutex; diff --git a/src/net/servercontext.h b/src/net/servercontext.h index 49a1fa92..7d2e27e6 100644 --- a/src/net/servercontext.h +++ b/src/net/servercontext.h @@ -31,7 +31,6 @@ public: virtual ~ServerContext(); virtual SOCKET GetSocket() const; - virtual u_int32_t GetId() const; void SetSocket(SOCKET sockfd); diff --git a/src/net/servergamethread.h b/src/net/servergamethread.h index ec0fecfe..323ba3bd 100644 --- a/src/net/servergamethread.h +++ b/src/net/servergamethread.h @@ -33,7 +33,7 @@ class SenderThread; class ReceiverHelper; class ServerLobbyThread; -class ServerSenderCallback; +class GameSenderCallback; class ServerGameState; class ConfigFile; struct GameData; @@ -112,7 +112,7 @@ protected: const StartData &GetStartData() const; void SetStartData(const StartData &startData); - ServerSenderCallback &GetSenderCallback(); + GameSenderCallback &GetSenderCallback(); GuiInterface &GetGui(); unsigned GetNextGameNum(); @@ -135,7 +135,7 @@ private: ServerLobbyThread &m_lobbyThread; std::auto_ptr m_receiver; std::auto_ptr m_sender; - std::auto_ptr m_senderCallback; + boost::shared_ptr m_senderCallback; GuiInterface &m_gui; const GameData m_gameData; @@ -161,6 +161,7 @@ friend class ServerGameStateDealCardsDelay; friend class ServerGameStateShowCardsDelay; friend class ServerGameStateNextHandDelay; friend class ServerGameStateNextGameDelay; +friend class GameSenderCallback; }; #endif diff --git a/src/net/serverlobbythread.h b/src/net/serverlobbythread.h index a9b9ed2b..41c68259 100644 --- a/src/net/serverlobbythread.h +++ b/src/net/serverlobbythread.h @@ -70,6 +70,8 @@ public: void RemoveGame(unsigned id); + bool GetSocketForSession(SessionId session, SOCKET &outSocket); + u_int32_t GetNextUniquePlayerId(); u_int32_t GetNextGameId(); ServerCallback &GetCallback(); @@ -82,7 +84,7 @@ protected: typedef std::deque SessionQueue; typedef std::list SessionList; typedef std::list > > CloseSessionList; - typedef std::map InitTimerSessionMap; + typedef std::map InitTimerSessionMap; typedef std::map > GameMap; typedef std::list RemoveGameList; @@ -121,9 +123,9 @@ protected: void CleanupSessionMap(); void CloseSessionDelayed(SessionWrapper session); - void SendError(SOCKET s, int errorCode); - void SendJoinGameFailed(SOCKET s, int reason); - void SendGameList(SOCKET s); + void SendError(SessionId s, int errorCode); + void SendJoinGameFailed(SessionId s, int reason); + void SendGameList(SessionId s); void BroadcastStatisticsUpdate(); SenderThread &GetSender(); @@ -165,7 +167,7 @@ private: std::auto_ptr m_receiver; std::auto_ptr m_sender; - std::auto_ptr m_senderCallback; + boost::shared_ptr m_senderCallback; GuiInterface &m_gui; AvatarManager &m_avatarManager; @@ -174,6 +176,7 @@ private: u_int32_t m_curGameId; u_int32_t m_curUniquePlayerId; + u_int32_t m_curSessionId; mutable boost::mutex m_curUniquePlayerIdMutex; unsigned m_totalPlayersLoggedIn; diff --git a/src/net/sessiondata.h b/src/net/sessiondata.h index 9a1400da..1e509449 100644 --- a/src/net/sessiondata.h +++ b/src/net/sessiondata.h @@ -26,17 +26,26 @@ #include #include -#define SESSION_ID_INIT 0 +#define INVALID_SESSION 0 +#define SESSION_ID_INIT INVALID_SESSION +#define SESSION_ID_GENERIC 0xFFFFFFFF + +typedef unsigned SessionId; +/*struct SessionId +{ + unsigned id; +};*/ + class SessionData { public: enum State { Init, ReceivingAvatar, Established, Game }; - SessionData(SOCKET sockfd, unsigned id); + SessionData(SOCKET sockfd, SessionId id); ~SessionData(); - unsigned GetId() const; + SessionId GetId() const; State GetState() const; void SetState(State state); @@ -53,7 +62,7 @@ public: private: SOCKET m_sockfd; - const unsigned m_id; + const SessionId m_id; State m_state; std::string m_clientAddr; ReceiveBuffer m_receiveBuffer; diff --git a/src/net/sessionmanager.h b/src/net/sessionmanager.h index c89c3354..d3d7a126 100644 --- a/src/net/sessionmanager.h +++ b/src/net/sessionmanager.h @@ -51,13 +51,15 @@ public: void AddSession(boost::shared_ptr sessionData); // new Sessions without player data void AddSession(SessionWrapper session); - void SetSessionPlayerData(SOCKET session, boost::shared_ptr playerData); - void RemoveSession(SOCKET session); + void SetSessionPlayerData(SessionId session, boost::shared_ptr playerData); + void RemoveSession(SessionId session); SessionWrapper Select(unsigned timeoutMsec); SessionWrapper GetSessionByPlayerName(const std::string playerName) const; SessionWrapper GetSessionByUniquePlayerId(unsigned uniqueId) const; + bool GetSocketForSession(SessionId session, SOCKET &outSocket); + PlayerDataList GetPlayerDataList() const; PlayerIdList GetPlayerIdList() const; bool IsPlayerConnected(const std::string &playerName) const; @@ -72,11 +74,11 @@ public: unsigned GetRawSessionCount(); void SendToAllSessions(SenderThread &sender, boost::shared_ptr packet, SessionData::State state); - void SendToAllButOneSessions(SenderThread &sender, boost::shared_ptr packet, SOCKET except, SessionData::State state); + void SendToAllButOneSessions(SenderThread &sender, boost::shared_ptr packet, SessionId except, SessionData::State state); protected: - typedef std::map SessionMap; + typedef std::map SessionMap; private: