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:
@@ -26,6 +26,7 @@
|
|||||||
#include <core/crypthelper.h>
|
#include <core/crypthelper.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include <boost/thread.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#define MAX_AVATAR_FILE_SIZE 30720
|
#define MAX_AVATAR_FILE_SIZE 30720
|
||||||
@@ -46,18 +47,24 @@ public:
|
|||||||
|
|
||||||
bool AvatarFileToNetPackets(const std::string &fileName, unsigned requestId, NetPacketList &packets);
|
bool AvatarFileToNetPackets(const std::string &fileName, unsigned requestId, NetPacketList &packets);
|
||||||
|
|
||||||
bool GetHashForAvatar(const std::string &fileName, MD5Buf &md5buf);
|
bool GetHashForAvatar(const std::string &fileName, MD5Buf &md5buf) const;
|
||||||
bool GetAvatarFileName(const MD5Buf &md5buf, std::string &fileName) const;
|
bool GetAvatarFileName(const MD5Buf &md5buf, std::string &fileName) const;
|
||||||
|
bool HasAvatar(const MD5Buf &md5buf) const;
|
||||||
bool StoreAvatarInCache(const MD5Buf &md5buf, AvatarFileType avatarFileType, const unsigned char *data, unsigned size);
|
bool StoreAvatarInCache(const MD5Buf &md5buf, AvatarFileType avatarFileType, const unsigned char *data, unsigned size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef std::map<MD5Buf, std::string> AvatarMap;
|
typedef std::map<MD5Buf, std::string> AvatarMap;
|
||||||
|
|
||||||
void InternalReadDirectory(const std::string &dir);
|
bool InternalReadDirectory(const std::string &dir, AvatarMap &avatars);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
mutable boost::mutex m_avatarsMutex;
|
||||||
AvatarMap m_avatars;
|
AvatarMap m_avatars;
|
||||||
|
|
||||||
|
mutable boost::mutex m_cachedAvatarsMutex;
|
||||||
|
AvatarMap m_cachedAvatars;
|
||||||
|
|
||||||
|
mutable boost::mutex m_cacheDirMutex;
|
||||||
std::string m_cacheDir;
|
std::string m_cacheDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "avatarmanager.h"
|
#include "avatarmanager.h"
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/lambda/lambda.hpp>
|
||||||
#include <openssl/md5.h>
|
#include <openssl/md5.h>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -51,18 +52,20 @@ AvatarManager::~AvatarManager()
|
|||||||
bool
|
bool
|
||||||
AvatarManager::Init(const std::string &dataDir, const std::string &cacheDir)
|
AvatarManager::Init(const std::string &dataDir, const std::string &cacheDir)
|
||||||
{
|
{
|
||||||
bool retVal = false;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
InternalReadDirectory(dataDir + "gfx/avatars/default/people/");
|
boost::mutex::scoped_lock lock(m_cacheDirMutex);
|
||||||
InternalReadDirectory(dataDir + "gfx/avatars/default/misc/");
|
|
||||||
InternalReadDirectory(cacheDir);
|
|
||||||
m_cacheDir = cacheDir;
|
m_cacheDir = cacheDir;
|
||||||
retVal = true;
|
|
||||||
} catch (...)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
return retVal;
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_avatarsMutex);
|
||||||
|
InternalReadDirectory(dataDir + "gfx/avatars/default/people/", m_avatars);
|
||||||
|
InternalReadDirectory(dataDir + "gfx/avatars/default/misc/", m_avatars);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_cachedAvatarsMutex);
|
||||||
|
InternalReadDirectory(cacheDir, m_cachedAvatars);
|
||||||
|
}
|
||||||
|
return true; // TODO handle errors
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<AvatarFileState>
|
boost::shared_ptr<AvatarFileState>
|
||||||
@@ -170,12 +173,14 @@ AvatarManager::AvatarFileToNetPackets(const string &fileName, unsigned requestId
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AvatarManager::GetHashForAvatar(const std::string &fileName, MD5Buf &md5buf)
|
AvatarManager::GetHashForAvatar(const std::string &fileName, MD5Buf &md5buf) const
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
if (exists(fileName))
|
if (exists(fileName))
|
||||||
{
|
{
|
||||||
|
// Scan default avatars first.
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_avatarsMutex);
|
||||||
AvatarMap::const_iterator i = m_avatars.begin();
|
AvatarMap::const_iterator i = m_avatars.begin();
|
||||||
AvatarMap::const_iterator end = m_avatars.end();
|
AvatarMap::const_iterator end = m_avatars.end();
|
||||||
while (i != end)
|
while (i != end)
|
||||||
@@ -188,15 +193,32 @@ AvatarManager::GetHashForAvatar(const std::string &fileName, MD5Buf &md5buf)
|
|||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Check cached avatars next.
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_cachedAvatarsMutex);
|
||||||
|
AvatarMap::const_iterator i = m_cachedAvatars.begin();
|
||||||
|
AvatarMap::const_iterator end = m_cachedAvatars.end();
|
||||||
|
while (i != end)
|
||||||
|
{
|
||||||
|
if (i->second == fileName)
|
||||||
|
{
|
||||||
|
md5buf = i->first;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate md5 sum if not found.
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
if (CryptHelper::MD5Sum(fileName, md5buf))
|
if (CryptHelper::MD5Sum(fileName, md5buf))
|
||||||
{
|
|
||||||
m_avatars.insert(AvatarMap::value_type(md5buf, fileName));
|
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,15 +226,35 @@ bool
|
|||||||
AvatarManager::GetAvatarFileName(const MD5Buf &md5buf, std::string &fileName) const
|
AvatarManager::GetAvatarFileName(const MD5Buf &md5buf, std::string &fileName) const
|
||||||
{
|
{
|
||||||
bool retVal = false;
|
bool retVal = false;
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_avatarsMutex);
|
||||||
AvatarMap::const_iterator pos = m_avatars.find(md5buf);
|
AvatarMap::const_iterator pos = m_avatars.find(md5buf);
|
||||||
if (pos != m_avatars.end())
|
if (pos != m_avatars.end())
|
||||||
{
|
{
|
||||||
fileName = pos->second;
|
fileName = pos->second;
|
||||||
retVal = true;
|
retVal = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!retVal)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_cachedAvatarsMutex);
|
||||||
|
AvatarMap::const_iterator pos = m_cachedAvatars.find(md5buf);
|
||||||
|
if (pos != m_cachedAvatars.end())
|
||||||
|
{
|
||||||
|
fileName = pos->second;
|
||||||
|
retVal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
AvatarManager::HasAvatar(const MD5Buf &md5buf) const
|
||||||
|
{
|
||||||
|
string tmpFile;
|
||||||
|
return GetAvatarFileName(md5buf, tmpFile);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AvatarManager::StoreAvatarInCache(const MD5Buf &md5buf, AvatarFileType avatarFileType, const unsigned char *data, unsigned size)
|
AvatarManager::StoreAvatarInCache(const MD5Buf &md5buf, AvatarFileType avatarFileType, const unsigned char *data, unsigned size)
|
||||||
{
|
{
|
||||||
@@ -237,7 +279,10 @@ AvatarManager::StoreAvatarInCache(const MD5Buf &md5buf, AvatarFileType avatarFil
|
|||||||
string fileName(tmpPath.file_string());
|
string fileName(tmpPath.file_string());
|
||||||
ofstream o(fileName.c_str(), ios_base::out | ios_base::binary);
|
ofstream o(fileName.c_str(), ios_base::out | ios_base::binary);
|
||||||
o.write((const char *)data, size);
|
o.write((const char *)data, size);
|
||||||
m_avatars.insert(AvatarMap::value_type(md5buf, fileName));
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_cachedAvatarsMutex);
|
||||||
|
m_cachedAvatars.insert(AvatarMap::value_type(md5buf, fileName));
|
||||||
|
}
|
||||||
retVal = true;
|
retVal = true;
|
||||||
} catch (...)
|
} catch (...)
|
||||||
{
|
{
|
||||||
@@ -245,9 +290,13 @@ AvatarManager::StoreAvatarInCache(const MD5Buf &md5buf, AvatarFileType avatarFil
|
|||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
AvatarManager::InternalReadDirectory(const std::string &dir)
|
AvatarManager::InternalReadDirectory(const std::string &dir, AvatarMap &avatars)
|
||||||
{
|
{
|
||||||
|
bool retVal = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// This method is not thread safe. Only call after locking the map.
|
||||||
directory_iterator i(dir);
|
directory_iterator i(dir);
|
||||||
directory_iterator end;
|
directory_iterator end;
|
||||||
|
|
||||||
@@ -266,9 +315,14 @@ AvatarManager::InternalReadDirectory(const std::string &dir)
|
|||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
if (success)
|
if (success)
|
||||||
m_avatars.insert(AvatarMap::value_type(md5buf, fileName));
|
avatars.insert(AvatarMap::value_type(md5buf, fileName));
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
} catch (...)
|
||||||
|
{
|
||||||
|
retVal = false;
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,12 @@ MD5Buf::FromString(const std::string &text)
|
|||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MD5Buf::IsZero() const
|
||||||
|
{
|
||||||
|
return *this == MD5Buf();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MD5Buf::operator==(const MD5Buf &other) const
|
MD5Buf::operator==(const MD5Buf &other) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ struct MD5Buf
|
|||||||
|
|
||||||
std::string ToString() const;
|
std::string ToString() const;
|
||||||
bool FromString(const std::string &text);
|
bool FromString(const std::string &text);
|
||||||
|
bool IsZero() const;
|
||||||
|
|
||||||
bool operator==(const MD5Buf &other) const;
|
bool operator==(const MD5Buf &other) const;
|
||||||
bool operator<(const MD5Buf &other) const;
|
bool operator<(const MD5Buf &other) const;
|
||||||
|
|||||||
@@ -1359,7 +1359,7 @@ NetPacketAvatarHeader::GetData(NetPacketAvatarHeader::Data &outData) const
|
|||||||
|
|
||||||
outData.requestId = ntohl(tmpData->requestId);
|
outData.requestId = ntohl(tmpData->requestId);
|
||||||
outData.avatarFileSize = ntohl(tmpData->avatarFileSize);
|
outData.avatarFileSize = ntohl(tmpData->avatarFileSize);
|
||||||
outData.avatarFileType = static_cast<AvatarFileType>(ntohl(tmpData->avatarFileType));
|
outData.avatarFileType = static_cast<AvatarFileType>(ntohs(tmpData->avatarFileType));
|
||||||
}
|
}
|
||||||
|
|
||||||
const NetPacketAvatarHeader *
|
const NetPacketAvatarHeader *
|
||||||
@@ -1402,7 +1402,6 @@ NetPacketAvatarFile::Clone() const
|
|||||||
void
|
void
|
||||||
NetPacketAvatarFile::SetData(const NetPacketAvatarFile::Data &inData)
|
NetPacketAvatarFile::SetData(const NetPacketAvatarFile::Data &inData)
|
||||||
{
|
{
|
||||||
NetPacketAvatarFileData *tmpData = (NetPacketAvatarFileData *)GetRawData();
|
|
||||||
int fileDataSize = static_cast<int>(inData.fileData.size());
|
int fileDataSize = static_cast<int>(inData.fileData.size());
|
||||||
|
|
||||||
if (fileDataSize > MAX_FILE_DATA_SIZE)
|
if (fileDataSize > MAX_FILE_DATA_SIZE)
|
||||||
@@ -1412,6 +1411,8 @@ NetPacketAvatarFile::SetData(const NetPacketAvatarFile::Data &inData)
|
|||||||
(sizeof(NetPacketAvatarFileData)
|
(sizeof(NetPacketAvatarFileData)
|
||||||
+ fileDataSize));
|
+ fileDataSize));
|
||||||
|
|
||||||
|
NetPacketAvatarFileData *tmpData = (NetPacketAvatarFileData *)GetRawData();
|
||||||
|
|
||||||
tmpData->requestId = htonl(inData.requestId);
|
tmpData->requestId = htonl(inData.requestId);
|
||||||
|
|
||||||
char *avatarDataPtr = (char *)tmpData + sizeof(NetPacketAvatarFileData);
|
char *avatarDataPtr = (char *)tmpData + sizeof(NetPacketAvatarFileData);
|
||||||
|
|||||||
@@ -30,11 +30,11 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
ServerAcceptThread::ServerAcceptThread(GuiInterface &gui, ConfigFile *config)
|
ServerAcceptThread::ServerAcceptThread(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager)
|
||||||
: m_gui(gui)
|
: m_gui(gui)
|
||||||
{
|
{
|
||||||
m_context.reset(new ServerContext);
|
m_context.reset(new ServerContext);
|
||||||
m_lobbyThread.reset(new ServerLobbyThread(gui, config));
|
m_lobbyThread.reset(new ServerLobbyThread(gui, config, avatarManager));
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerAcceptThread::~ServerAcceptThread()
|
ServerAcceptThread::~ServerAcceptThread()
|
||||||
|
|||||||
@@ -24,11 +24,12 @@
|
|||||||
#include <net/sendercallback.h>
|
#include <net/sendercallback.h>
|
||||||
#include <net/receiverhelper.h>
|
#include <net/receiverhelper.h>
|
||||||
#include <net/socket_msg.h>
|
#include <net/socket_msg.h>
|
||||||
|
#include <core/avatarmanager.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
#include <boost/lambda/lambda.hpp>
|
#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_MAX_NUM_SESSIONS 512 // Maximum number of idle users in lobby.
|
||||||
|
|
||||||
#define SERVER_COMPUTER_PLAYER_NAME "Computer"
|
#define SERVER_COMPUTER_PLAYER_NAME "Computer"
|
||||||
@@ -54,8 +55,9 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig)
|
ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig, AvatarManager &avatarManager)
|
||||||
: m_gui(gui), m_playerConfig(playerConfig), m_curGameId(0), m_curUniquePlayerId(0)
|
: 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_senderCallback.reset(new ServerSenderCallback(*this));
|
||||||
m_sender.reset(new SenderThread(GetSenderCallback()));
|
m_sender.reset(new SenderThread(GetSenderCallback()));
|
||||||
@@ -174,6 +176,12 @@ ServerLobbyThread::RemoveGame(unsigned id)
|
|||||||
m_removeGameList.push_back(id);
|
m_removeGameList.push_back(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AvatarManager &
|
||||||
|
ServerLobbyThread::GetAvatarManager()
|
||||||
|
{
|
||||||
|
return m_avatarManager;
|
||||||
|
}
|
||||||
|
|
||||||
u_int32_t
|
u_int32_t
|
||||||
ServerLobbyThread::GetNextUniquePlayerId()
|
ServerLobbyThread::GetNextUniquePlayerId()
|
||||||
{
|
{
|
||||||
@@ -265,17 +273,24 @@ ServerLobbyThread::ProcessLoop()
|
|||||||
}
|
}
|
||||||
if (packet.get())
|
if (packet.get())
|
||||||
{
|
{
|
||||||
if (packet->ToNetPacketInit())
|
if (session.sessionData->GetState() == SessionData::Init)
|
||||||
{
|
{
|
||||||
// Session should be in initial state.
|
if (packet->ToNetPacketInit())
|
||||||
if (session.sessionData->GetState() != SessionData::Init)
|
|
||||||
SessionError(session, ERR_SOCK_INVALID_STATE);
|
|
||||||
else
|
|
||||||
HandleNetPacketInit(session, *packet->ToNetPacketInit());
|
HandleNetPacketInit(session, *packet->ToNetPacketInit());
|
||||||
}
|
else if (packet->ToNetPacketAvatarHeader())
|
||||||
// Session should be established.
|
HandleNetPacketAvatarHeader(session, *packet->ToNetPacketAvatarHeader());
|
||||||
else if (session.sessionData->GetState() != SessionData::Established)
|
else
|
||||||
SessionError(session, ERR_SOCK_INVALID_STATE);
|
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);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (packet->ToNetPacketRetrievePlayerInfo())
|
if (packet->ToNetPacketRetrievePlayerInfo())
|
||||||
@@ -284,6 +299,8 @@ ServerLobbyThread::ProcessLoop()
|
|||||||
HandleNetPacketCreateGame(session, *packet->ToNetPacketCreateGame());
|
HandleNetPacketCreateGame(session, *packet->ToNetPacketCreateGame());
|
||||||
else if (packet->ToNetPacketJoinGame())
|
else if (packet->ToNetPacketJoinGame())
|
||||||
HandleNetPacketJoinGame(session, *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->SetName(initData.playerName);
|
||||||
tmpPlayerData->SetNetSessionData(session.sessionData);
|
tmpPlayerData->SetNetSessionData(session.sessionData);
|
||||||
if (initData.showAvatar)
|
if (initData.showAvatar)
|
||||||
tmpPlayerData->SetAvatarFile(initData.avatar.ToString());
|
tmpPlayerData->SetAvatarMD5(initData.avatar);
|
||||||
|
|
||||||
// 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());
|
|
||||||
|
|
||||||
// Set player data for session.
|
// Set player data for session.
|
||||||
m_sessionManager.SetSessionPlayerData(session.sessionData->GetSocket(), tmpPlayerData);
|
m_sessionManager.SetSessionPlayerData(session.sessionData->GetSocket(), tmpPlayerData);
|
||||||
|
session.playerData = tmpPlayerData;
|
||||||
|
|
||||||
// Session is now established.
|
if (!GetAvatarManager().HasAvatar(initData.avatar))
|
||||||
session.sessionData->SetState(SessionData::Established);
|
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
|
void
|
||||||
@@ -372,9 +445,9 @@ ServerLobbyThread::HandleNetPacketRetrievePlayerInfo(SessionWrapper session, con
|
|||||||
infoData.playerId = tmpPlayer->GetUniqueId();
|
infoData.playerId = tmpPlayer->GetUniqueId();
|
||||||
infoData.playerInfo.ptype = tmpPlayer->GetType();
|
infoData.playerInfo.ptype = tmpPlayer->GetType();
|
||||||
infoData.playerInfo.playerName = tmpPlayer->GetName();
|
infoData.playerInfo.playerName = tmpPlayer->GetName();
|
||||||
infoData.playerInfo.hasAvatar = !tmpPlayer->GetAvatarFile().empty();
|
infoData.playerInfo.hasAvatar = !tmpPlayer->GetAvatarMD5().IsZero();
|
||||||
if (infoData.playerInfo.hasAvatar)
|
if (infoData.playerInfo.hasAvatar)
|
||||||
infoData.playerInfo.avatar.FromString(tmpPlayer->GetAvatarFile());
|
infoData.playerInfo.avatar = tmpPlayer->GetAvatarMD5();
|
||||||
static_cast<NetPacketPlayerInfo *>(info.get())->SetData(infoData);
|
static_cast<NetPacketPlayerInfo *>(info.get())->SetData(infoData);
|
||||||
GetSender().Send(session.sessionData->GetSocket(), info);
|
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
|
void
|
||||||
ServerLobbyThread::CloseSessionLoop()
|
ServerLobbyThread::CloseSessionLoop()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,12 +32,13 @@ class ServerLobbyThread;
|
|||||||
class ServerSenderCallback;
|
class ServerSenderCallback;
|
||||||
class SenderThread;
|
class SenderThread;
|
||||||
class ConfigFile;
|
class ConfigFile;
|
||||||
|
class AvatarManager;
|
||||||
struct GameData;
|
struct GameData;
|
||||||
|
|
||||||
class ServerAcceptThread : public Thread
|
class ServerAcceptThread : public Thread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ServerAcceptThread(GuiInterface &gui, ConfigFile *config);
|
ServerAcceptThread(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager);
|
||||||
virtual ~ServerAcceptThread();
|
virtual ~ServerAcceptThread();
|
||||||
|
|
||||||
// Set the parameters.
|
// Set the parameters.
|
||||||
|
|||||||
@@ -39,13 +39,14 @@ class ReceiverHelper;
|
|||||||
class ServerSenderCallback;
|
class ServerSenderCallback;
|
||||||
class ServerGameThread;
|
class ServerGameThread;
|
||||||
class ConfigFile;
|
class ConfigFile;
|
||||||
|
class AvatarManager;
|
||||||
struct GameData;
|
struct GameData;
|
||||||
class Game;
|
class Game;
|
||||||
|
|
||||||
class ServerLobbyThread : public Thread
|
class ServerLobbyThread : public Thread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig);
|
ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig, AvatarManager &avatarManager);
|
||||||
virtual ~ServerLobbyThread();
|
virtual ~ServerLobbyThread();
|
||||||
|
|
||||||
void Init(const std::string &pwd);
|
void Init(const std::string &pwd);
|
||||||
@@ -67,6 +68,8 @@ public:
|
|||||||
u_int32_t GetNextGameId();
|
u_int32_t GetNextGameId();
|
||||||
ServerCallback &GetCallback();
|
ServerCallback &GetCallback();
|
||||||
|
|
||||||
|
AvatarManager &GetAvatarManager();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
typedef std::deque<boost::shared_ptr<ConnectData> > ConnectQueue;
|
typedef std::deque<boost::shared_ptr<ConnectData> > ConnectQueue;
|
||||||
@@ -81,9 +84,14 @@ protected:
|
|||||||
|
|
||||||
void ProcessLoop();
|
void ProcessLoop();
|
||||||
void HandleNetPacketInit(SessionWrapper session, const NetPacketInit &tmpPacket);
|
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 HandleNetPacketRetrievePlayerInfo(SessionWrapper session, const NetPacketRetrievePlayerInfo &tmpPacket);
|
||||||
void HandleNetPacketCreateGame(SessionWrapper session, const NetPacketCreateGame &tmpPacket);
|
void HandleNetPacketCreateGame(SessionWrapper session, const NetPacketCreateGame &tmpPacket);
|
||||||
void HandleNetPacketJoinGame(SessionWrapper session, const NetPacketJoinGame &tmpPacket);
|
void HandleNetPacketJoinGame(SessionWrapper session, const NetPacketJoinGame &tmpPacket);
|
||||||
|
void EstablishSession(SessionWrapper session);
|
||||||
|
void RequestPlayerAvatar(SessionWrapper session);
|
||||||
void CloseSessionLoop();
|
void CloseSessionLoop();
|
||||||
void RemoveGameLoop();
|
void RemoveGameLoop();
|
||||||
|
|
||||||
@@ -141,6 +149,7 @@ private:
|
|||||||
std::auto_ptr<SenderThread> m_sender;
|
std::auto_ptr<SenderThread> m_sender;
|
||||||
std::auto_ptr<ServerSenderCallback> m_senderCallback;
|
std::auto_ptr<ServerSenderCallback> m_senderCallback;
|
||||||
GuiInterface &m_gui;
|
GuiInterface &m_gui;
|
||||||
|
AvatarManager &m_avatarManager;
|
||||||
|
|
||||||
std::string m_password;
|
std::string m_password;
|
||||||
ConfigFile *m_playerConfig;
|
ConfigFile *m_playerConfig;
|
||||||
@@ -148,6 +157,8 @@ private:
|
|||||||
|
|
||||||
u_int32_t m_curUniquePlayerId;
|
u_int32_t m_curUniquePlayerId;
|
||||||
mutable boost::mutex m_curUniquePlayerIdMutex;
|
mutable boost::mutex m_curUniquePlayerIdMutex;
|
||||||
|
|
||||||
|
u_int32_t m_curRequestId;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
class SessionData
|
class SessionData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum State { Init, Established, Game };
|
enum State { Init, ReceivingAvatar, Established, Game };
|
||||||
|
|
||||||
SessionData(SOCKET sockfd, unsigned id);
|
SessionData(SOCKET sockfd, unsigned id);
|
||||||
~SessionData();
|
~SessionData();
|
||||||
|
|||||||
+29
-2
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include <playerdata.h>
|
#include <playerdata.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
PlayerData::PlayerData(unsigned uniqueId, int number, PlayerType type, PlayerRights rights)
|
PlayerData::PlayerData(unsigned uniqueId, int number, PlayerType type, PlayerRights rights)
|
||||||
: m_uniqueId(uniqueId), m_number(number), m_type(type), m_rights(rights)
|
: m_uniqueId(uniqueId), m_number(number), m_type(type), m_rights(rights)
|
||||||
{
|
{
|
||||||
@@ -35,7 +37,7 @@ PlayerData::~PlayerData()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &
|
string
|
||||||
PlayerData::GetName() const
|
PlayerData::GetName() const
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(m_dataMutex);
|
boost::mutex::scoped_lock lock(m_dataMutex);
|
||||||
@@ -49,7 +51,7 @@ PlayerData::SetName(const std::string &name)
|
|||||||
m_name = name;
|
m_name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &
|
string
|
||||||
PlayerData::GetAvatarFile() const
|
PlayerData::GetAvatarFile() const
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock lock(m_dataMutex);
|
boost::mutex::scoped_lock lock(m_dataMutex);
|
||||||
@@ -63,6 +65,19 @@ PlayerData::SetAvatarFile(const std::string &avatarFile)
|
|||||||
m_avatarFile = avatarFile;
|
m_avatarFile = avatarFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MD5Buf
|
||||||
|
PlayerData::GetAvatarMD5() const
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_dataMutex);
|
||||||
|
return m_avatarMD5;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
PlayerData::SetAvatarMD5(const MD5Buf &avatarMD5)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_dataMutex);
|
||||||
|
m_avatarMD5 = avatarMD5;
|
||||||
|
}
|
||||||
|
|
||||||
boost::shared_ptr<SessionData>
|
boost::shared_ptr<SessionData>
|
||||||
PlayerData::GetNetSessionData() const
|
PlayerData::GetNetSessionData() const
|
||||||
{
|
{
|
||||||
@@ -77,6 +92,18 @@ PlayerData::SetNetSessionData(boost::shared_ptr<SessionData> session)
|
|||||||
m_netSessionData = session;
|
m_netSessionData = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<AvatarData>
|
||||||
|
PlayerData::GetNetAvatarData() const
|
||||||
|
{
|
||||||
|
return m_netAvatarData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PlayerData::SetNetAvatarData(boost::shared_ptr<AvatarData> avatarData)
|
||||||
|
{
|
||||||
|
m_netAvatarData = avatarData;
|
||||||
|
}
|
||||||
|
|
||||||
PlayerType
|
PlayerType
|
||||||
PlayerData::GetType() const
|
PlayerData::GetType() const
|
||||||
{
|
{
|
||||||
|
|||||||
+17
-2
@@ -24,6 +24,7 @@
|
|||||||
#include <core/crypthelper.h>
|
#include <core/crypthelper.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
@@ -50,6 +51,14 @@ enum AvatarFileType
|
|||||||
AVATAR_FILE_TYPE_GIF
|
AVATAR_FILE_TYPE_GIF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AvatarData
|
||||||
|
{
|
||||||
|
AvatarData() : fileType(AVATAR_FILE_TYPE_UNKNOWN), reportedSize(0) {}
|
||||||
|
std::vector<unsigned char> fileData;
|
||||||
|
AvatarFileType fileType;
|
||||||
|
unsigned reportedSize;
|
||||||
|
};
|
||||||
|
|
||||||
struct PlayerInfo
|
struct PlayerInfo
|
||||||
{
|
{
|
||||||
PlayerInfo() : ptype(PLAYER_TYPE_HUMAN) {}
|
PlayerInfo() : ptype(PLAYER_TYPE_HUMAN) {}
|
||||||
@@ -66,12 +75,16 @@ public:
|
|||||||
PlayerData(const PlayerData &other);
|
PlayerData(const PlayerData &other);
|
||||||
~PlayerData();
|
~PlayerData();
|
||||||
|
|
||||||
const std::string &GetName() const;
|
std::string GetName() const;
|
||||||
void SetName(const std::string &name);
|
void SetName(const std::string &name);
|
||||||
const std::string &GetAvatarFile() const;
|
std::string GetAvatarFile() const;
|
||||||
void SetAvatarFile(const std::string &avatarFile);
|
void SetAvatarFile(const std::string &avatarFile);
|
||||||
|
MD5Buf GetAvatarMD5() const;
|
||||||
|
void SetAvatarMD5(const MD5Buf &avatarMD5);
|
||||||
boost::shared_ptr<SessionData> GetNetSessionData() const;
|
boost::shared_ptr<SessionData> GetNetSessionData() const;
|
||||||
void SetNetSessionData(boost::shared_ptr<SessionData> session);
|
void SetNetSessionData(boost::shared_ptr<SessionData> session);
|
||||||
|
boost::shared_ptr<AvatarData> GetNetAvatarData() const;
|
||||||
|
void SetNetAvatarData(boost::shared_ptr<AvatarData> avatarData);
|
||||||
PlayerType GetType() const;
|
PlayerType GetType() const;
|
||||||
void SetType(PlayerType type);
|
void SetType(PlayerType type);
|
||||||
PlayerRights GetRights() const;
|
PlayerRights GetRights() const;
|
||||||
@@ -87,9 +100,11 @@ private:
|
|||||||
int m_number;
|
int m_number;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::string m_avatarFile;
|
std::string m_avatarFile;
|
||||||
|
MD5Buf m_avatarMD5;
|
||||||
PlayerType m_type;
|
PlayerType m_type;
|
||||||
PlayerRights m_rights;
|
PlayerRights m_rights;
|
||||||
boost::shared_ptr<SessionData> m_netSessionData;
|
boost::shared_ptr<SessionData> m_netSessionData;
|
||||||
|
boost::shared_ptr<AvatarData> m_netAvatarData;
|
||||||
|
|
||||||
mutable boost::mutex m_dataMutex;
|
mutable boost::mutex m_dataMutex;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -69,6 +69,9 @@ main(int argc, char *argv[])
|
|||||||
|
|
||||||
//_CrtSetBreakAlloc(164);
|
//_CrtSetBreakAlloc(164);
|
||||||
|
|
||||||
|
//create defaultconfig
|
||||||
|
ConfigFile *myConfig = new ConfigFile(argc, argv);
|
||||||
|
|
||||||
// TODO: Hack
|
// TODO: Hack
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
daemon(0, 0);
|
daemon(0, 0);
|
||||||
@@ -77,9 +80,6 @@ main(int argc, char *argv[])
|
|||||||
signal(SIGTERM, TerminateHandler);
|
signal(SIGTERM, TerminateHandler);
|
||||||
signal(SIGINT, TerminateHandler);
|
signal(SIGINT, TerminateHandler);
|
||||||
|
|
||||||
//create defaultconfig
|
|
||||||
ConfigFile *myConfig = new ConfigFile(argc, argv);
|
|
||||||
|
|
||||||
socket_startup();
|
socket_startup();
|
||||||
|
|
||||||
// Create pseudo Gui Wrapper for the server.
|
// Create pseudo Gui Wrapper for the server.
|
||||||
|
|||||||
+1
-1
@@ -212,7 +212,7 @@ void Session::startNetworkServer()
|
|||||||
assert(false);
|
assert(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
myNetServer = new ServerAcceptThread(*myGui, myConfig);
|
myNetServer = new ServerAcceptThread(*myGui, myConfig, *myAvatarManager);
|
||||||
myNetServer->Init(
|
myNetServer->Init(
|
||||||
myConfig->readConfigInt("ServerPort"),
|
myConfig->readConfigInt("ServerPort"),
|
||||||
myConfig->readConfigInt("ServerUseIpv6") == 1,
|
myConfig->readConfigInt("ServerUseIpv6") == 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user