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: