2007-03-13 23:27:17 +00:00
|
|
|
/***************************************************************************
|
|
|
|
|
* Copyright (C) 2007 by Lothar May *
|
|
|
|
|
* *
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
|
* (at your option) any later version. *
|
|
|
|
|
* *
|
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
|
* *
|
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
|
* along with this program; if not, write to the *
|
|
|
|
|
* Free Software Foundation, Inc., *
|
|
|
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
2007-08-19 20:58:57 +00:00
|
|
|
#include <net/serverlobbythread.h>
|
2007-08-20 20:37:54 +00:00
|
|
|
#include <net/servergamethread.h>
|
2007-03-13 23:27:17 +00:00
|
|
|
#include <net/serverexception.h>
|
|
|
|
|
#include <net/senderthread.h>
|
|
|
|
|
#include <net/sendercallback.h>
|
|
|
|
|
#include <net/receiverhelper.h>
|
|
|
|
|
#include <net/socket_msg.h>
|
2007-10-07 15:52:12 +00:00
|
|
|
#include <core/avatarmanager.h>
|
2007-10-23 21:26:07 +00:00
|
|
|
#include <core/loghelper.h>
|
2007-09-08 11:00:46 +00:00
|
|
|
#include <openssl/rand.h>
|
2007-04-26 23:07:08 +00:00
|
|
|
|
2007-05-08 06:45:46 +00:00
|
|
|
#include <boost/lambda/lambda.hpp>
|
|
|
|
|
|
2007-10-25 21:20:35 +00:00
|
|
|
#define SERVER_MAX_NUM_SESSIONS 512 // Maximum number of idle users in lobby.
|
|
|
|
|
#define SERVER_CACHE_CLEANUP_INTERVAL_SEC 86400 // 1 day
|
2007-10-26 14:54:57 +00:00
|
|
|
#define SERVER_INIT_SESSION_TIMEOUT_SEC 20
|
2007-08-15 13:28:28 +00:00
|
|
|
|
2007-10-25 21:20:35 +00:00
|
|
|
#define SERVER_COMPUTER_PLAYER_NAME "Computer"
|
2007-05-06 23:27:08 +00:00
|
|
|
|
2007-04-26 23:07:08 +00:00
|
|
|
using namespace std;
|
2007-03-13 23:27:17 +00:00
|
|
|
|
2007-05-12 22:00:59 +00:00
|
|
|
|
2007-03-13 23:27:17 +00:00
|
|
|
class ServerSenderCallback : public SenderCallback
|
|
|
|
|
{
|
|
|
|
|
public:
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerSenderCallback(ServerLobbyThread &server) : m_server(server) {}
|
2007-03-13 23:27:17 +00:00
|
|
|
virtual ~ServerSenderCallback() {}
|
|
|
|
|
|
2007-10-28 12:53:54 +00:00
|
|
|
virtual void SignalNetError(SessionId /*session*/, int /*errorID*/, int /*osErrorID*/)
|
2007-03-13 23:27:17 +00:00
|
|
|
{
|
2007-05-05 21:14:23 +00:00
|
|
|
// We just ignore send errors for now, on server side.
|
2007-08-15 13:28:28 +00:00
|
|
|
// A serious send error should trigger a read error or a read
|
2007-05-05 21:14:23 +00:00
|
|
|
// returning 0 afterwards, and we will handle this error.
|
2007-03-13 23:27:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread &m_server;
|
2007-03-13 23:27:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2007-10-07 15:52:12 +00:00
|
|
|
ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig, AvatarManager &avatarManager)
|
|
|
|
|
: m_gui(gui), m_avatarManager(avatarManager), m_playerConfig(playerConfig),
|
2007-10-28 12:53:54 +00:00
|
|
|
m_curGameId(0), m_curUniquePlayerId(0), m_curSessionId(INVALID_SESSION + 1),
|
|
|
|
|
m_totalPlayersLoggedIn(0), m_totalGamesStarted(0)
|
2007-03-13 23:27:17 +00:00
|
|
|
{
|
|
|
|
|
m_senderCallback.reset(new ServerSenderCallback(*this));
|
2007-03-20 11:56:30 +00:00
|
|
|
m_sender.reset(new SenderThread(GetSenderCallback()));
|
|
|
|
|
m_receiver.reset(new ReceiverHelper);
|
2007-03-13 23:27:17 +00:00
|
|
|
}
|
|
|
|
|
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::~ServerLobbyThread()
|
2007-03-13 23:27:17 +00:00
|
|
|
{
|
2007-03-20 11:56:30 +00:00
|
|
|
CleanupConnectQueue();
|
2007-03-13 23:27:17 +00:00
|
|
|
}
|
|
|
|
|
|
2007-04-26 23:07:08 +00:00
|
|
|
void
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::Init(const string &pwd)
|
2007-04-26 23:07:08 +00:00
|
|
|
{
|
|
|
|
|
m_password = pwd;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-13 23:27:17 +00:00
|
|
|
void
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::AddConnection(boost::shared_ptr<ConnectData> data)
|
2007-03-13 23:27:17 +00:00
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_connectQueueMutex);
|
|
|
|
|
m_connectQueue.push_back(data);
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-06 19:09:05 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::ReAddSession(SessionWrapper session, int reason)
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<NetPacket> packet(new NetPacketRemovedFromGame);
|
|
|
|
|
NetPacketRemovedFromGame::Data removedData;
|
|
|
|
|
removedData.removeReason = reason;
|
|
|
|
|
static_cast<NetPacketRemovedFromGame *>(packet.get())->SetData(removedData);
|
2007-10-28 15:06:57 +00:00
|
|
|
GetSender().Send(session.sessionData, packet);
|
2007-09-06 19:09:05 +00:00
|
|
|
|
|
|
|
|
boost::mutex::scoped_lock lock(m_sessionQueueMutex);
|
|
|
|
|
m_sessionQueue.push_back(session);
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-29 14:05:41 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::MoveSessionToGame(ServerGameThread &game, SessionWrapper session)
|
|
|
|
|
{
|
|
|
|
|
// Remove session from the lobby.
|
2007-10-28 12:53:54 +00:00
|
|
|
m_sessionManager.RemoveSession(session.sessionData->GetId());
|
2007-09-29 14:05:41 +00:00
|
|
|
// Session is now in game state.
|
|
|
|
|
session.sessionData->SetState(SessionData::Game);
|
|
|
|
|
// Store it in the list of game sessions.
|
|
|
|
|
m_gameSessionManager.AddSession(session);
|
|
|
|
|
// Add session to the game.
|
|
|
|
|
game.AddSession(session);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ServerLobbyThread::RemoveSessionFromGame(SessionWrapper session)
|
|
|
|
|
{
|
|
|
|
|
// Just remove the session. Only for fatal errors.
|
2007-10-28 15:21:24 +00:00
|
|
|
CloseSession(session);
|
2007-09-29 14:05:41 +00:00
|
|
|
}
|
|
|
|
|
|
2007-08-20 15:30:22 +00:00
|
|
|
void
|
2007-10-28 15:21:24 +00:00
|
|
|
ServerLobbyThread::CloseSession(SessionWrapper session)
|
2007-08-20 15:30:22 +00:00
|
|
|
{
|
2007-10-30 21:25:10 +00:00
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_initTimerSessionMapMutex);
|
|
|
|
|
m_initTimerSessionMap.erase(session.sessionData->GetId());
|
|
|
|
|
}
|
2007-10-28 12:53:54 +00:00
|
|
|
m_sessionManager.RemoveSession(session.sessionData->GetId());
|
|
|
|
|
m_gameSessionManager.RemoveSession(session.sessionData->GetId());
|
2007-08-20 15:30:22 +00:00
|
|
|
|
2007-10-20 23:24:40 +00:00
|
|
|
// Update stats (if needed).
|
|
|
|
|
BroadcastStatisticsUpdate();
|
2007-08-20 15:30:22 +00:00
|
|
|
}
|
|
|
|
|
|
2007-09-02 16:36:52 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::NotifyPlayerJoinedGame(unsigned gameId, unsigned playerId)
|
|
|
|
|
{
|
|
|
|
|
// Send notification to players in lobby.
|
|
|
|
|
boost::shared_ptr<NetPacket> packet(new NetPacketGameListPlayerJoined);
|
|
|
|
|
NetPacketGameListPlayerJoined::Data packetData;
|
|
|
|
|
packetData.gameId = gameId;
|
|
|
|
|
packetData.playerId = playerId;
|
|
|
|
|
static_cast<NetPacketGameListPlayerJoined *>(packet.get())->SetData(packetData);
|
2007-10-30 21:02:52 +00:00
|
|
|
m_sessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Established);
|
|
|
|
|
m_gameSessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Game);
|
2007-09-02 16:36:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ServerLobbyThread::NotifyPlayerLeftGame(unsigned gameId, unsigned playerId)
|
|
|
|
|
{
|
|
|
|
|
// Send notification to players in lobby.
|
|
|
|
|
boost::shared_ptr<NetPacket> packet(new NetPacketGameListPlayerLeft);
|
|
|
|
|
NetPacketGameListPlayerLeft::Data packetData;
|
|
|
|
|
packetData.gameId = gameId;
|
|
|
|
|
packetData.playerId = playerId;
|
|
|
|
|
static_cast<NetPacketGameListPlayerLeft *>(packet.get())->SetData(packetData);
|
2007-10-30 21:02:52 +00:00
|
|
|
m_sessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Established);
|
|
|
|
|
m_gameSessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Game);
|
2007-09-29 14:05:41 +00:00
|
|
|
}
|
|
|
|
|
|
2007-10-12 14:32:25 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::NotifyGameAdminChanged(unsigned gameId, unsigned newAdminPlayerId)
|
|
|
|
|
{
|
|
|
|
|
// Send notification to players in lobby.
|
|
|
|
|
boost::shared_ptr<NetPacket> packet(new NetPacketGameListAdminChanged);
|
|
|
|
|
NetPacketGameListAdminChanged::Data packetData;
|
|
|
|
|
packetData.gameId = gameId;
|
|
|
|
|
packetData.newAdminplayerId = newAdminPlayerId;
|
|
|
|
|
static_cast<NetPacketGameListAdminChanged *>(packet.get())->SetData(packetData);
|
2007-10-30 21:02:52 +00:00
|
|
|
m_sessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Established);
|
|
|
|
|
m_gameSessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Game);
|
2007-10-12 14:32:25 +00:00
|
|
|
}
|
|
|
|
|
|
2007-09-29 20:20:01 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::NotifyStartingGame(unsigned gameId)
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<NetPacket> packet = CreateNetPacketGameListUpdate(gameId, GAME_MODE_STARTED);
|
2007-10-30 21:02:52 +00:00
|
|
|
m_sessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Established);
|
|
|
|
|
m_gameSessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Game);
|
2007-09-29 20:20:01 +00:00
|
|
|
}
|
|
|
|
|
|
2007-10-08 20:14:44 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::NotifyReopeningGame(unsigned gameId)
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<NetPacket> packet = CreateNetPacketGameListUpdate(gameId, GAME_MODE_CREATED);
|
2007-10-30 21:02:52 +00:00
|
|
|
m_sessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Established);
|
|
|
|
|
m_gameSessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Game);
|
2007-10-08 20:14:44 +00:00
|
|
|
}
|
|
|
|
|
|
2007-09-29 14:05:41 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::HandleGameRetrievePlayerInfo(SessionWrapper session, const NetPacketRetrievePlayerInfo &tmpPacket)
|
|
|
|
|
{
|
|
|
|
|
// Someone within a game requested player info.
|
|
|
|
|
HandleNetPacketRetrievePlayerInfo(session, tmpPacket);
|
2007-09-02 16:36:52 +00:00
|
|
|
}
|
|
|
|
|
|
2007-10-07 18:46:40 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::HandleGameRetrieveAvatar(SessionWrapper session, const NetPacketRetrieveAvatar &tmpPacket)
|
|
|
|
|
{
|
|
|
|
|
// Someone within a game requested an avatar.
|
|
|
|
|
HandleNetPacketRetrieveAvatar(session, tmpPacket);
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-07 21:23:37 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::AddComputerPlayer(boost::shared_ptr<PlayerData> player)
|
|
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_computerPlayersMutex);
|
|
|
|
|
m_computerPlayers.insert(PlayerDataMap::value_type(player->GetUniqueId(), player));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ServerLobbyThread::RemoveComputerPlayer(boost::shared_ptr<PlayerData> player)
|
|
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_computerPlayersMutex);
|
|
|
|
|
m_computerPlayers.erase(player->GetUniqueId());
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-21 17:27:13 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::RemoveGame(unsigned id)
|
|
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_removeGameListMutex);
|
|
|
|
|
m_removeGameList.push_back(id);
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-07 15:52:12 +00:00
|
|
|
AvatarManager &
|
|
|
|
|
ServerLobbyThread::GetAvatarManager()
|
|
|
|
|
{
|
|
|
|
|
return m_avatarManager;
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-15 13:28:28 +00:00
|
|
|
u_int32_t
|
|
|
|
|
ServerLobbyThread::GetNextUniquePlayerId()
|
2007-03-20 14:05:16 +00:00
|
|
|
{
|
2007-09-02 20:59:16 +00:00
|
|
|
boost::mutex::scoped_lock lock(m_curUniquePlayerIdMutex);
|
2007-08-15 13:28:28 +00:00
|
|
|
return m_curUniquePlayerId++;
|
2007-03-20 14:05:16 +00:00
|
|
|
}
|
|
|
|
|
|
2007-08-20 20:37:54 +00:00
|
|
|
u_int32_t
|
|
|
|
|
ServerLobbyThread::GetNextGameId()
|
|
|
|
|
{
|
|
|
|
|
return m_curGameId++;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-13 23:27:17 +00:00
|
|
|
void
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::Main()
|
2007-03-13 23:27:17 +00:00
|
|
|
{
|
|
|
|
|
GetSender().Run();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
while (!ShouldTerminate())
|
|
|
|
|
{
|
2007-10-26 14:54:57 +00:00
|
|
|
// Process new connections.
|
|
|
|
|
NewConnectionLoop();
|
|
|
|
|
// Process re-added sessions.
|
|
|
|
|
NewSessionLoop();
|
|
|
|
|
// Main loop.
|
2007-08-15 13:28:28 +00:00
|
|
|
ProcessLoop();
|
2007-05-06 23:27:08 +00:00
|
|
|
// Close sessions.
|
|
|
|
|
CloseSessionLoop();
|
2007-08-21 17:27:13 +00:00
|
|
|
// Remove games.
|
|
|
|
|
RemoveGameLoop();
|
2007-10-25 21:20:35 +00:00
|
|
|
// Cleanup cache.
|
|
|
|
|
CleanupAvatarCache();
|
2007-03-13 23:27:17 +00:00
|
|
|
}
|
2007-10-18 20:36:49 +00:00
|
|
|
} catch (const PokerTHException &e)
|
2007-03-13 23:27:17 +00:00
|
|
|
{
|
2007-06-10 23:28:25 +00:00
|
|
|
GetCallback().SignalNetServerError(e.GetErrorId(), e.GetOsErrorCode());
|
2007-10-23 21:26:07 +00:00
|
|
|
LOG_ERROR(e.what());
|
2007-03-13 23:27:17 +00:00
|
|
|
}
|
2007-08-21 12:34:33 +00:00
|
|
|
|
|
|
|
|
TerminateGames();
|
|
|
|
|
|
2007-03-13 23:27:17 +00:00
|
|
|
GetSender().SignalTermination();
|
2007-10-29 12:57:29 +00:00
|
|
|
if (!GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT))
|
2007-10-29 18:49:28 +00:00
|
|
|
LOG_ERROR("Fatal error: Unable to terminated Sender Thread in Lobby.");
|
2007-03-20 02:20:50 +00:00
|
|
|
|
2007-03-20 11:56:30 +00:00
|
|
|
CleanupConnectQueue();
|
2007-03-20 02:20:50 +00:00
|
|
|
}
|
|
|
|
|
|
2007-03-20 14:05:16 +00:00
|
|
|
void
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::ProcessLoop()
|
2007-03-20 14:05:16 +00:00
|
|
|
{
|
2007-08-15 13:28:28 +00:00
|
|
|
// Wait for data.
|
|
|
|
|
SessionWrapper session = m_sessionManager.Select(RECV_TIMEOUT_MSEC);
|
2007-03-20 14:05:16 +00:00
|
|
|
|
2007-08-15 13:28:28 +00:00
|
|
|
if (session.sessionData.get())
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<NetPacket> packet;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Receive the next packet.
|
2007-09-03 16:35:45 +00:00
|
|
|
packet = GetReceiver().Recv(session.sessionData->GetSocket(), session.sessionData->GetReceiveBuffer());
|
2007-08-15 13:28:28 +00:00
|
|
|
} catch (const NetException &)
|
|
|
|
|
{
|
|
|
|
|
// On error: Close this session.
|
2007-10-28 15:21:24 +00:00
|
|
|
CloseSession(session);
|
2007-08-15 13:28:28 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (packet.get())
|
|
|
|
|
{
|
2007-10-07 15:52:12 +00:00
|
|
|
if (session.sessionData->GetState() == SessionData::Init)
|
2007-08-15 13:28:28 +00:00
|
|
|
{
|
2007-10-07 15:52:12 +00:00
|
|
|
if (packet->ToNetPacketInit())
|
2007-08-15 13:28:28 +00:00
|
|
|
HandleNetPacketInit(session, *packet->ToNetPacketInit());
|
2007-10-07 15:52:12 +00:00
|
|
|
else if (packet->ToNetPacketAvatarHeader())
|
|
|
|
|
HandleNetPacketAvatarHeader(session, *packet->ToNetPacketAvatarHeader());
|
2007-10-11 20:42:44 +00:00
|
|
|
else if (packet->ToNetPacketUnknownAvatar())
|
|
|
|
|
HandleNetPacketUnknownAvatar(session, *packet->ToNetPacketUnknownAvatar());
|
2007-10-07 15:52:12 +00:00
|
|
|
else
|
|
|
|
|
SessionError(session, ERR_SOCK_INVALID_STATE);
|
|
|
|
|
}
|
|
|
|
|
else if (session.sessionData->GetState() == SessionData::ReceivingAvatar)
|
|
|
|
|
{
|
|
|
|
|
if (packet->ToNetPacketAvatarFile())
|
|
|
|
|
HandleNetPacketAvatarFile(session, *packet->ToNetPacketAvatarFile());
|
|
|
|
|
else if (packet->ToNetPacketAvatarEnd())
|
|
|
|
|
HandleNetPacketAvatarEnd(session, *packet->ToNetPacketAvatarEnd());
|
|
|
|
|
else
|
|
|
|
|
SessionError(session, ERR_SOCK_INVALID_STATE);
|
2007-08-15 13:28:28 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2007-08-26 22:41:37 +00:00
|
|
|
if (packet->ToNetPacketRetrievePlayerInfo())
|
|
|
|
|
HandleNetPacketRetrievePlayerInfo(session, *packet->ToNetPacketRetrievePlayerInfo());
|
2007-10-07 18:46:40 +00:00
|
|
|
else if (packet->ToNetPacketRetrieveAvatar())
|
|
|
|
|
HandleNetPacketRetrieveAvatar(session, *packet->ToNetPacketRetrieveAvatar());
|
2007-08-26 22:41:37 +00:00
|
|
|
else if (packet->ToNetPacketCreateGame())
|
2007-08-15 13:28:28 +00:00
|
|
|
HandleNetPacketCreateGame(session, *packet->ToNetPacketCreateGame());
|
|
|
|
|
else if (packet->ToNetPacketJoinGame())
|
|
|
|
|
HandleNetPacketJoinGame(session, *packet->ToNetPacketJoinGame());
|
2007-10-07 15:52:12 +00:00
|
|
|
else
|
|
|
|
|
SessionError(session, ERR_SOCK_INVALID_STATE);
|
2007-08-15 13:28:28 +00:00
|
|
|
}
|
|
|
|
|
}
|
2007-03-20 14:05:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-06 23:27:08 +00:00
|
|
|
void
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::HandleNetPacketInit(SessionWrapper session, const NetPacketInit &tmpPacket)
|
|
|
|
|
{
|
|
|
|
|
NetPacketInit::Data initData;
|
|
|
|
|
tmpPacket.GetData(initData);
|
|
|
|
|
|
|
|
|
|
// Check the protocol version.
|
|
|
|
|
if (initData.versionMajor != NET_VERSION_MAJOR)
|
|
|
|
|
{
|
|
|
|
|
SessionError(session, ERR_NET_VERSION_NOT_SUPPORTED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check the server password.
|
|
|
|
|
if (!CheckPassword(initData.password))
|
|
|
|
|
{
|
|
|
|
|
SessionError(session, ERR_NET_INVALID_PASSWORD);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check whether the player name is correct.
|
|
|
|
|
// Partly, this is also done in netpacket.
|
|
|
|
|
// However, some disallowed names are checked only here.
|
|
|
|
|
if (initData.playerName.empty() || initData.playerName.size() > MAX_NAME_SIZE
|
2007-08-27 09:57:51 +00:00
|
|
|
|| initData.playerName[0] == '#'
|
2007-10-15 08:35:56 +00:00
|
|
|
|| initData.playerName[0] == ' '
|
2007-08-15 13:28:28 +00:00
|
|
|
|| initData.playerName.substr(0, sizeof(SERVER_COMPUTER_PLAYER_NAME) - 1) == SERVER_COMPUTER_PLAYER_NAME)
|
|
|
|
|
{
|
|
|
|
|
SessionError(session, ERR_NET_INVALID_PLAYER_NAME);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check whether this player is already connected.
|
2007-08-21 17:27:13 +00:00
|
|
|
if (IsPlayerConnected(initData.playerName))
|
2007-08-15 13:28:28 +00:00
|
|
|
{
|
|
|
|
|
SessionError(session, ERR_NET_PLAYER_NAME_IN_USE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create player data object.
|
|
|
|
|
boost::shared_ptr<PlayerData> tmpPlayerData(
|
|
|
|
|
new PlayerData(GetNextUniquePlayerId(), 0, PLAYER_TYPE_HUMAN, PLAYER_RIGHTS_NORMAL));
|
|
|
|
|
tmpPlayerData->SetName(initData.playerName);
|
|
|
|
|
tmpPlayerData->SetNetSessionData(session.sessionData);
|
2007-11-01 00:12:47 +00:00
|
|
|
if (initData.showAvatar)
|
|
|
|
|
tmpPlayerData->SetAvatarMD5(initData.avatar);
|
2007-08-15 13:28:28 +00:00
|
|
|
|
|
|
|
|
// Set player data for session.
|
2007-10-28 12:53:54 +00:00
|
|
|
m_sessionManager.SetSessionPlayerData(session.sessionData->GetId(), tmpPlayerData);
|
2007-10-07 15:52:12 +00:00
|
|
|
session.playerData = tmpPlayerData;
|
2007-08-15 13:28:28 +00:00
|
|
|
|
2007-11-01 00:12:47 +00:00
|
|
|
if (initData.showAvatar && !initData.avatar.IsZero() && !GetAvatarManager().HasAvatar(initData.avatar))
|
|
|
|
|
RequestPlayerAvatar(session);
|
|
|
|
|
else
|
2007-10-07 15:52:12 +00:00
|
|
|
EstablishSession(session);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ServerLobbyThread::HandleNetPacketAvatarHeader(SessionWrapper session, const NetPacketAvatarHeader &tmpPacket)
|
|
|
|
|
{
|
|
|
|
|
if (session.playerData.get())
|
|
|
|
|
{
|
|
|
|
|
NetPacketAvatarHeader::Data headerData;
|
|
|
|
|
tmpPacket.GetData(headerData);
|
|
|
|
|
|
2007-10-18 23:00:55 +00:00
|
|
|
if (headerData.avatarFileSize >= MIN_AVATAR_FILE_SIZE && headerData.avatarFileSize <= MAX_AVATAR_FILE_SIZE)
|
2007-10-07 15:52:12 +00:00
|
|
|
{
|
|
|
|
|
boost::shared_ptr<AvatarData> tmpAvatarData(new AvatarData);
|
|
|
|
|
tmpAvatarData->fileData.reserve(headerData.avatarFileSize);
|
|
|
|
|
tmpAvatarData->fileType = headerData.avatarFileType;
|
|
|
|
|
tmpAvatarData->reportedSize = headerData.avatarFileSize;
|
|
|
|
|
// Ignore request id for now.
|
|
|
|
|
|
|
|
|
|
session.playerData->SetNetAvatarData(tmpAvatarData);
|
|
|
|
|
|
|
|
|
|
// Session is now receiving an avatar.
|
|
|
|
|
session.sessionData->SetState(SessionData::ReceivingAvatar);
|
|
|
|
|
}
|
2007-10-10 22:21:24 +00:00
|
|
|
else
|
|
|
|
|
SessionError(session, ERR_NET_AVATAR_TOO_LARGE);
|
2007-10-07 15:52:12 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-11 20:42:44 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::HandleNetPacketUnknownAvatar(SessionWrapper session, const NetPacketUnknownAvatar &/*tmpPacket*/)
|
|
|
|
|
{
|
|
|
|
|
if (session.playerData.get())
|
|
|
|
|
{
|
|
|
|
|
// Free memory (just in case).
|
|
|
|
|
session.playerData->SetNetAvatarData(boost::shared_ptr<AvatarData>());
|
2007-10-31 19:21:54 +00:00
|
|
|
session.playerData->SetAvatarMD5(MD5Buf());
|
2007-10-11 20:42:44 +00:00
|
|
|
// Start session.
|
|
|
|
|
EstablishSession(session);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-07 15:52:12 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::HandleNetPacketAvatarFile(SessionWrapper session, const NetPacketAvatarFile &tmpPacket)
|
|
|
|
|
{
|
|
|
|
|
if (session.playerData.get())
|
|
|
|
|
{
|
|
|
|
|
NetPacketAvatarFile::Data data;
|
|
|
|
|
tmpPacket.GetData(data);
|
|
|
|
|
|
|
|
|
|
boost::shared_ptr<AvatarData> tmpAvatar = session.playerData->GetNetAvatarData();
|
|
|
|
|
if (tmpAvatar.get() && tmpAvatar->fileData.size() + data.fileData.size() <= tmpAvatar->reportedSize)
|
|
|
|
|
{
|
|
|
|
|
std::copy(data.fileData.begin(), data.fileData.end(), back_inserter(tmpAvatar->fileData));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2007-10-10 22:21:24 +00:00
|
|
|
ServerLobbyThread::HandleNetPacketAvatarEnd(SessionWrapper session, const NetPacketAvatarEnd &/*tmpPacket*/)
|
2007-10-07 15:52:12 +00:00
|
|
|
{
|
|
|
|
|
if (session.playerData.get())
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<AvatarData> tmpAvatar = session.playerData->GetNetAvatarData();
|
|
|
|
|
MD5Buf avatarMD5 = session.playerData->GetAvatarMD5();
|
|
|
|
|
if (!avatarMD5.IsZero() && tmpAvatar.get())
|
|
|
|
|
{
|
|
|
|
|
unsigned avatarSize = (unsigned)tmpAvatar->fileData.size();
|
|
|
|
|
if (avatarSize == tmpAvatar->reportedSize)
|
|
|
|
|
{
|
2007-10-24 23:17:12 +00:00
|
|
|
if (!GetAvatarManager().StoreAvatarInCache(avatarMD5, tmpAvatar->fileType, &tmpAvatar->fileData[0], avatarSize))
|
2007-10-31 20:23:27 +00:00
|
|
|
{
|
|
|
|
|
session.playerData->SetAvatarMD5(MD5Buf());
|
2007-10-24 23:17:12 +00:00
|
|
|
LOG_ERROR("Failed to store avatar in cache directory.");
|
2007-10-31 20:23:27 +00:00
|
|
|
}
|
2007-10-24 23:17:12 +00:00
|
|
|
|
2007-10-07 15:52:12 +00:00
|
|
|
// Free memory.
|
|
|
|
|
session.playerData->SetNetAvatarData(boost::shared_ptr<AvatarData>());
|
|
|
|
|
// Init finished - start session.
|
|
|
|
|
EstablishSession(session);
|
|
|
|
|
}
|
2007-10-10 22:21:24 +00:00
|
|
|
else
|
|
|
|
|
SessionError(session, ERR_NET_WRONG_AVATAR_SIZE);
|
2007-10-07 15:52:12 +00:00
|
|
|
}
|
|
|
|
|
}
|
2007-08-15 13:28:28 +00:00
|
|
|
}
|
|
|
|
|
|
2007-08-26 22:41:37 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::HandleNetPacketRetrievePlayerInfo(SessionWrapper session, const NetPacketRetrievePlayerInfo &tmpPacket)
|
|
|
|
|
{
|
|
|
|
|
NetPacketRetrievePlayerInfo::Data request;
|
|
|
|
|
tmpPacket.GetData(request);
|
|
|
|
|
|
|
|
|
|
// Find player in lobby or in a game.
|
2007-09-02 20:59:16 +00:00
|
|
|
boost::shared_ptr<PlayerData> tmpPlayer = m_sessionManager.GetSessionByUniquePlayerId(request.playerId).playerData;
|
|
|
|
|
if (!tmpPlayer.get())
|
2007-09-29 14:05:41 +00:00
|
|
|
tmpPlayer = m_gameSessionManager.GetSessionByUniquePlayerId(request.playerId).playerData;
|
2007-10-07 21:23:37 +00:00
|
|
|
if (!tmpPlayer.get())
|
|
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_computerPlayersMutex);
|
|
|
|
|
PlayerDataMap::const_iterator pos = m_computerPlayers.find(request.playerId);
|
|
|
|
|
if (pos != m_computerPlayers.end())
|
|
|
|
|
tmpPlayer = pos->second;
|
|
|
|
|
}
|
2007-08-26 22:41:37 +00:00
|
|
|
|
2007-09-02 20:59:16 +00:00
|
|
|
if (tmpPlayer.get())
|
2007-08-26 22:41:37 +00:00
|
|
|
{
|
|
|
|
|
// Send player info to client.
|
|
|
|
|
boost::shared_ptr<NetPacket> info(new NetPacketPlayerInfo);
|
|
|
|
|
NetPacketPlayerInfo::Data infoData;
|
2007-09-02 20:59:16 +00:00
|
|
|
infoData.playerId = tmpPlayer->GetUniqueId();
|
|
|
|
|
infoData.playerInfo.ptype = tmpPlayer->GetType();
|
|
|
|
|
infoData.playerInfo.playerName = tmpPlayer->GetName();
|
2007-10-07 15:52:12 +00:00
|
|
|
infoData.playerInfo.hasAvatar = !tmpPlayer->GetAvatarMD5().IsZero();
|
2007-09-09 00:00:19 +00:00
|
|
|
if (infoData.playerInfo.hasAvatar)
|
2007-10-07 15:52:12 +00:00
|
|
|
infoData.playerInfo.avatar = tmpPlayer->GetAvatarMD5();
|
2007-08-26 22:41:37 +00:00
|
|
|
static_cast<NetPacketPlayerInfo *>(info.get())->SetData(infoData);
|
2007-10-28 15:06:57 +00:00
|
|
|
GetSender().Send(session.sessionData, info);
|
2007-08-26 22:41:37 +00:00
|
|
|
}
|
2007-10-11 20:42:44 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Unknown player id - notify client.
|
|
|
|
|
boost::shared_ptr<NetPacket> unknown(new NetPacketUnknownPlayerId);
|
|
|
|
|
NetPacketUnknownPlayerId::Data unknownData;
|
|
|
|
|
unknownData.playerId = request.playerId;
|
|
|
|
|
static_cast<NetPacketUnknownPlayerId *>(unknown.get())->SetData(unknownData);
|
2007-10-28 15:06:57 +00:00
|
|
|
GetSender().Send(session.sessionData, unknown);
|
2007-10-11 20:42:44 +00:00
|
|
|
}
|
2007-08-26 22:41:37 +00:00
|
|
|
}
|
|
|
|
|
|
2007-10-07 18:46:40 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::HandleNetPacketRetrieveAvatar(SessionWrapper session, const NetPacketRetrieveAvatar &tmpPacket)
|
|
|
|
|
{
|
2007-10-11 20:42:44 +00:00
|
|
|
bool avatarFound = false;
|
2007-10-07 18:46:40 +00:00
|
|
|
NetPacketRetrieveAvatar::Data request;
|
|
|
|
|
tmpPacket.GetData(request);
|
|
|
|
|
|
|
|
|
|
string tmpFile;
|
|
|
|
|
if (GetAvatarManager().GetAvatarFileName(request.avatar, tmpFile))
|
|
|
|
|
{
|
|
|
|
|
NetPacketList tmpPackets;
|
2007-10-24 23:17:12 +00:00
|
|
|
if (GetAvatarManager().AvatarFileToNetPackets(tmpFile, request.requestId, tmpPackets) == 0)
|
2007-10-11 20:42:44 +00:00
|
|
|
{
|
|
|
|
|
avatarFound = true;
|
2007-10-28 15:06:57 +00:00
|
|
|
GetSender().SendLowPrio(session.sessionData, tmpPackets);
|
2007-10-11 20:42:44 +00:00
|
|
|
}
|
2007-10-24 23:17:12 +00:00
|
|
|
else
|
|
|
|
|
LOG_ERROR("Failed to read avatar file for network transmission.");
|
2007-10-11 20:42:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!avatarFound)
|
|
|
|
|
{
|
|
|
|
|
// Notify client we didn't find the avatar.
|
|
|
|
|
boost::shared_ptr<NetPacket> unknown(new NetPacketUnknownAvatar);
|
|
|
|
|
NetPacketUnknownAvatar::Data unknownData;
|
|
|
|
|
unknownData.requestId = request.requestId;
|
|
|
|
|
static_cast<NetPacketUnknownAvatar *>(unknown.get())->SetData(unknownData);
|
2007-10-28 15:06:57 +00:00
|
|
|
GetSender().Send(session.sessionData, unknown);
|
2007-10-07 18:46:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-15 13:28:28 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::HandleNetPacketCreateGame(SessionWrapper session, const NetPacketCreateGame &tmpPacket)
|
|
|
|
|
{
|
2007-08-20 20:37:54 +00:00
|
|
|
// Create a new game.
|
|
|
|
|
NetPacketCreateGame::Data createGameData;
|
|
|
|
|
tmpPacket.GetData(createGameData);
|
|
|
|
|
|
|
|
|
|
boost::shared_ptr<ServerGameThread> game(
|
2007-09-04 12:44:11 +00:00
|
|
|
new ServerGameThread(
|
2007-10-12 14:32:25 +00:00
|
|
|
*this,
|
|
|
|
|
GetNextGameId(),
|
2007-09-04 12:44:11 +00:00
|
|
|
createGameData.gameName,
|
|
|
|
|
createGameData.password,
|
2007-10-25 21:59:06 +00:00
|
|
|
createGameData.gameData,
|
2007-10-12 14:32:25 +00:00
|
|
|
session.playerData->GetUniqueId(),
|
2007-09-04 12:44:11 +00:00
|
|
|
GetGui(),
|
|
|
|
|
m_playerConfig));
|
2007-08-20 20:37:54 +00:00
|
|
|
|
2007-09-29 14:05:41 +00:00
|
|
|
MoveSessionToGame(*game, session);
|
2007-08-20 20:37:54 +00:00
|
|
|
|
2007-08-21 19:50:13 +00:00
|
|
|
// Add game to list of games.
|
|
|
|
|
InternalAddGame(game);
|
2007-08-20 20:37:54 +00:00
|
|
|
|
2007-08-20 22:55:39 +00:00
|
|
|
// Start the game.
|
|
|
|
|
game->Run();
|
2007-08-15 13:28:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ServerLobbyThread::HandleNetPacketJoinGame(SessionWrapper session, const NetPacketJoinGame &tmpPacket)
|
|
|
|
|
{
|
2007-08-20 20:37:54 +00:00
|
|
|
// Join an existing game.
|
|
|
|
|
NetPacketJoinGame::Data joinGameData;
|
|
|
|
|
tmpPacket.GetData(joinGameData);
|
|
|
|
|
|
|
|
|
|
GameMap::iterator pos = m_gameMap.find(joinGameData.gameId);
|
|
|
|
|
|
|
|
|
|
if (pos != m_gameMap.end())
|
|
|
|
|
{
|
|
|
|
|
ServerGameThread &game = *pos->second;
|
|
|
|
|
if (game.CheckPassword(joinGameData.password))
|
|
|
|
|
{
|
2007-09-29 14:05:41 +00:00
|
|
|
MoveSessionToGame(game, session);
|
2007-08-20 20:37:54 +00:00
|
|
|
}
|
2007-08-21 17:27:13 +00:00
|
|
|
else
|
|
|
|
|
{
|
2007-10-28 15:06:57 +00:00
|
|
|
SendJoinGameFailed(session.sessionData, NTF_NET_JOIN_INVALID_PASSWORD);
|
2007-08-21 17:27:13 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SessionError(session, ERR_NET_UNKNOWN_GAME);
|
2007-08-20 20:37:54 +00:00
|
|
|
}
|
2007-08-15 13:28:28 +00:00
|
|
|
}
|
|
|
|
|
|
2007-10-07 15:52:12 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::EstablishSession(SessionWrapper session)
|
|
|
|
|
{
|
2007-11-10 22:18:31 +00:00
|
|
|
if (!session.playerData.get())
|
2007-11-10 22:29:00 +00:00
|
|
|
throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
|
2007-10-07 15:52:12 +00:00
|
|
|
// Send ACK to client.
|
|
|
|
|
boost::shared_ptr<NetPacket> initAck(new NetPacketInitAck);
|
|
|
|
|
NetPacketInitAck::Data initAckData;
|
2007-10-12 13:07:04 +00:00
|
|
|
initAckData.latestGameVersion = POKERTH_VERSION;
|
|
|
|
|
initAckData.latestBetaRevision = POKERTH_BETA_REVISION;
|
2007-10-07 15:52:12 +00:00
|
|
|
initAckData.sessionId = session.sessionData->GetId(); // TODO: currently unused.
|
|
|
|
|
initAckData.playerId = session.playerData->GetUniqueId();
|
|
|
|
|
static_cast<NetPacketInitAck *>(initAck.get())->SetData(initAckData);
|
2007-10-28 15:06:57 +00:00
|
|
|
GetSender().Send(session.sessionData, initAck);
|
2007-10-07 15:52:12 +00:00
|
|
|
|
|
|
|
|
// Send the game list to the client.
|
2007-10-28 15:06:57 +00:00
|
|
|
SendGameList(session.sessionData);
|
2007-10-07 15:52:12 +00:00
|
|
|
|
|
|
|
|
// Session is now established.
|
2007-10-30 21:25:10 +00:00
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_initTimerSessionMapMutex);
|
|
|
|
|
m_initTimerSessionMap.erase(session.sessionData->GetId());
|
|
|
|
|
}
|
2007-10-07 15:52:12 +00:00
|
|
|
session.sessionData->SetState(SessionData::Established);
|
2007-10-20 22:22:11 +00:00
|
|
|
|
2007-10-30 21:25:10 +00:00
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_statMutex);
|
|
|
|
|
++m_totalPlayersLoggedIn;
|
|
|
|
|
}
|
2007-10-20 22:22:11 +00:00
|
|
|
|
|
|
|
|
BroadcastStatisticsUpdate();
|
2007-10-07 15:52:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ServerLobbyThread::RequestPlayerAvatar(SessionWrapper session)
|
|
|
|
|
{
|
2007-11-10 22:18:31 +00:00
|
|
|
if (!session.playerData.get())
|
2007-11-10 22:29:00 +00:00
|
|
|
throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
|
2007-10-07 15:52:12 +00:00
|
|
|
// Ask the client to send its avatar.
|
|
|
|
|
boost::shared_ptr<NetPacket> retrieveAvatar(new NetPacketRetrieveAvatar);
|
|
|
|
|
NetPacketRetrieveAvatar::Data retrieveAvatarData;
|
2007-10-08 18:49:13 +00:00
|
|
|
retrieveAvatarData.requestId = session.playerData->GetUniqueId();
|
2007-10-07 15:52:12 +00:00
|
|
|
retrieveAvatarData.avatar = session.playerData->GetAvatarMD5();
|
|
|
|
|
static_cast<NetPacketRetrieveAvatar *>(retrieveAvatar.get())->SetData(retrieveAvatarData);
|
2007-10-28 15:06:57 +00:00
|
|
|
GetSender().Send(session.sessionData, retrieveAvatar);
|
2007-10-07 15:52:12 +00:00
|
|
|
}
|
|
|
|
|
|
2007-10-26 14:54:57 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::NewConnectionLoop()
|
|
|
|
|
{
|
|
|
|
|
// Handle one incoming connection at a time.
|
|
|
|
|
boost::shared_ptr<ConnectData> tmpData;
|
|
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_connectQueueMutex);
|
|
|
|
|
if (!m_connectQueue.empty())
|
|
|
|
|
{
|
|
|
|
|
tmpData = m_connectQueue.front();
|
|
|
|
|
m_connectQueue.pop_front();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (tmpData.get())
|
|
|
|
|
HandleNewConnection(tmpData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ServerLobbyThread::NewSessionLoop()
|
|
|
|
|
{
|
|
|
|
|
// Handle one incoming session at a time.
|
|
|
|
|
SessionWrapper tmpSession;
|
|
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_sessionQueueMutex);
|
|
|
|
|
if (!m_sessionQueue.empty())
|
|
|
|
|
{
|
|
|
|
|
tmpSession = m_sessionQueue.front();
|
|
|
|
|
m_sessionQueue.pop_front();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (tmpSession.sessionData.get() && tmpSession.playerData.get())
|
|
|
|
|
HandleReAddedSession(tmpSession);
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-15 13:28:28 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::CloseSessionLoop()
|
2007-05-06 23:27:08 +00:00
|
|
|
{
|
2007-10-30 21:25:10 +00:00
|
|
|
boost::mutex::scoped_lock lock(m_initTimerSessionMapMutex);
|
|
|
|
|
InitTimerSessionMap::iterator i = m_initTimerSessionMap.begin();
|
|
|
|
|
InitTimerSessionMap::iterator end = m_initTimerSessionMap.end();
|
2007-05-06 23:27:08 +00:00
|
|
|
|
2007-10-30 21:25:10 +00:00
|
|
|
// Remove sessions if they do not initialize within a certain period.
|
|
|
|
|
while (i != end)
|
|
|
|
|
{
|
|
|
|
|
InitTimerSessionMap::iterator next = i;
|
|
|
|
|
++next;
|
|
|
|
|
if (i->second.elapsed().total_seconds() > SERVER_INIT_SESSION_TIMEOUT_SEC)
|
2007-10-26 14:54:57 +00:00
|
|
|
{
|
2007-10-30 21:25:10 +00:00
|
|
|
m_sessionManager.RemoveSession(i->first);
|
|
|
|
|
m_initTimerSessionMap.erase(i);
|
2007-10-26 14:54:57 +00:00
|
|
|
}
|
2007-10-30 21:25:10 +00:00
|
|
|
i = next;
|
2007-10-26 14:54:57 +00:00
|
|
|
}
|
2007-05-06 23:27:08 +00:00
|
|
|
}
|
|
|
|
|
|
2007-08-21 17:27:13 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::RemoveGameLoop()
|
|
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_removeGameListMutex);
|
|
|
|
|
|
|
|
|
|
RemoveGameList::iterator i = m_removeGameList.begin();
|
|
|
|
|
RemoveGameList::iterator end = m_removeGameList.end();
|
|
|
|
|
|
|
|
|
|
// Synchronously remove games which have been closed.
|
|
|
|
|
while (i != end)
|
|
|
|
|
{
|
|
|
|
|
GameMap::iterator pos = m_gameMap.find(*i);
|
|
|
|
|
if (pos != m_gameMap.end())
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<ServerGameThread> tmpGame = pos->second;
|
|
|
|
|
tmpGame->SignalTermination();
|
2007-10-29 12:57:29 +00:00
|
|
|
if (!tmpGame->Join(GAME_THREAD_TERMINATE_TIMEOUT))
|
2007-10-29 18:49:28 +00:00
|
|
|
throw ServerException(__FILE__, __LINE__, ERR_NET_GAME_TERMINATION_FAILED, 0);
|
2007-08-21 19:50:13 +00:00
|
|
|
InternalRemoveGame(tmpGame);
|
2007-08-21 17:27:13 +00:00
|
|
|
}
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
m_removeGameList.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-25 21:20:35 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::CleanupAvatarCache()
|
|
|
|
|
{
|
|
|
|
|
// Only act on timer and if there are no sessions.
|
|
|
|
|
if (m_cacheCleanupTimer.elapsed().total_seconds() > SERVER_CACHE_CLEANUP_INTERVAL_SEC
|
|
|
|
|
&& !m_sessionManager.HasSessions() && !m_gameSessionManager.HasSessions())
|
|
|
|
|
{
|
|
|
|
|
m_avatarManager.RemoveOldAvatarCacheEntries();
|
|
|
|
|
m_cacheCleanupTimer.reset();
|
|
|
|
|
m_cacheCleanupTimer.start();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-21 19:50:13 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::InternalAddGame(boost::shared_ptr<ServerGameThread> game)
|
|
|
|
|
{
|
|
|
|
|
// Add game to list.
|
|
|
|
|
m_gameMap.insert(GameMap::value_type(game->GetId(), game));
|
|
|
|
|
// Notify all players.
|
2007-10-30 21:02:52 +00:00
|
|
|
m_sessionManager.SendToAllSessionsLowPrio(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Established);
|
|
|
|
|
m_gameSessionManager.SendToAllSessionsLowPrio(GetSender(), CreateNetPacketGameListNew(*game), SessionData::Game);
|
2007-10-20 22:22:11 +00:00
|
|
|
|
2007-10-30 21:25:10 +00:00
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_statMutex);
|
|
|
|
|
++m_totalGamesStarted;
|
|
|
|
|
}
|
2007-10-20 22:22:11 +00:00
|
|
|
BroadcastStatisticsUpdate();
|
2007-08-21 19:50:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ServerLobbyThread::InternalRemoveGame(boost::shared_ptr<ServerGameThread> game)
|
|
|
|
|
{
|
|
|
|
|
// Remove game from list.
|
|
|
|
|
m_gameMap.erase(game->GetId());
|
2007-09-29 14:05:41 +00:00
|
|
|
// Remove all sessions left in the game.
|
|
|
|
|
game->RemoveAllSessions();
|
2007-08-21 19:50:13 +00:00
|
|
|
// Notify all players.
|
2007-09-29 20:20:01 +00:00
|
|
|
boost::shared_ptr<NetPacket> packet = CreateNetPacketGameListUpdate(game->GetId(), GAME_MODE_CLOSED);
|
2007-10-30 21:02:52 +00:00
|
|
|
m_sessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Established);
|
|
|
|
|
m_gameSessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Game);
|
2007-08-21 19:50:13 +00:00
|
|
|
}
|
|
|
|
|
|
2007-08-21 12:34:33 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::TerminateGames()
|
|
|
|
|
{
|
|
|
|
|
GameMap::iterator i = m_gameMap.begin();
|
|
|
|
|
GameMap::iterator end = m_gameMap.end();
|
|
|
|
|
|
|
|
|
|
while (i != end)
|
|
|
|
|
{
|
|
|
|
|
i->second->SignalTermination();
|
|
|
|
|
i->second->Join(GAME_THREAD_TERMINATE_TIMEOUT);
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
m_gameMap.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-15 13:28:28 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::HandleNewConnection(boost::shared_ptr<ConnectData> connData)
|
2007-03-20 02:20:50 +00:00
|
|
|
{
|
2007-10-28 12:53:54 +00:00
|
|
|
// 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> sessionData(new SessionData(connData->ReleaseSocket(), m_curSessionId++));
|
|
|
|
|
m_sessionManager.AddSession(sessionData);
|
|
|
|
|
|
2007-08-15 13:28:28 +00:00
|
|
|
if (m_sessionManager.GetRawSessionCount() <= SERVER_MAX_NUM_SESSIONS)
|
2007-03-20 11:56:30 +00:00
|
|
|
{
|
2007-10-30 21:25:10 +00:00
|
|
|
boost::mutex::scoped_lock lock(m_initTimerSessionMapMutex);
|
2007-10-28 12:53:54 +00:00
|
|
|
m_initTimerSessionMap[sessionData->GetId()] = boost::timers::portable::microsec_timer();
|
2007-03-20 02:20:50 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2007-08-15 13:28:28 +00:00
|
|
|
// Server is full.
|
|
|
|
|
// Gracefully close this session.
|
|
|
|
|
SessionError(SessionWrapper(sessionData, boost::shared_ptr<PlayerData>()), ERR_NET_SERVER_FULL);
|
2007-03-20 02:20:50 +00:00
|
|
|
}
|
2007-03-13 23:27:17 +00:00
|
|
|
}
|
|
|
|
|
|
2007-09-06 19:09:05 +00:00
|
|
|
void
|
2007-09-29 14:05:41 +00:00
|
|
|
ServerLobbyThread::HandleReAddedSession(SessionWrapper session)
|
2007-09-06 19:09:05 +00:00
|
|
|
{
|
2007-09-29 14:05:41 +00:00
|
|
|
// Remove session from game session list.
|
2007-10-28 12:53:54 +00:00
|
|
|
m_gameSessionManager.RemoveSession(session.sessionData->GetId());
|
2007-09-29 14:05:41 +00:00
|
|
|
|
2007-09-06 19:09:05 +00:00
|
|
|
if (m_sessionManager.GetRawSessionCount() <= SERVER_MAX_NUM_SESSIONS)
|
|
|
|
|
{
|
2007-09-29 14:05:41 +00:00
|
|
|
// Set state (back) to established.
|
|
|
|
|
session.sessionData->SetState(SessionData::Established);
|
|
|
|
|
// Add session to lobby list.
|
|
|
|
|
m_sessionManager.AddSession(session);
|
2007-09-06 19:09:05 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Gracefully close this session.
|
|
|
|
|
SessionError(session, ERR_NET_SERVER_FULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-20 11:56:30 +00:00
|
|
|
void
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::CleanupConnectQueue()
|
2007-03-20 11:56:30 +00:00
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_connectQueueMutex);
|
|
|
|
|
|
|
|
|
|
// Sockets will be closed automatically.
|
|
|
|
|
m_connectQueue.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::SessionError(SessionWrapper session, int errorCode)
|
2007-05-05 21:40:24 +00:00
|
|
|
{
|
2007-08-02 20:52:13 +00:00
|
|
|
if (session.sessionData.get())
|
|
|
|
|
{
|
2007-10-28 15:06:57 +00:00
|
|
|
SendError(session.sessionData, errorCode);
|
2007-10-28 15:21:24 +00:00
|
|
|
CloseSession(session);
|
2007-08-02 20:52:13 +00:00
|
|
|
}
|
2007-05-08 06:45:46 +00:00
|
|
|
}
|
|
|
|
|
|
2007-05-23 08:57:34 +00:00
|
|
|
void
|
2007-10-28 15:06:57 +00:00
|
|
|
ServerLobbyThread::SendError(boost::shared_ptr<SessionData> s, int errorCode)
|
2007-05-08 06:45:46 +00:00
|
|
|
{
|
|
|
|
|
boost::shared_ptr<NetPacket> packet(new NetPacketError);
|
|
|
|
|
NetPacketError::Data errorData;
|
|
|
|
|
errorData.errorCode = errorCode;
|
|
|
|
|
static_cast<NetPacketError *>(packet.get())->SetData(errorData);
|
|
|
|
|
GetSender().Send(s, packet);
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-06 19:09:05 +00:00
|
|
|
void
|
2007-10-28 15:06:57 +00:00
|
|
|
ServerLobbyThread::SendJoinGameFailed(boost::shared_ptr<SessionData> s, int reason)
|
2007-09-06 19:09:05 +00:00
|
|
|
{
|
|
|
|
|
boost::shared_ptr<NetPacket> packet(new NetPacketJoinGameFailed);
|
|
|
|
|
NetPacketJoinGameFailed::Data failedData;
|
|
|
|
|
failedData.failureCode = reason;
|
|
|
|
|
static_cast<NetPacketJoinGameFailed *>(packet.get())->SetData(failedData);
|
|
|
|
|
GetSender().Send(s, packet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2007-10-28 15:06:57 +00:00
|
|
|
ServerLobbyThread::SendGameList(boost::shared_ptr<SessionData> s)
|
2007-09-06 19:09:05 +00:00
|
|
|
{
|
|
|
|
|
GameMap::const_iterator game_i = m_gameMap.begin();
|
|
|
|
|
GameMap::const_iterator game_end = m_gameMap.end();
|
|
|
|
|
while (game_i != game_end)
|
|
|
|
|
{
|
|
|
|
|
GetSender().Send(s, CreateNetPacketGameListNew(*game_i->second));
|
|
|
|
|
++game_i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-20 22:22:11 +00:00
|
|
|
void
|
|
|
|
|
ServerLobbyThread::BroadcastStatisticsUpdate()
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<NetPacket> packet(new NetPacketStatisticsChanged);
|
|
|
|
|
NetPacketStatisticsChanged::Data statData;
|
|
|
|
|
unsigned curNumberOfPlayersOnServer = m_sessionManager.GetRawSessionCount() + m_gameSessionManager.GetRawSessionCount();
|
2007-10-30 21:25:10 +00:00
|
|
|
{
|
|
|
|
|
boost::mutex::scoped_lock lock(m_statMutex);
|
|
|
|
|
if (curNumberOfPlayersOnServer != m_lastStatData.numberOfPlayersOnServer)
|
|
|
|
|
m_lastStatData.numberOfPlayersOnServer = statData.stats.numberOfPlayersOnServer = curNumberOfPlayersOnServer;
|
|
|
|
|
if (m_totalPlayersLoggedIn != m_lastStatData.totalPlayersEverLoggedIn)
|
|
|
|
|
m_lastStatData.totalPlayersEverLoggedIn = statData.stats.totalPlayersEverLoggedIn = m_totalPlayersLoggedIn;
|
|
|
|
|
if (m_totalGamesStarted != m_lastStatData.totalGamesEverStarted)
|
|
|
|
|
m_lastStatData.totalGamesEverStarted = statData.stats.totalGamesEverStarted = m_totalGamesStarted;
|
|
|
|
|
}
|
2007-10-20 22:22:11 +00:00
|
|
|
|
2007-10-21 00:17:04 +00:00
|
|
|
if (curNumberOfPlayersOnServer)
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
static_cast<NetPacketStatisticsChanged *>(packet.get())->SetData(statData);
|
2007-10-20 22:22:11 +00:00
|
|
|
|
2007-10-30 21:02:52 +00:00
|
|
|
m_sessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Established);
|
|
|
|
|
m_gameSessionManager.SendToAllSessionsLowPrio(GetSender(), packet, SessionData::Game);
|
2007-10-25 21:20:35 +00:00
|
|
|
} catch (const NetException &)
|
2007-10-21 00:17:04 +00:00
|
|
|
{
|
2007-10-24 23:17:12 +00:00
|
|
|
// Ignore errors for now.
|
|
|
|
|
//LOG_ERROR("ServerLobbyThread::BroadcastStatisticsUpdate: " << e.what());
|
2007-10-21 00:17:04 +00:00
|
|
|
}
|
|
|
|
|
}
|
2007-10-20 22:22:11 +00:00
|
|
|
}
|
|
|
|
|
|
2007-05-08 06:45:46 +00:00
|
|
|
ServerCallback &
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::GetCallback()
|
2007-05-08 06:45:46 +00:00
|
|
|
{
|
2007-05-13 22:25:59 +00:00
|
|
|
return m_gui;
|
2007-05-08 06:45:46 +00:00
|
|
|
}
|
|
|
|
|
|
2007-03-13 23:27:17 +00:00
|
|
|
SenderThread &
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::GetSender()
|
2007-03-13 23:27:17 +00:00
|
|
|
{
|
|
|
|
|
assert(m_sender.get());
|
|
|
|
|
return *m_sender;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReceiverHelper &
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::GetReceiver()
|
2007-03-13 23:27:17 +00:00
|
|
|
{
|
|
|
|
|
assert(m_receiver.get());
|
|
|
|
|
return *m_receiver;
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-26 23:07:08 +00:00
|
|
|
bool
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::CheckPassword(const string &password) const
|
2007-04-26 23:07:08 +00:00
|
|
|
{
|
|
|
|
|
return (password == m_password);
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-13 23:27:17 +00:00
|
|
|
ServerSenderCallback &
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::GetSenderCallback()
|
2007-03-13 23:27:17 +00:00
|
|
|
{
|
|
|
|
|
assert(m_senderCallback.get());
|
|
|
|
|
return *m_senderCallback;
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-13 22:25:59 +00:00
|
|
|
GuiInterface &
|
2007-08-15 13:28:28 +00:00
|
|
|
ServerLobbyThread::GetGui()
|
2007-05-13 22:25:59 +00:00
|
|
|
{
|
|
|
|
|
return m_gui;
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-21 17:27:13 +00:00
|
|
|
bool
|
|
|
|
|
ServerLobbyThread::IsPlayerConnected(const string &name)
|
|
|
|
|
{
|
|
|
|
|
bool retVal = false;
|
|
|
|
|
|
|
|
|
|
retVal = m_sessionManager.IsPlayerConnected(name);
|
|
|
|
|
|
|
|
|
|
if (!retVal)
|
2007-09-29 14:05:41 +00:00
|
|
|
retVal = m_gameSessionManager.IsPlayerConnected(name);
|
|
|
|
|
|
2007-08-21 17:27:13 +00:00
|
|
|
return retVal;
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-21 12:34:33 +00:00
|
|
|
boost::shared_ptr<NetPacket>
|
|
|
|
|
ServerLobbyThread::CreateNetPacketGameListNew(const ServerGameThread &game)
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<NetPacket> packet(new NetPacketGameListNew);
|
|
|
|
|
NetPacketGameListNew::Data packetData;
|
|
|
|
|
packetData.gameId = game.GetId();
|
2007-10-12 14:32:25 +00:00
|
|
|
packetData.gameInfo.adminPlayerId = game.GetAdminPlayerId();
|
2007-09-29 22:50:57 +00:00
|
|
|
packetData.gameInfo.mode = game.IsRunning() ? GAME_MODE_STARTED : GAME_MODE_CREATED;
|
2007-08-27 09:57:51 +00:00
|
|
|
packetData.gameInfo.name = game.GetName();
|
|
|
|
|
packetData.gameInfo.data = game.GetGameData();
|
2007-09-02 20:59:16 +00:00
|
|
|
packetData.gameInfo.players = game.GetPlayerIdList();
|
2007-09-04 12:44:11 +00:00
|
|
|
packetData.gameInfo.isPasswordProtected = game.IsPasswordProtected();
|
2007-08-21 12:34:33 +00:00
|
|
|
static_cast<NetPacketGameListNew *>(packet.get())->SetData(packetData);
|
|
|
|
|
return packet;
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-21 19:50:13 +00:00
|
|
|
boost::shared_ptr<NetPacket>
|
2007-09-29 20:20:01 +00:00
|
|
|
ServerLobbyThread::CreateNetPacketGameListUpdate(unsigned gameId, GameMode mode)
|
2007-08-21 19:50:13 +00:00
|
|
|
{
|
|
|
|
|
boost::shared_ptr<NetPacket> packet(new NetPacketGameListUpdate);
|
|
|
|
|
NetPacketGameListUpdate::Data packetData;
|
2007-09-29 20:20:01 +00:00
|
|
|
packetData.gameId = gameId;
|
2007-08-21 19:50:13 +00:00
|
|
|
packetData.gameMode = mode;
|
|
|
|
|
static_cast<NetPacketGameListUpdate *>(packet.get())->SetData(packetData);
|
|
|
|
|
return packet;
|
|
|
|
|
}
|
|
|
|
|
|