diff --git a/src/core/openssl_wrapper.h b/src/core/openssl_wrapper.h index ae979c63..dc1fc5e7 100644 --- a/src/core/openssl_wrapper.h +++ b/src/core/openssl_wrapper.h @@ -22,7 +22,7 @@ #define _OPENSSL_WRAPPER_H_ #ifndef HAVE_SSIZE_T -# define HAVE_SSIZE_T +#define HAVE_SSIZE_T #include #ifdef _WIN32 // This is only for Windows. Supports only Win32. #ifndef _SSIZE_T_ diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 069c089d..197f6546 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -1013,8 +1013,14 @@ ClientStateSynchronizeStart::Process(ClientThread &client) if (client.IsSynchronized()) { + // Acknowledge start. boost::shared_ptr startAck(new NetPacketStartEventAck); client.GetSender().Send(client.GetContext().GetSessionData(), startAck); + // Unsubscribe lobby messages. + // TODO + //boost::shared_ptr unsubscr(new NetPacketUnsubscribeGameList); + //client.GetSender().Send(client.GetContext().GetSessionData(), unsubscr); + client.SetState(ClientStateWaitStart::Instance()); } diff --git a/src/net/common/servergamestate.cpp b/src/net/common/servergamestate.cpp index 8dd5adf0..be5eb280 100644 --- a/src/net/common/servergamestate.cpp +++ b/src/net/common/servergamestate.cpp @@ -213,6 +213,18 @@ AbstractServerGameStateReceiving::Process(ServerGameThread &server) server.SendToAllPlayers(outChat, SessionData::Game); } } + else if (packet->ToNetPacketUnsubscribeGameList()) + { + // We can do this directly in this thread. + session.sessionData->ResetWantsLobbyMsg(); + } + else if (packet->ToNetPacketResubscribeGameList()) + { + // This needs to be performed in the lobby thread, + // because a new game list needs to be sent. + if (!session.sessionData->WantsLobbyMsg()) + server.GetLobbyThread().ResubscribeLobbyMsg(session); + } else { // Packet processing in subclass. diff --git a/src/net/common/serverlobbythread.cpp b/src/net/common/serverlobbythread.cpp index 38bfe5cb..7a77f11f 100644 --- a/src/net/common/serverlobbythread.cpp +++ b/src/net/common/serverlobbythread.cpp @@ -159,6 +159,13 @@ ServerLobbyThread::CloseSession(SessionWrapper session) UpdateStatisticsNumberOfPlayers(); } +void +ServerLobbyThread::ResubscribeLobbyMsg(SessionWrapper session) +{ + boost::mutex::scoped_lock lock(m_resubscribeListMutex); + m_resubscribeList.push_back(session.sessionData->GetId()); +} + void ServerLobbyThread::NotifyPlayerJoinedGame(unsigned gameId, unsigned playerId) { @@ -168,8 +175,8 @@ ServerLobbyThread::NotifyPlayerJoinedGame(unsigned gameId, unsigned playerId) packetData.gameId = gameId; packetData.playerId = playerId; static_cast(packet.get())->SetData(packetData); - m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game); + m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); } void @@ -181,8 +188,8 @@ ServerLobbyThread::NotifyPlayerLeftGame(unsigned gameId, unsigned playerId) packetData.gameId = gameId; packetData.playerId = playerId; static_cast(packet.get())->SetData(packetData); - m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game); + m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); } void @@ -194,24 +201,24 @@ ServerLobbyThread::NotifyGameAdminChanged(unsigned gameId, unsigned newAdminPlay packetData.gameId = gameId; packetData.newAdminplayerId = newAdminPlayerId; static_cast(packet.get())->SetData(packetData); - m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game); + m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); } void ServerLobbyThread::NotifyStartingGame(unsigned gameId) { boost::shared_ptr packet = CreateNetPacketGameListUpdate(gameId, GAME_MODE_STARTED); - m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game); + m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); } void ServerLobbyThread::NotifyReopeningGame(unsigned gameId) { boost::shared_ptr packet = CreateNetPacketGameListUpdate(gameId, GAME_MODE_CREATED); - m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game); + m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); } void @@ -324,6 +331,8 @@ ServerLobbyThread::Main() RemoveGameLoop(); // Kick players. RemovePlayerLoop(); + // Resubscribe Lobby Messages if needed. + ResubscribeLobbyMsgLoop(); // Check session timeouts. CheckSessionTimeoutsLoop(); // Update avatar limitation lock. @@ -402,6 +411,10 @@ ServerLobbyThread::ProcessLoop() HandleNetPacketRetrieveAvatar(session, *packet->ToNetPacketRetrieveAvatar()); else if (packet->ToNetPacketResetTimeout()) {} + else if (packet->ToNetPacketUnsubscribeGameList()) + session.sessionData->ResetWantsLobbyMsg(); + else if (packet->ToNetPacketResubscribeGameList()) + InternalResubscribeMsg(session); else if (packet->ToNetPacketCreateGame()) HandleNetPacketCreateGame(session, *packet->ToNetPacketCreateGame()); else if (packet->ToNetPacketJoinGame()) @@ -813,15 +826,41 @@ ServerLobbyThread::RemovePlayerLoop() { boost::mutex::scoped_lock lock(m_removePlayerListMutex); - RemovePlayerList::iterator i = m_removePlayerList.begin(); - RemovePlayerList::iterator end = m_removePlayerList.end(); - - while (i != end) + if (!m_removePlayerList.empty()) { - InternalRemovePlayer(i->first, i->second); - ++i; + RemovePlayerList::iterator i = m_removePlayerList.begin(); + RemovePlayerList::iterator end = m_removePlayerList.end(); + + while (i != end) + { + InternalRemovePlayer(i->first, i->second); + ++i; + } + m_removePlayerList.clear(); + } +} + +void +ServerLobbyThread::ResubscribeLobbyMsgLoop() +{ + boost::mutex::scoped_lock lock(m_resubscribeListMutex); + + if (!m_resubscribeList.empty()) + { + SessionIdList::iterator i = m_resubscribeList.begin(); + SessionIdList::iterator end = m_resubscribeList.end(); + + while (i != end) + { + SessionWrapper tmpSession = m_gameSessionManager.GetSessionById(*i); + if (!tmpSession.sessionData.get()) + tmpSession = m_sessionManager.GetSessionById(*i); + if (tmpSession.sessionData.get()); + InternalResubscribeMsg(tmpSession); + ++i; + } + m_resubscribeList.clear(); } - m_removePlayerList.clear(); } void @@ -875,8 +914,8 @@ ServerLobbyThread::InternalAddGame(boost::shared_ptr game) // Add game to list. m_gameMap.insert(GameMap::value_type(game->GetId(), game)); // Notify all players. - m_sessionManager.SendToAllSessions(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Established); - m_gameSessionManager.SendToAllSessions(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Game); + m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Established); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Game); { boost::mutex::scoped_lock lock(m_statMutex); @@ -906,8 +945,8 @@ ServerLobbyThread::InternalRemoveGame(boost::shared_ptr game) game->RemoveAllSessions(); // Notify all players. boost::shared_ptr packet = CreateNetPacketGameListUpdate(game->GetId(), GAME_MODE_CLOSED); - m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game); + m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); } void @@ -935,6 +974,16 @@ ServerLobbyThread::InternalRemovePlayer(unsigned playerId, unsigned errorCode) } } +void +ServerLobbyThread::InternalResubscribeMsg(SessionWrapper session) +{ + if (!session.sessionData->WantsLobbyMsg()) + { + session.sessionData->SetWantsLobbyMsg(); + SendGameList(session.sessionData); + } +} + void ServerLobbyThread::TerminateGames() { @@ -1129,8 +1178,8 @@ ServerLobbyThread::BroadcastStatisticsUpdate(const ServerStats &stats) try { static_cast(packet.get())->SetData(statData); - m_sessionManager.SendToAllSessions(GetSender(), packet, SessionData::Established); - m_gameSessionManager.SendToAllSessions(GetSender(), packet, SessionData::Game); + m_sessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Established); + m_gameSessionManager.SendLobbyMsgToAllSessions(GetSender(), packet, SessionData::Game); } catch (const NetException &) { // Ignore errors for now. diff --git a/src/net/common/sessiondata.cpp b/src/net/common/sessiondata.cpp index a0621c38..6eb0ce2c 100644 --- a/src/net/common/sessiondata.cpp +++ b/src/net/common/sessiondata.cpp @@ -21,7 +21,7 @@ SessionData::SessionData(SOCKET sockfd, SessionId id) : m_sockfd(sockfd), m_id(id), m_state(SessionData::Init), m_readyFlag(false), - m_activityTimeoutNoticeSent(false) + m_wantsLobbyMsg(true), m_activityTimeoutNoticeSent(false) { } @@ -80,6 +80,27 @@ SessionData::IsReady() const return m_readyFlag; } +void +SessionData::SetWantsLobbyMsg() +{ + boost::mutex::scoped_lock lock(m_dataMutex); + m_wantsLobbyMsg = true; +} + +void +SessionData::ResetWantsLobbyMsg() +{ + boost::mutex::scoped_lock lock(m_dataMutex); + m_wantsLobbyMsg = false; +} + +bool +SessionData::WantsLobbyMsg() const +{ + boost::mutex::scoped_lock lock(m_dataMutex); + return m_wantsLobbyMsg; +} + const std::string & SessionData::GetClientAddr() const { diff --git a/src/net/common/sessionmanager.cpp b/src/net/common/sessionmanager.cpp index 8e3c6c4e..77a30a8b 100644 --- a/src/net/common/sessionmanager.cpp +++ b/src/net/common/sessionmanager.cpp @@ -150,6 +150,17 @@ SessionManager::Select(unsigned timeoutMsec) return retSession; } +SessionWrapper +SessionManager::GetSessionById(SessionId id) const +{ + SessionWrapper tmpSession; + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); + SessionMap::const_iterator pos = m_sessionMap.find(id); + if (pos != m_sessionMap.end()) + tmpSession = pos->second; + return tmpSession; +} + SessionWrapper SessionManager::GetSessionByPlayerName(const string playerName) const { @@ -365,6 +376,26 @@ SessionManager::SendToAllSessions(SenderThread &sender, boost::shared_ptr packet, SessionData::State state) +{ + boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex); + + SessionMap::iterator i = m_sessionMap.begin(); + SessionMap::iterator end = m_sessionMap.end(); + + while (i != end) + { + if (!i->second.sessionData.get()) + throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0); + + // Send each client (with a certain state) a copy of the packet. + if (i->second.sessionData->GetState() == state && i->second.sessionData->WantsLobbyMsg()) + sender.Send(i->second.sessionData, boost::shared_ptr(packet->Clone())); + ++i; + } +} + void SessionManager::SendToAllButOneSessions(SenderThread &sender, boost::shared_ptr packet, SessionId except, SessionData::State state) { diff --git a/src/net/serverlobbythread.h b/src/net/serverlobbythread.h index 49a9be94..b65c4f52 100644 --- a/src/net/serverlobbythread.h +++ b/src/net/serverlobbythread.h @@ -58,6 +58,7 @@ public: void MoveSessionToGame(ServerGameThread &game, SessionWrapper session); void RemoveSessionFromGame(SessionWrapper session); void SessionError(SessionWrapper session, int errorCode); + void ResubscribeLobbyMsg(SessionWrapper session); void NotifyPlayerJoinedGame(unsigned gameId, unsigned playerId); void NotifyPlayerLeftGame(unsigned gameId, unsigned playerId); void NotifyGameAdminChanged(unsigned gameId, unsigned newAdminPlayerId); @@ -91,6 +92,7 @@ protected: typedef std::deque > ConnectQueue; typedef std::deque SessionQueue; typedef std::list SessionList; + typedef std::list SessionIdList; typedef std::map TimerSessionMap; typedef std::map > GameMap; typedef std::map TimerClientAddressMap; @@ -116,6 +118,7 @@ protected: void NewSessionLoop(); void RemoveGameLoop(); void RemovePlayerLoop(); + void ResubscribeLobbyMsgLoop(); void CheckSessionTimeoutsLoop(); void UpdateAvatarClientTimerLoop(); void CleanupAvatarCache(); @@ -123,6 +126,7 @@ protected: void InternalAddGame(boost::shared_ptr game); void InternalRemoveGame(boost::shared_ptr game); void InternalRemovePlayer(unsigned playerId, unsigned errorCode); + void InternalResubscribeMsg(SessionWrapper session); void TerminateGames(); @@ -179,6 +183,8 @@ private: PlayerDataMap m_computerPlayers; mutable boost::mutex m_computerPlayersMutex; + SessionIdList m_resubscribeList; + mutable boost::mutex m_resubscribeListMutex; GameMap m_gameMap; diff --git a/src/net/sessiondata.h b/src/net/sessiondata.h index 7a93a519..6922c350 100644 --- a/src/net/sessiondata.h +++ b/src/net/sessiondata.h @@ -50,6 +50,9 @@ public: void SetReadyFlag(); void ResetReadyFlag(); bool IsReady() const; + void SetWantsLobbyMsg(); + void ResetWantsLobbyMsg(); + bool WantsLobbyMsg() const; const std::string &GetClientAddr() const; void SetClientAddr(const std::string &addr); @@ -69,6 +72,7 @@ private: std::string m_clientAddr; ReceiveBuffer m_receiveBuffer; bool m_readyFlag; + bool m_wantsLobbyMsg; boost::timers::portable::microsec_timer m_activityTimer; bool m_activityTimeoutNoticeSent; boost::timers::portable::microsec_timer m_autoDisconnectTimer; diff --git a/src/net/sessionmanager.h b/src/net/sessionmanager.h index e4c1c74a..d829fa9f 100644 --- a/src/net/sessionmanager.h +++ b/src/net/sessionmanager.h @@ -55,6 +55,7 @@ public: void RemoveSession(SessionId session); SessionWrapper Select(unsigned timeoutMsec); + SessionWrapper GetSessionById(SessionId id) const; SessionWrapper GetSessionByPlayerName(const std::string playerName) const; SessionWrapper GetSessionByUniquePlayerId(unsigned uniqueId) const; @@ -74,6 +75,7 @@ public: unsigned GetRawSessionCount(); void SendToAllSessions(SenderThread &sender, boost::shared_ptr packet, SessionData::State state); + void SendLobbyMsgToAllSessions(SenderThread &sender, boost::shared_ptr packet, SessionData::State state); void SendToAllButOneSessions(SenderThread &sender, boost::shared_ptr packet, SessionId except, SessionData::State state); protected: