Server now requests unknown avatar files from client and stores them in the cache dir. Error handling is still missing. Clients not yet request avatar files from the server, this is the next step.
AvatarManager is now thread safe. Default and cached avatars are handled in different lists to prevent deleting the default avatars when clearing the cache.
This commit is contained in:
@@ -1359,7 +1359,7 @@ NetPacketAvatarHeader::GetData(NetPacketAvatarHeader::Data &outData) const
|
||||
|
||||
outData.requestId = ntohl(tmpData->requestId);
|
||||
outData.avatarFileSize = ntohl(tmpData->avatarFileSize);
|
||||
outData.avatarFileType = static_cast<AvatarFileType>(ntohl(tmpData->avatarFileType));
|
||||
outData.avatarFileType = static_cast<AvatarFileType>(ntohs(tmpData->avatarFileType));
|
||||
}
|
||||
|
||||
const NetPacketAvatarHeader *
|
||||
@@ -1402,7 +1402,6 @@ NetPacketAvatarFile::Clone() const
|
||||
void
|
||||
NetPacketAvatarFile::SetData(const NetPacketAvatarFile::Data &inData)
|
||||
{
|
||||
NetPacketAvatarFileData *tmpData = (NetPacketAvatarFileData *)GetRawData();
|
||||
int fileDataSize = static_cast<int>(inData.fileData.size());
|
||||
|
||||
if (fileDataSize > MAX_FILE_DATA_SIZE)
|
||||
@@ -1412,6 +1411,8 @@ NetPacketAvatarFile::SetData(const NetPacketAvatarFile::Data &inData)
|
||||
(sizeof(NetPacketAvatarFileData)
|
||||
+ fileDataSize));
|
||||
|
||||
NetPacketAvatarFileData *tmpData = (NetPacketAvatarFileData *)GetRawData();
|
||||
|
||||
tmpData->requestId = htonl(inData.requestId);
|
||||
|
||||
char *avatarDataPtr = (char *)tmpData + sizeof(NetPacketAvatarFileData);
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
ServerAcceptThread::ServerAcceptThread(GuiInterface &gui, ConfigFile *config)
|
||||
ServerAcceptThread::ServerAcceptThread(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager)
|
||||
: m_gui(gui)
|
||||
{
|
||||
m_context.reset(new ServerContext);
|
||||
m_lobbyThread.reset(new ServerLobbyThread(gui, config));
|
||||
m_lobbyThread.reset(new ServerLobbyThread(gui, config, avatarManager));
|
||||
}
|
||||
|
||||
ServerAcceptThread::~ServerAcceptThread()
|
||||
|
||||
@@ -24,11 +24,12 @@
|
||||
#include <net/sendercallback.h>
|
||||
#include <net/receiverhelper.h>
|
||||
#include <net/socket_msg.h>
|
||||
#include <core/avatarmanager.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
|
||||
#define SERVER_CLOSE_SESSION_DELAY_SEC 10
|
||||
#define SERVER_CLOSE_SESSION_DELAY_SEC 1
|
||||
#define SERVER_MAX_NUM_SESSIONS 512 // Maximum number of idle users in lobby.
|
||||
|
||||
#define SERVER_COMPUTER_PLAYER_NAME "Computer"
|
||||
@@ -54,8 +55,9 @@ private:
|
||||
};
|
||||
|
||||
|
||||
ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig)
|
||||
: m_gui(gui), m_playerConfig(playerConfig), m_curGameId(0), m_curUniquePlayerId(0)
|
||||
ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig, AvatarManager &avatarManager)
|
||||
: m_gui(gui), m_avatarManager(avatarManager), m_playerConfig(playerConfig),
|
||||
m_curGameId(0), m_curUniquePlayerId(0), m_curRequestId(0)
|
||||
{
|
||||
m_senderCallback.reset(new ServerSenderCallback(*this));
|
||||
m_sender.reset(new SenderThread(GetSenderCallback()));
|
||||
@@ -174,6 +176,12 @@ ServerLobbyThread::RemoveGame(unsigned id)
|
||||
m_removeGameList.push_back(id);
|
||||
}
|
||||
|
||||
AvatarManager &
|
||||
ServerLobbyThread::GetAvatarManager()
|
||||
{
|
||||
return m_avatarManager;
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
ServerLobbyThread::GetNextUniquePlayerId()
|
||||
{
|
||||
@@ -265,17 +273,24 @@ ServerLobbyThread::ProcessLoop()
|
||||
}
|
||||
if (packet.get())
|
||||
{
|
||||
if (packet->ToNetPacketInit())
|
||||
if (session.sessionData->GetState() == SessionData::Init)
|
||||
{
|
||||
// Session should be in initial state.
|
||||
if (session.sessionData->GetState() != SessionData::Init)
|
||||
SessionError(session, ERR_SOCK_INVALID_STATE);
|
||||
else
|
||||
if (packet->ToNetPacketInit())
|
||||
HandleNetPacketInit(session, *packet->ToNetPacketInit());
|
||||
else if (packet->ToNetPacketAvatarHeader())
|
||||
HandleNetPacketAvatarHeader(session, *packet->ToNetPacketAvatarHeader());
|
||||
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);
|
||||
}
|
||||
// Session should be established.
|
||||
else if (session.sessionData->GetState() != SessionData::Established)
|
||||
SessionError(session, ERR_SOCK_INVALID_STATE);
|
||||
else
|
||||
{
|
||||
if (packet->ToNetPacketRetrievePlayerInfo())
|
||||
@@ -284,6 +299,8 @@ ServerLobbyThread::ProcessLoop()
|
||||
HandleNetPacketCreateGame(session, *packet->ToNetPacketCreateGame());
|
||||
else if (packet->ToNetPacketJoinGame())
|
||||
HandleNetPacketJoinGame(session, *packet->ToNetPacketJoinGame());
|
||||
else
|
||||
SessionError(session, ERR_SOCK_INVALID_STATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -333,24 +350,80 @@ ServerLobbyThread::HandleNetPacketInit(SessionWrapper session, const NetPacketIn
|
||||
tmpPlayerData->SetName(initData.playerName);
|
||||
tmpPlayerData->SetNetSessionData(session.sessionData);
|
||||
if (initData.showAvatar)
|
||||
tmpPlayerData->SetAvatarFile(initData.avatar.ToString());
|
||||
|
||||
// Send ACK to client.
|
||||
boost::shared_ptr<NetPacket> initAck(new NetPacketInitAck);
|
||||
NetPacketInitAck::Data initAckData;
|
||||
initAckData.sessionId = session.sessionData->GetId(); // TODO: currently unused.
|
||||
initAckData.playerId = tmpPlayerData->GetUniqueId();
|
||||
static_cast<NetPacketInitAck *>(initAck.get())->SetData(initAckData);
|
||||
GetSender().Send(session.sessionData->GetSocket(), initAck);
|
||||
|
||||
// Send the game list to the client.
|
||||
SendGameList(session.sessionData->GetSocket());
|
||||
tmpPlayerData->SetAvatarMD5(initData.avatar);
|
||||
|
||||
// Set player data for session.
|
||||
m_sessionManager.SetSessionPlayerData(session.sessionData->GetSocket(), tmpPlayerData);
|
||||
session.playerData = tmpPlayerData;
|
||||
|
||||
// Session is now established.
|
||||
session.sessionData->SetState(SessionData::Established);
|
||||
if (!GetAvatarManager().HasAvatar(initData.avatar))
|
||||
RequestPlayerAvatar(session);
|
||||
else
|
||||
EstablishSession(session);
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::HandleNetPacketAvatarHeader(SessionWrapper session, const NetPacketAvatarHeader &tmpPacket)
|
||||
{
|
||||
if (session.playerData.get())
|
||||
{
|
||||
NetPacketAvatarHeader::Data headerData;
|
||||
tmpPacket.GetData(headerData);
|
||||
|
||||
if (headerData.avatarFileSize && headerData.avatarFileSize <= MAX_AVATAR_FILE_SIZE)
|
||||
{
|
||||
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);
|
||||
}
|
||||
// TODO error handling
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
ServerLobbyThread::HandleNetPacketAvatarEnd(SessionWrapper session, const NetPacketAvatarEnd &tmpPacket)
|
||||
{
|
||||
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)
|
||||
{
|
||||
GetAvatarManager().StoreAvatarInCache(avatarMD5, tmpAvatar->fileType, &tmpAvatar->fileData[0], avatarSize);
|
||||
// Free memory.
|
||||
session.playerData->SetNetAvatarData(boost::shared_ptr<AvatarData>());
|
||||
// Init finished - start session.
|
||||
EstablishSession(session);
|
||||
}
|
||||
// TODO error handling
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -372,9 +445,9 @@ ServerLobbyThread::HandleNetPacketRetrievePlayerInfo(SessionWrapper session, con
|
||||
infoData.playerId = tmpPlayer->GetUniqueId();
|
||||
infoData.playerInfo.ptype = tmpPlayer->GetType();
|
||||
infoData.playerInfo.playerName = tmpPlayer->GetName();
|
||||
infoData.playerInfo.hasAvatar = !tmpPlayer->GetAvatarFile().empty();
|
||||
infoData.playerInfo.hasAvatar = !tmpPlayer->GetAvatarMD5().IsZero();
|
||||
if (infoData.playerInfo.hasAvatar)
|
||||
infoData.playerInfo.avatar.FromString(tmpPlayer->GetAvatarFile());
|
||||
infoData.playerInfo.avatar = tmpPlayer->GetAvatarMD5();
|
||||
static_cast<NetPacketPlayerInfo *>(info.get())->SetData(infoData);
|
||||
GetSender().Send(session.sessionData->GetSocket(), info);
|
||||
}
|
||||
@@ -433,6 +506,38 @@ ServerLobbyThread::HandleNetPacketJoinGame(SessionWrapper session, const NetPack
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::EstablishSession(SessionWrapper session)
|
||||
{
|
||||
assert(session.playerData.get());
|
||||
// Send ACK to client.
|
||||
boost::shared_ptr<NetPacket> initAck(new NetPacketInitAck);
|
||||
NetPacketInitAck::Data initAckData;
|
||||
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);
|
||||
|
||||
// Send the game list to the client.
|
||||
SendGameList(session.sessionData->GetSocket());
|
||||
|
||||
// Session is now established.
|
||||
session.sessionData->SetState(SessionData::Established);
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::RequestPlayerAvatar(SessionWrapper session)
|
||||
{
|
||||
assert(session.playerData.get());
|
||||
// Ask the client to send its avatar.
|
||||
boost::shared_ptr<NetPacket> retrieveAvatar(new NetPacketRetrieveAvatar);
|
||||
NetPacketRetrieveAvatar::Data retrieveAvatarData;
|
||||
retrieveAvatarData.requestId = m_curRequestId++;
|
||||
retrieveAvatarData.avatar = session.playerData->GetAvatarMD5();
|
||||
static_cast<NetPacketRetrieveAvatar *>(retrieveAvatar.get())->SetData(retrieveAvatarData);
|
||||
GetSender().Send(session.sessionData->GetSocket(), retrieveAvatar);
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::CloseSessionLoop()
|
||||
{
|
||||
|
||||
@@ -32,12 +32,13 @@ class ServerLobbyThread;
|
||||
class ServerSenderCallback;
|
||||
class SenderThread;
|
||||
class ConfigFile;
|
||||
class AvatarManager;
|
||||
struct GameData;
|
||||
|
||||
class ServerAcceptThread : public Thread
|
||||
{
|
||||
public:
|
||||
ServerAcceptThread(GuiInterface &gui, ConfigFile *config);
|
||||
ServerAcceptThread(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager);
|
||||
virtual ~ServerAcceptThread();
|
||||
|
||||
// Set the parameters.
|
||||
|
||||
@@ -39,13 +39,14 @@ class ReceiverHelper;
|
||||
class ServerSenderCallback;
|
||||
class ServerGameThread;
|
||||
class ConfigFile;
|
||||
class AvatarManager;
|
||||
struct GameData;
|
||||
class Game;
|
||||
|
||||
class ServerLobbyThread : public Thread
|
||||
{
|
||||
public:
|
||||
ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig);
|
||||
ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig, AvatarManager &avatarManager);
|
||||
virtual ~ServerLobbyThread();
|
||||
|
||||
void Init(const std::string &pwd);
|
||||
@@ -67,6 +68,8 @@ public:
|
||||
u_int32_t GetNextGameId();
|
||||
ServerCallback &GetCallback();
|
||||
|
||||
AvatarManager &GetAvatarManager();
|
||||
|
||||
protected:
|
||||
|
||||
typedef std::deque<boost::shared_ptr<ConnectData> > ConnectQueue;
|
||||
@@ -81,9 +84,14 @@ protected:
|
||||
|
||||
void ProcessLoop();
|
||||
void HandleNetPacketInit(SessionWrapper session, const NetPacketInit &tmpPacket);
|
||||
void HandleNetPacketAvatarHeader(SessionWrapper session, const NetPacketAvatarHeader &tmpPacket);
|
||||
void HandleNetPacketAvatarFile(SessionWrapper session, const NetPacketAvatarFile &tmpPacket);
|
||||
void HandleNetPacketAvatarEnd(SessionWrapper session, const NetPacketAvatarEnd &tmpPacket);
|
||||
void HandleNetPacketRetrievePlayerInfo(SessionWrapper session, const NetPacketRetrievePlayerInfo &tmpPacket);
|
||||
void HandleNetPacketCreateGame(SessionWrapper session, const NetPacketCreateGame &tmpPacket);
|
||||
void HandleNetPacketJoinGame(SessionWrapper session, const NetPacketJoinGame &tmpPacket);
|
||||
void EstablishSession(SessionWrapper session);
|
||||
void RequestPlayerAvatar(SessionWrapper session);
|
||||
void CloseSessionLoop();
|
||||
void RemoveGameLoop();
|
||||
|
||||
@@ -141,6 +149,7 @@ private:
|
||||
std::auto_ptr<SenderThread> m_sender;
|
||||
std::auto_ptr<ServerSenderCallback> m_senderCallback;
|
||||
GuiInterface &m_gui;
|
||||
AvatarManager &m_avatarManager;
|
||||
|
||||
std::string m_password;
|
||||
ConfigFile *m_playerConfig;
|
||||
@@ -148,6 +157,8 @@ private:
|
||||
|
||||
u_int32_t m_curUniquePlayerId;
|
||||
mutable boost::mutex m_curUniquePlayerIdMutex;
|
||||
|
||||
u_int32_t m_curRequestId;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
class SessionData
|
||||
{
|
||||
public:
|
||||
enum State { Init, Established, Game };
|
||||
enum State { Init, ReceivingAvatar, Established, Game };
|
||||
|
||||
SessionData(SOCKET sockfd, unsigned id);
|
||||
~SessionData();
|
||||
|
||||
Reference in New Issue
Block a user