Fixed a very nasty bug concerning the sender thread. SOCKETs were assumed to be kind of unique, but Windows tends to return the socket number of a socket which was just closed as new socket number in accept. This led to very strange behavior when the server was flooded with inits, because the sender thread still had entries for this socket number (which were not removed because they should just fail).

No longer use socket as key in maps, instead, use the session id. Only use the session id in the sender thread, "resolve" it to the socket only in the moment when it is needed. Outstanding requests will be detected to have an invalid session id then.
Also, as side effect, fixed an issue with two callback classes which were named the same and caused unexpected behavior.
This commit is contained in:
lotodore
2007-10-28 12:53:54 +00:00
parent 2fa888062f
commit fa7af40a49
20 changed files with 223 additions and 166 deletions
+1 -8
View File
@@ -20,7 +20,7 @@
#include <net/clientcontext.h>
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)
{
+3 -3
View File
@@ -362,7 +362,7 @@ ClientStateStartSession::Process(ClientThread &client)
boost::shared_ptr<NetPacket> 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<NetPacket> startAck(new NetPacketStartEventAck);
client.GetSender().Send(client.GetContext().GetSocket(), startAck);
client.GetSender().Send(client.GetContext().GetSessionId(), startAck);
client.SetState(ClientStateWaitStart::Instance());
}
+10 -5
View File
@@ -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<NetPacketRetrievePlayerInfo *>(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<NetPacketRetrieveAvatar *>(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<AvatarData>();
+65 -52
View File
@@ -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<NetPacket> packet)
SenderThread::Send(SessionId session, boost::shared_ptr<NetPacket> 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<NetPacket> packet)
SenderThread::SendLowPrio(SessionId session, boost::shared_ptr<NetPacket> 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<NetPacket> packet)
SenderThread::InternalStore(SendDataDeque &sendQueue, unsigned maxQueueSize, SessionId session, boost::shared_ptr<NetPacket> 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;
}
}
}
}
-7
View File
@@ -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)
{
+4 -4
View File
@@ -271,7 +271,7 @@ ServerGameStateInit::HandleNewSession(ServerGameThread &server, SessionWrapper s
joinGameAckData.prights = session.playerData->GetRights();
joinGameAckData.gameData = server.GetGameData();
static_cast<NetPacketJoinGameAck *>(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<NetPacketHandStart *>(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<NetPacketPlayersActionRejected *>(reject.get())->SetData(rejectData);
server.GetSender().Send(session.sessionData->GetSocket(), reject);
server.GetSender().Send(session.sessionData->GetId(), reject);
}
}
+11 -7
View File
@@ -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<PlayerData> 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());
+54 -41
View File
@@ -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<NetPacketRemovedFromGame *>(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<NetPacketPlayerInfo *>(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<NetPacketUnknownPlayerId *>(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<NetPacketUnknownAvatar *>(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<NetPacketInitAck *>(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<NetPacketRetrieveAvatar *>(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<ConnectData> 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> 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> 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> sessionData(new SessionData(connData->ReleaseSocket(), 0));
// Gracefully close this session.
SessionError(SessionWrapper(sessionData, boost::shared_ptr<PlayerData>()), 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<NetPacket> 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<NetPacket> 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();
+2 -2
View File
@@ -19,7 +19,7 @@
#include <net/sessiondata.h>
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.
+23 -8
View File
@@ -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> playerData)
SessionManager::SetSessionPlayerData(SessionId session, boost::shared_ptr<PlayerData> 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_ptr<PlayerDat
}
void
SessionManager::RemoveSession(SOCKET session)
SessionManager::RemoveSession(SessionId session)
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);
m_sessionMap.erase(session);
@@ -96,7 +96,7 @@ SessionManager::Select(unsigned timeoutMsec)
while (i != end)
{
// Collect all sockets.
SOCKET tmpSock = i->first;
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<NetPac
}
void
SessionManager::SendToAllButOneSessions(SenderThread &sender, boost::shared_ptr<NetPacket> packet, SOCKET except, SessionData::State state)
SessionManager::SendToAllButOneSessions(SenderThread &sender, boost::shared_ptr<NetPacket> packet, SessionId except, SessionData::State state)
{
boost::mutex::scoped_lock lock(m_sessionMapMutex);