The client network code was rewritten to use boost::asio. Some optimization is still required, and some code files can now be removed.
This commit is contained in:
@@ -24,7 +24,6 @@ ClientContext::ClientContext()
|
||||
: m_protocol(0), m_addrFamily(AF_INET), m_useServerList(false), m_serverPort(0),
|
||||
m_hasSubscribedLobbyMsg(true)
|
||||
{
|
||||
bzero(&m_clientSockaddr, sizeof(m_clientSockaddr));
|
||||
}
|
||||
|
||||
ClientContext::~ClientContext()
|
||||
@@ -32,13 +31,6 @@ ClientContext::~ClientContext()
|
||||
m_sessionData.reset();
|
||||
}
|
||||
|
||||
SOCKET
|
||||
ClientContext::GetSocket() const
|
||||
{
|
||||
assert(m_sessionData.get());
|
||||
return m_sessionData->GetSocket();
|
||||
}
|
||||
|
||||
boost::shared_ptr<SessionData>
|
||||
ClientContext::GetSessionData() const
|
||||
{
|
||||
@@ -51,3 +43,15 @@ ClientContext::SetSessionData(boost::shared_ptr<SessionData> sessionData)
|
||||
m_sessionData = sessionData;
|
||||
}
|
||||
|
||||
boost::shared_ptr<boost::asio::ip::tcp::resolver>
|
||||
ClientContext::GetResolver() const
|
||||
{
|
||||
return m_resolver;
|
||||
}
|
||||
|
||||
void
|
||||
ClientContext::SetResolver(boost::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
|
||||
{
|
||||
m_resolver = resolver;
|
||||
}
|
||||
|
||||
|
||||
+901
-865
File diff suppressed because it is too large
Load Diff
+132
-52
@@ -39,6 +39,8 @@
|
||||
#include <cassert>
|
||||
|
||||
#define TEMP_AVATAR_FILENAME "avatar.tmp"
|
||||
#define CLIENT_AVATAR_LOOP_MSEC 100
|
||||
#define CLIENT_SEND_LOOP_MSEC 50
|
||||
|
||||
using namespace std;
|
||||
using boost::asio::ip::tcp;
|
||||
@@ -62,10 +64,11 @@ private:
|
||||
};
|
||||
|
||||
ClientThread::ClientThread(GuiInterface &gui, AvatarManager &avatarManager)
|
||||
: m_curState(NULL), m_gui(gui), m_avatarManager(avatarManager), m_isServerSelected(false),
|
||||
m_curGameId(0), m_curGameNum(1), m_guiPlayerId(0), m_sessionEstablished(false)
|
||||
: m_ioService(new boost::asio::io_service), m_curState(NULL), m_gui(gui),
|
||||
m_avatarManager(avatarManager), m_isServerSelected(false),
|
||||
m_curGameId(0), m_curGameNum(1), m_guiPlayerId(0), m_sessionEstablished(false),
|
||||
m_stateTimer(*m_ioService), m_avatarTimer(*m_ioService), m_sendTimer(*m_ioService)
|
||||
{
|
||||
m_ioService.reset(new boost::asio::io_service());
|
||||
m_context.reset(new ClientContext);
|
||||
m_receiver.reset(new ReceiverHelper);
|
||||
myQtToolsInterface.reset(CreateQtToolsWrapper());
|
||||
@@ -106,6 +109,13 @@ ClientThread::Init(
|
||||
context.SetCacheDir(cacheDir);
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::SignalTermination()
|
||||
{
|
||||
Thread::SignalTermination();
|
||||
m_ioService->stop();
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::SendKickPlayer(unsigned playerId)
|
||||
{
|
||||
@@ -286,6 +296,27 @@ ClientThread::SendVoteKick(bool doKick)
|
||||
m_outPacketList.push_back(vote);
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::StartAsyncRead()
|
||||
{
|
||||
ReceiveBuffer &buf = GetContext().GetSessionData()->GetReceiveBuffer();
|
||||
GetContext().GetSessionData()->GetAsioSocket()->async_read_some(
|
||||
boost::asio::buffer(buf.recvBuf + buf.recvBufUsed, RECV_BUF_SIZE - buf.recvBufUsed),
|
||||
boost::bind(
|
||||
&ClientThread::HandleRead,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::HandleRead(const boost::system::error_code& ec, size_t bytesRead)
|
||||
{
|
||||
GetState().HandleRead(ec, shared_from_this(), bytesRead);
|
||||
if (!ec)
|
||||
StartAsyncRead();
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::SelectServer(unsigned serverId)
|
||||
{
|
||||
@@ -381,51 +412,67 @@ ClientThread::Main()
|
||||
m_avatarDownloader.reset(new DownloaderThread);
|
||||
m_avatarDownloader->Run();
|
||||
SetState(CLIENT_INITIAL_STATE::Instance());
|
||||
RegisterTimers();
|
||||
|
||||
// Main loop.
|
||||
boost::asio::io_service::work ioWork(*m_ioService);
|
||||
try
|
||||
{
|
||||
while (!ShouldTerminate())
|
||||
{
|
||||
int msg = GetState().Process(*this);
|
||||
if (msg != MSG_SOCK_INTERNAL_PENDING)
|
||||
{
|
||||
if (msg <= MSG_SOCK_LIMIT_CONNECT)
|
||||
GetCallback().SignalNetClientConnect(msg);
|
||||
else
|
||||
GetCallback().SignalNetClientGameInfo(msg);
|
||||
|
||||
// Additionally signal the start of the game.
|
||||
if (msg == MSG_NET_GAME_CLIENT_START)
|
||||
{
|
||||
// EngineFactory erstellen
|
||||
boost::shared_ptr<EngineFactory> factory(new ClientEngineFactory); // LocalEngine erstellen
|
||||
|
||||
MapPlayerDataList();
|
||||
if (GetPlayerDataList().size() != (unsigned)GetStartData().numberOfPlayers)
|
||||
throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PLAYER_COUNT, 0);
|
||||
m_game.reset(new Game(&m_gui, factory, GetPlayerDataList(), GetGameData(), GetStartData(), m_curGameNum++));
|
||||
// Initialize GUI speed.
|
||||
GetGui().initGui(GetGameData().guiSpeed);
|
||||
// Signal start of game to GUI.
|
||||
GetCallback().SignalNetClientGameStart(m_game);
|
||||
}
|
||||
}
|
||||
if (IsSessionEstablished())
|
||||
SendPacketLoop();
|
||||
m_ioService->poll();
|
||||
Thread::Msleep(10);
|
||||
boost::asio::io_service::work ioWork(*m_ioService);
|
||||
m_ioService->run(); // Will only be aborted asynchronously.
|
||||
}
|
||||
} catch (const PokerTHException &e)
|
||||
{
|
||||
GetCallback().SignalNetClientError(e.GetErrorId(), e.GetOsErrorCode());
|
||||
}
|
||||
// Cancel timers.
|
||||
GetStateTimer().cancel();
|
||||
CancelTimers();
|
||||
// Terminate sub-threads.
|
||||
m_avatarDownloader->SignalTermination();
|
||||
m_avatarDownloader->Join(DOWNLOADER_THREAD_TERMINATE_TIMEOUT);
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::RegisterTimers()
|
||||
{
|
||||
m_avatarTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(CLIENT_AVATAR_LOOP_MSEC));
|
||||
m_avatarTimer.async_wait(
|
||||
boost::bind(
|
||||
&ClientThread::TimerCheckAvatarDownloads, shared_from_this(), boost::asio::placeholders::error));
|
||||
|
||||
m_sendTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(CLIENT_SEND_LOOP_MSEC));
|
||||
m_sendTimer.async_wait(
|
||||
boost::bind(
|
||||
&ClientThread::TimerSendPacketLoop, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::CancelTimers()
|
||||
{
|
||||
m_avatarTimer.cancel();
|
||||
m_sendTimer.cancel();
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::InitGame()
|
||||
{
|
||||
// EngineFactory erstellen
|
||||
boost::shared_ptr<EngineFactory> factory(new ClientEngineFactory); // LocalEngine erstellen
|
||||
|
||||
MapPlayerDataList();
|
||||
if (GetPlayerDataList().size() != (unsigned)GetStartData().numberOfPlayers)
|
||||
throw ClientException(__FILE__, __LINE__, ERR_NET_INVALID_PLAYER_COUNT, 0);
|
||||
m_game.reset(new Game(&m_gui, factory, GetPlayerDataList(), GetGameData(), GetStartData(), m_curGameNum++));
|
||||
// Initialize GUI speed.
|
||||
GetGui().initGui(GetGameData().guiSpeed);
|
||||
// Signal start of game to GUI.
|
||||
GetCallback().SignalNetClientGameStart(m_game);
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::AddPacket(boost::shared_ptr<NetPacket> packet)
|
||||
{
|
||||
@@ -434,21 +481,32 @@ ClientThread::AddPacket(boost::shared_ptr<NetPacket> packet)
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::SendPacketLoop()
|
||||
ClientThread::TimerSendPacketLoop(const boost::system::error_code &ec)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_outPacketListMutex);
|
||||
|
||||
if (!m_outPacketList.empty())
|
||||
if (!ec)
|
||||
{
|
||||
NetPacketList::iterator i = m_outPacketList.begin();
|
||||
NetPacketList::iterator end = m_outPacketList.end();
|
||||
|
||||
while (i != end)
|
||||
if (IsSessionEstablished())
|
||||
{
|
||||
GetSender().Send(GetContext().GetSessionData(), *i);
|
||||
++i;
|
||||
boost::mutex::scoped_lock lock(m_outPacketListMutex);
|
||||
|
||||
if (!m_outPacketList.empty())
|
||||
{
|
||||
NetPacketList::iterator i = m_outPacketList.begin();
|
||||
NetPacketList::iterator end = m_outPacketList.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
GetSender().Send(GetContext().GetSessionData(), *i);
|
||||
++i;
|
||||
}
|
||||
m_outPacketList.clear();
|
||||
}
|
||||
}
|
||||
m_outPacketList.clear();
|
||||
m_sendTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(CLIENT_SEND_LOOP_MSEC));
|
||||
m_sendTimer.async_wait(
|
||||
boost::bind(
|
||||
&ClientThread::TimerSendPacketLoop, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,15 +726,23 @@ ClientThread::SetUnknownAvatar(unsigned playerId)
|
||||
}
|
||||
|
||||
void
|
||||
ClientThread::CheckAvatarDownloads()
|
||||
ClientThread::TimerCheckAvatarDownloads(const boost::system::error_code& ec)
|
||||
{
|
||||
if (m_avatarDownloader && m_avatarDownloader->HasDownloadResult())
|
||||
if (!ec)
|
||||
{
|
||||
unsigned playerId;
|
||||
boost::shared_ptr<AvatarData> tmpAvatar(new AvatarData);
|
||||
m_avatarDownloader->GetDownloadResult(playerId, tmpAvatar->fileData);
|
||||
tmpAvatar->reportedSize = tmpAvatar->fileData.size();
|
||||
PassAvatarDataToManager(playerId, tmpAvatar);
|
||||
if (m_avatarDownloader && m_avatarDownloader->HasDownloadResult())
|
||||
{
|
||||
unsigned playerId;
|
||||
boost::shared_ptr<AvatarData> tmpAvatar(new AvatarData);
|
||||
m_avatarDownloader->GetDownloadResult(playerId, tmpAvatar->fileData);
|
||||
tmpAvatar->reportedSize = tmpAvatar->fileData.size();
|
||||
PassAvatarDataToManager(playerId, tmpAvatar);
|
||||
}
|
||||
m_avatarTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(CLIENT_AVATAR_LOOP_MSEC));
|
||||
m_avatarTimer.async_wait(
|
||||
boost::bind(
|
||||
&ClientThread::TimerCheckAvatarDownloads, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -724,10 +790,13 @@ void
|
||||
ClientThread::CreateContextSession()
|
||||
{
|
||||
bool validSocket = false;
|
||||
// TODO ipv6
|
||||
// TODO sctp
|
||||
try {
|
||||
boost::shared_ptr<tcp::socket> newSock(new boost::asio::ip::tcp::socket(*m_ioService, tcp::v4()));
|
||||
boost::shared_ptr<tcp::socket> newSock;
|
||||
if (GetContext().GetAddrFamily() == AF_INET6)
|
||||
newSock.reset(new boost::asio::ip::tcp::socket(*m_ioService, tcp::v6()));
|
||||
else
|
||||
newSock.reset(new boost::asio::ip::tcp::socket(*m_ioService, tcp::v4()));
|
||||
boost::asio::socket_base::non_blocking_io command(true);
|
||||
newSock->io_control(command);
|
||||
newSock->set_option(tcp::no_delay(true));
|
||||
@@ -737,6 +806,8 @@ ClientThread::CreateContextSession()
|
||||
newSock,
|
||||
SESSION_ID_GENERIC,
|
||||
*m_senderCallback)));
|
||||
GetContext().SetResolver(boost::shared_ptr<boost::asio::ip::tcp::resolver>(
|
||||
new boost::asio::ip::tcp::resolver(*m_ioService)));
|
||||
validSocket = true;
|
||||
} catch (...)
|
||||
{
|
||||
@@ -755,7 +826,16 @@ ClientThread::GetState()
|
||||
void
|
||||
ClientThread::SetState(ClientState &newState)
|
||||
{
|
||||
if (m_curState)
|
||||
m_curState->Exit(shared_from_this());
|
||||
m_curState = &newState;
|
||||
m_curState->Enter(shared_from_this());
|
||||
}
|
||||
|
||||
boost::asio::deadline_timer &
|
||||
ClientThread::GetStateTimer()
|
||||
{
|
||||
return m_stateTimer;
|
||||
}
|
||||
|
||||
SenderHelper &
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/***************************************************************************
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <net/servercontext.h>
|
||||
|
||||
ServerContext::ServerContext()
|
||||
: m_protocol(0), m_addrFamily(AF_INET), m_serverPort(0)
|
||||
{
|
||||
}
|
||||
|
||||
ServerContext::~ServerContext()
|
||||
{
|
||||
}
|
||||
|
||||
SOCKET
|
||||
ServerContext::GetSocket() const
|
||||
{
|
||||
return m_sock;
|
||||
}
|
||||
|
||||
void
|
||||
ServerContext::SetSocket(SOCKET sock)
|
||||
{
|
||||
m_sock = sock;
|
||||
}
|
||||
|
||||
@@ -165,8 +165,8 @@ ServerLobbyThread::AddConnection(boost::shared_ptr<tcp::socket> sock)
|
||||
boost::bind(
|
||||
&ServerLobbyThread::HandleRead,
|
||||
this,
|
||||
sessionData->GetId(),
|
||||
boost::asio::placeholders::error,
|
||||
sessionData->GetId(),
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
}
|
||||
@@ -513,9 +513,10 @@ ServerLobbyThread::Main()
|
||||
RegisterTimers();
|
||||
try
|
||||
{
|
||||
m_work.reset(new boost::asio::io_service::work(*m_ioService));
|
||||
m_ioService->run(); // Will only be aborted asynchronously.
|
||||
m_work.reset();
|
||||
{
|
||||
boost::asio::io_service::work ioWork(*m_ioService);
|
||||
m_ioService->run(); // Will only be aborted asynchronously.
|
||||
}
|
||||
|
||||
// Clear all sessions.
|
||||
m_sessionManager.Clear();
|
||||
@@ -585,7 +586,7 @@ ServerLobbyThread::CancelTimers()
|
||||
}
|
||||
|
||||
void
|
||||
ServerLobbyThread::HandleRead(SessionId sessionId, const boost::system::error_code &error, size_t bytesRead)
|
||||
ServerLobbyThread::HandleRead(const boost::system::error_code &ec, SessionId sessionId, size_t bytesRead)
|
||||
{
|
||||
// Find the session.
|
||||
SessionWrapper session = m_sessionManager.GetSessionById(sessionId);
|
||||
@@ -593,7 +594,7 @@ ServerLobbyThread::HandleRead(SessionId sessionId, const boost::system::error_co
|
||||
session = m_gameSessionManager.GetSessionById(sessionId);
|
||||
if (session.sessionData)
|
||||
{
|
||||
if (!error)
|
||||
if (!ec)
|
||||
{
|
||||
ReceiveBuffer &buf = session.sessionData->GetReceiveBuffer();
|
||||
buf.recvBufUsed += bytesRead;
|
||||
@@ -625,8 +626,8 @@ ServerLobbyThread::HandleRead(SessionId sessionId, const boost::system::error_co
|
||||
boost::bind(
|
||||
&ServerLobbyThread::HandleRead,
|
||||
this,
|
||||
sessionId,
|
||||
boost::asio::placeholders::error,
|
||||
sessionId,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include <net/socket_helper.h>
|
||||
#include <net/servermanager.h>
|
||||
#include <net/servercontext.h>
|
||||
#include <net/ircthread.h>
|
||||
#include <net/connectdata.h>
|
||||
#include <net/serverlobbythread.h>
|
||||
@@ -39,7 +38,7 @@ using namespace std;
|
||||
ServerManager::ServerManager(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager)
|
||||
: m_gui(gui), m_playerConfig(config), m_avatarManager(avatarManager)
|
||||
{
|
||||
m_ioService.reset(new boost::asio::io_service());
|
||||
m_ioService.reset(new boost::asio::io_service);
|
||||
}
|
||||
|
||||
ServerManager::~ServerManager()
|
||||
|
||||
Reference in New Issue
Block a user