diff --git a/src/net/common/serverrecvstate.cpp b/src/net/common/serverrecvstate.cpp index d3d0383a..fcb2b0ae 100644 --- a/src/net/common/serverrecvstate.cpp +++ b/src/net/common/serverrecvstate.cpp @@ -120,6 +120,15 @@ ServerRecvStateInit::Process(ServerRecvThread &server) return retVal; } + size_t curNumPlayers = server.GetCurNumberOfPlayers(); + + // Check the number of players. + if (curNumPlayers >= (size_t)server.GetGameData().numberOfPlayers) + { + server.SessionError(session, ERR_NET_SERVER_FULL); + return retVal; + } + // Check the server password. if (!server.CheckPassword(joinGameData.password)) { @@ -127,12 +136,11 @@ ServerRecvStateInit::Process(ServerRecvThread &server) return retVal; } - size_t curNumPlayers = server.GetCurNumberOfPlayers(); - - // Check the number of players. - if (curNumPlayers >= (size_t)server.GetGameData().numberOfPlayers) + // Check whether the player name is correct. + // Paranoia check, this is also done in netpacket. + if (joinGameData.playerName.empty() || joinGameData.playerName.size() > MAX_NAME_SIZE) { - server.SessionError(session, ERR_NET_SERVER_FULL); + server.SessionError(session, ERR_NET_INVALID_PLAYER_NAME); return retVal; } @@ -177,7 +185,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server) ++player_i; } - // Send "Player Joined" to other clients. + // Send "Player Joined" to other fully connected clients. boost::shared_ptr thisPlayerJoined(new NetPacketPlayerJoined); NetPacketPlayerJoined::Data thisPlayerJoinedData; thisPlayerJoinedData.playerId = tmpPlayerData->GetUniqueId(); @@ -185,7 +193,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server) thisPlayerJoinedData.playerNumber = tmpPlayerData->GetNumber(); thisPlayerJoinedData.ptype = tmpPlayerData->GetType(); static_cast(thisPlayerJoined.get())->SetData(thisPlayerJoinedData); - server.SendToAllButOnePlayers(thisPlayerJoined, session.sessionData->GetSocket()); + server.SendToAllPlayers(thisPlayerJoined); // Set player data for session. server.SetSessionPlayerData(session.sessionData, tmpPlayerData); @@ -217,7 +225,8 @@ ServerRecvStateStartGame::~ServerRecvStateStartGame() void ServerRecvStateStartGame::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr connData) { - // TODO: send error msg + // Do not accept new connections in this state. + server.RejectNewConnection(connData); } int @@ -255,7 +264,8 @@ ServerRecvStateStartHand::~ServerRecvStateStartHand() void ServerRecvStateStartHand::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr connData) { - // TODO: send error msg + // Do not accept new connections in this state. + server.RejectNewConnection(connData); } int @@ -271,24 +281,20 @@ ServerRecvStateStartHand::Process(ServerRecvThread &server) // Send cards to all players. for (int i = 0; i < curGame.getActualQuantityPlayers(); i++) { - if (playerArray[i]->getNetSessionData().get()) // TODO: this is an assert. - { - int cards[2]; - playerArray[i]->getMyCards(cards); - boost::shared_ptr notifyCards(new NetPacketHandStart); - NetPacketHandStart::Data handStartData; - handStartData.yourCards[0] = static_cast(cards[0]); - handStartData.yourCards[1] = static_cast(cards[1]); - static_cast(notifyCards.get())->SetData(handStartData); + assert(playerArray[i]->getNetSessionData().get()); // TODO throw exception - server.GetSender().Send(playerArray[i]->getNetSessionData()->GetSocket(), notifyCards); - } + int cards[2]; + playerArray[i]->getMyCards(cards); + boost::shared_ptr notifyCards(new NetPacketHandStart); + NetPacketHandStart::Data handStartData; + handStartData.yourCards[0] = static_cast(cards[0]); + handStartData.yourCards[1] = static_cast(cards[1]); + static_cast(notifyCards.get())->SetData(handStartData); + + server.GetSender().Send(playerArray[i]->getNetSessionData()->GetSocket(), notifyCards); } - // Start hand. - curGame.startHand(); - - // Auto small blind / big blind at the beginning of preflop. + // Auto small blind / big blind at the beginning of hand. for (int i = 0; i < curGame.getActualQuantityPlayers(); i++) { if(playerArray[i]->getMyButton() == BUTTON_SMALL_BLIND) @@ -320,6 +326,9 @@ ServerRecvStateStartHand::Process(ServerRecvThread &server) } } + // Start hand. + curGame.startHand(); + server.SetState(ServerRecvStateStartRound::Instance()); return MSG_NET_GAME_SERVER_HAND; @@ -345,7 +354,8 @@ ServerRecvStateStartRound::~ServerRecvStateStartRound() void ServerRecvStateStartRound::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr connData) { - // TODO: send error msg + // Do not accept new connections in this state. + server.RejectNewConnection(connData); } int @@ -403,7 +413,7 @@ ServerRecvStateStartRound::GameRun(Game &curGame, int state) curGame.getCurrentHand()->getRiver()->riverRun(); } break; default: { - // TODO + // } } } @@ -427,7 +437,7 @@ ServerRecvStateStartRound::GetCurrentPlayer(Game &curGame) curPlayerNum = curGame.getCurrentHand()->getRiver()->getPlayersTurn(); } break; default: { - // TODO + // } } assert(curPlayerNum < curGame.getActualQuantityPlayers()); @@ -455,7 +465,8 @@ ServerRecvStateFinal::~ServerRecvStateFinal() void ServerRecvStateFinal::HandleNewConnection(ServerRecvThread &server, boost::shared_ptr connData) { - // TODO: send error msg + // Do not accept new connections in this state. + server.RejectNewConnection(connData); } int diff --git a/src/net/common/serverrecvthread.cpp b/src/net/common/serverrecvthread.cpp index e8196b48..5f1624cb 100644 --- a/src/net/common/serverrecvthread.cpp +++ b/src/net/common/serverrecvthread.cpp @@ -246,10 +246,16 @@ ServerRecvThread::CleanupSessionMap() void ServerRecvThread::InternalStartGame() { + SetState(SERVER_START_GAME_STATE::Instance()); + + // Kick all players which are not fully connected. + RemoveNotEstablishedSessions(); + + // Initialize the game. GuiInterface &gui = GetGui(); PlayerDataList playerData = GetPlayerDataList(); - // EngineFactory erstellen + // Create EngineFactory boost::shared_ptr factory(new LocalEngineFactory(m_playerConfig)); // LocalEngine erstellen // Set dealer pos. @@ -274,12 +280,11 @@ ServerRecvThread::InternalStartGame() } ++player_i; } - assert(randDealerFound); + assert(randDealerFound); // TODO: Throw exception. SetStartData(startData); m_game.reset(new Game(&gui, factory, playerData, GetGameData(), GetStartData(), m_curGameId++)); - SetState(SERVER_START_GAME_STATE::Instance()); } SessionWrapper @@ -320,6 +325,15 @@ ServerRecvThread::SessionError(SessionWrapper session, int errorCode) CloseSessionDelayed(session); } +void +ServerRecvThread::RejectNewConnection(boost::shared_ptr connData) +{ + // 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_GAME_ALREADY_RUNNING); +} + void ServerRecvThread::CloseSessionDelayed(SessionWrapper session) { @@ -348,6 +362,39 @@ ServerRecvThread::CloseSessionDelayed(SessionWrapper session) m_closeSessionList.push_back(closeSessionData); } +void +ServerRecvThread::RemoveNotEstablishedSessions() +{ + SessionList removeList; + + SocketSessionMap::iterator session_i = m_sessionMap.begin(); + SocketSessionMap::iterator session_end = m_sessionMap.end(); + + while (session_i != session_end) + { + // Remove all players which are not fully connected. + assert(session_i->second.sessionData.get()); + if (session_i->second.sessionData->GetState() != SessionData::Established) + { + // Do not mess with the map within this loop. + // Just store what needs to be removed. + removeList.push_back(session_i->second); + } + ++session_i; + } + + SessionList::iterator remove_i = removeList.begin(); + SessionList::iterator remove_end = removeList.end(); + + while (remove_i != remove_end) + { + // Inform the players that we are starting without them. + // Gracefully remove them from the server. + SessionError(*remove_i, ERR_NET_GAME_ALREADY_RUNNING); + ++remove_i; + } +} + size_t ServerRecvThread::GetCurNumberOfPlayers() const { @@ -364,6 +411,7 @@ ServerRecvThread::IsPlayerConnected(const std::string &playerName) const PlayerDataList::const_iterator player_i = playerList.begin(); PlayerDataList::const_iterator player_end = playerList.end(); + // Check by name - the name is unique. while (player_i != player_end) { if ((*player_i)->GetName() == playerName) @@ -380,19 +428,19 @@ ServerRecvThread::IsPlayerConnected(const std::string &playerName) const void ServerRecvThread::SetSessionPlayerData(boost::shared_ptr sessionData, boost::shared_ptr playerData) { - if (playerData.get() && !playerData->GetName().empty()) + assert(playerData.get()); + assert(!playerData->GetName().empty()); + assert(sessionData.get()); + + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + SocketSessionMap::iterator pos = m_sessionMap.find(sessionData->GetSocket()); + if (pos != m_sessionMap.end()) { - assert(sessionData.get()); - boost::mutex::scoped_lock lock(m_sessionMapMutex); + pos->second.playerData = playerData; - SocketSessionMap::iterator pos = m_sessionMap.find(sessionData->GetSocket()); - if (pos != m_sessionMap.end()) - { - pos->second.playerData = playerData; - - // Signal joining player to GUI. - GetCallback().SignalNetServerPlayerJoined(playerData->GetName()); - } + // Signal joining player to GUI. + GetCallback().SignalNetServerPlayerJoined(playerData->GetName()); } } @@ -407,9 +455,14 @@ ServerRecvThread::GetPlayerDataList() const while (session_i != session_end) { - boost::shared_ptr tmpPlayer(session_i->second.playerData); - if (tmpPlayer.get() && !tmpPlayer->GetName().empty()) + // Get all players which are fully connected. + if (session_i->second.sessionData->GetState() == SessionData::Established) + { + boost::shared_ptr tmpPlayer(session_i->second.playerData); + assert(tmpPlayer.get()); + assert(!tmpPlayer->GetName().empty()); playerList.push_back(tmpPlayer); + } ++session_i; } // Sort the list by player number. @@ -460,8 +513,11 @@ ServerRecvThread::SendToAllPlayers(boost::shared_ptr packet) while (i != end) { - // Send each client a copy of the packet. - GetSender().Send(i->first, boost::shared_ptr(packet->Clone())); + assert(i->second.sessionData.get()); + + // Send each fully connected client a copy of the packet. + if (i->second.sessionData->GetState() == SessionData::Established) + GetSender().Send(i->first, boost::shared_ptr(packet->Clone())); ++i; } } @@ -477,9 +533,10 @@ ServerRecvThread::SendToAllButOnePlayers(boost::shared_ptr packet, SO while (i != end) { - // Send each client but one a copy of the packet. - if (i->first != except) - GetSender().Send(i->first, boost::shared_ptr(packet->Clone())); + // Send each fully connected client but one a copy of the packet. + if (i->second.sessionData->GetState() == SessionData::Established) + if (i->first != except) + GetSender().Send(i->first, boost::shared_ptr(packet->Clone())); ++i; } } diff --git a/src/net/serverrecvthread.h b/src/net/serverrecvthread.h index 4d4c90dc..a3fc5c9b 100644 --- a/src/net/serverrecvthread.h +++ b/src/net/serverrecvthread.h @@ -83,6 +83,7 @@ protected: typedef std::deque > ConnectQueue; typedef std::map SocketSessionMap; + typedef std::list SessionList; typedef std::deque NotificationQueue; typedef std::list > > CloseSessionList; @@ -102,7 +103,9 @@ protected: SessionWrapper GetSession(SOCKET sock); void AddSession(boost::shared_ptr sessionData); // new Sessions have no player data void SessionError(SessionWrapper session, int errorCode); + void RejectNewConnection(boost::shared_ptr connData); void CloseSessionDelayed(SessionWrapper session); + void RemoveNotEstablishedSessions(); size_t GetCurNumberOfPlayers() const; bool IsPlayerConnected(const std::string &playerName) const; @@ -163,6 +166,7 @@ friend class ServerRecvStateInit; friend class ServerRecvStateStartGame; friend class ServerRecvStateStartHand; friend class ServerRecvStateStartRound; +friend class ServerRecvStateFinal; }; #endif