mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Fix connection to game lobby & map load
This commit is contained in:
parent
0a1153e1c6
commit
22f0ca67c6
@ -131,7 +131,11 @@ public:
|
||||
static const std::string NAME_AFFIX = "client";
|
||||
static const std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name
|
||||
|
||||
CServerHandler::~CServerHandler() = default;
|
||||
CServerHandler::~CServerHandler()
|
||||
{
|
||||
networkClient->stop();
|
||||
threadNetwork->join();
|
||||
}
|
||||
|
||||
CServerHandler::CServerHandler()
|
||||
: state(EClientState::NONE)
|
||||
@ -148,6 +152,16 @@ CServerHandler::CServerHandler()
|
||||
uuid = settings["server"]["uuid"].String();
|
||||
applier = std::make_shared<CApplier<CBaseForLobbyApply>>();
|
||||
registerTypesLobbyPacks(*applier);
|
||||
|
||||
threadNetwork = std::make_unique<boost::thread>(&CServerHandler::threadRunNetwork, this);
|
||||
}
|
||||
|
||||
void CServerHandler::threadRunNetwork()
|
||||
{
|
||||
logGlobal->info("Starting network thread");
|
||||
setThreadName("runNetwork");
|
||||
networkClient->run();
|
||||
logGlobal->info("Ending network thread");
|
||||
}
|
||||
|
||||
void CServerHandler::resetStateForLobby(const StartInfo::EMode mode, const std::vector<std::string> * names)
|
||||
@ -178,12 +192,13 @@ void CServerHandler::startLocalServerAndConnect(const std::function<void()> & on
|
||||
|
||||
auto errorMsg = CGI->generaltexth->translate("vcmi.server.errors.existingProcess");
|
||||
|
||||
if (!checkNetworkPortIsFree(localhostAddress, getDefaultPort()))
|
||||
{
|
||||
logNetwork->error("Port is busy, check if another instance of vcmiserver is working");
|
||||
CInfoWindow::showInfoDialog(errorMsg, {});
|
||||
return;
|
||||
}
|
||||
// TODO: restore
|
||||
// if (!checkNetworkPortIsFree(localhostAddress, getDefaultPort()))
|
||||
// {
|
||||
// logNetwork->error("Port is busy, check if another instance of vcmiserver is working");
|
||||
// CInfoWindow::showInfoDialog(errorMsg, {});
|
||||
// return;
|
||||
// }
|
||||
|
||||
#if defined(SINGLE_PROCESS_APP)
|
||||
boost::condition_variable cond;
|
||||
@ -195,7 +210,7 @@ void CServerHandler::startLocalServerAndConnect(const std::function<void()> & on
|
||||
args.push_back("--lobby-port=" + std::to_string(settings["session"]["port"].Integer()));
|
||||
args.push_back("--lobby-uuid=" + settings["session"]["hostUuid"].String());
|
||||
}
|
||||
threadRunLocalServer = std::make_shared<boost::thread>([&cond, args, this] {
|
||||
threadRunLocalServer = std::make_unique<boost::thread>([&cond, args, this] {
|
||||
setThreadName("CVCMIServer");
|
||||
CVCMIServer::create(&cond, args);
|
||||
onServerFinished();
|
||||
@ -207,7 +222,7 @@ void CServerHandler::startLocalServerAndConnect(const std::function<void()> & on
|
||||
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "startServer", true);
|
||||
}
|
||||
#else
|
||||
threadRunLocalServer = std::make_shared<boost::thread>(&CServerHandler::threadRunServer, this); //runs server executable;
|
||||
threadRunLocalServer = std::make_unique<boost::thread>(&CServerHandler::threadRunServer, this); //runs server executable;
|
||||
#endif
|
||||
logNetwork->trace("Setting up thread calling server: %d ms", th->getDiff());
|
||||
|
||||
@ -268,6 +283,10 @@ void CServerHandler::justConnectToServer(const std::string & addr, const ui16 po
|
||||
serverPort->Integer() = port;
|
||||
}
|
||||
|
||||
if (onConnectedCallback)
|
||||
throw std::runtime_error("Attempt to connect while there is already a pending connection!");
|
||||
|
||||
onConnectedCallback = onConnected;
|
||||
networkClient->start(addr.size() ? addr : getHostAddress(), port ? port : getHostPort());
|
||||
}
|
||||
|
||||
@ -288,14 +307,18 @@ void CServerHandler::onConnectionFailed(const std::string & errorMessage)
|
||||
networkClient->start(getHostAddress(), getHostPort());
|
||||
}
|
||||
|
||||
void CServerHandler::onConnectionEstablished()
|
||||
void CServerHandler::onConnectionEstablished(const std::shared_ptr<NetworkConnection> & netConnection)
|
||||
{
|
||||
logNetwork->info("Connection established");
|
||||
c = std::make_shared<CConnection>(netConnection);
|
||||
c->enterLobbyConnectionMode();
|
||||
sendClientConnecting();
|
||||
|
||||
//FIXME: call functor provided in CServerHandler::justConnectToServer
|
||||
assert(0);
|
||||
//onConnected();
|
||||
if (onConnectedCallback)
|
||||
{
|
||||
onConnectedCallback();
|
||||
onConnectedCallback = {};
|
||||
}
|
||||
}
|
||||
|
||||
void CServerHandler::applyPacksOnLobbyScreen()
|
||||
@ -620,7 +643,6 @@ void CServerHandler::sendStartGame(bool allowOnlyAI) const
|
||||
}
|
||||
sendLobbyPack(lsg);
|
||||
c->enterLobbyConnectionMode();
|
||||
c->disableStackSendingByID();
|
||||
}
|
||||
|
||||
void CServerHandler::startMapAfterConnection(std::shared_ptr<CMapInfo> to)
|
||||
@ -699,10 +721,7 @@ void CServerHandler::endGameplay(bool closeConnection, bool restart)
|
||||
}
|
||||
|
||||
if(c)
|
||||
{
|
||||
c->enterLobbyConnectionMode();
|
||||
c->disableStackSendingByID();
|
||||
}
|
||||
|
||||
//reset settings
|
||||
Settings saveSession = settings.write["server"]["reconnect"];
|
||||
@ -898,7 +917,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void CServerHandler::onPacketReceived(const std::vector<uint8_t> & message)
|
||||
void CServerHandler::onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message)
|
||||
{
|
||||
CPack * pack = c->retrievePack(message);
|
||||
if(state == EClientState::DISCONNECTING)
|
||||
@ -914,7 +933,7 @@ void CServerHandler::onPacketReceived(const std::vector<uint8_t> & message)
|
||||
}
|
||||
}
|
||||
|
||||
void CServerHandler::onDisconnected()
|
||||
void CServerHandler::onDisconnected(const std::shared_ptr<NetworkConnection> &)
|
||||
{
|
||||
if(state == EClientState::DISCONNECTING)
|
||||
{
|
||||
|
@ -98,14 +98,17 @@ class CServerHandler : public IServerAPI, public LobbyInfo, public INetworkClien
|
||||
|
||||
std::shared_ptr<HighScoreCalculation> highScoreCalc;
|
||||
|
||||
std::function<void()> onConnectedCallback;
|
||||
|
||||
void threadRunNetwork();
|
||||
void threadRunServer();
|
||||
void onServerFinished();
|
||||
void sendLobbyPack(const CPackForLobby & pack) const override;
|
||||
|
||||
void onPacketReceived(const std::vector<uint8_t> & message) override;
|
||||
void onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message) override;
|
||||
void onConnectionFailed(const std::string & errorMessage) override;
|
||||
void onConnectionEstablished() override;
|
||||
void onDisconnected() override;
|
||||
void onConnectionEstablished(const std::shared_ptr<NetworkConnection> &) override;
|
||||
void onDisconnected(const std::shared_ptr<NetworkConnection> &) override;
|
||||
|
||||
public:
|
||||
std::shared_ptr<CConnection> c;
|
||||
@ -122,7 +125,8 @@ public:
|
||||
////////////////////
|
||||
|
||||
std::unique_ptr<CStopWatch> th;
|
||||
std::shared_ptr<boost::thread> threadRunLocalServer;
|
||||
std::unique_ptr<boost::thread> threadRunLocalServer;
|
||||
std::unique_ptr<boost::thread> threadNetwork;
|
||||
|
||||
CClient * client;
|
||||
|
||||
|
@ -36,7 +36,8 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyClientConnected(LobbyClientCon
|
||||
result = false;
|
||||
|
||||
// Check if it's LobbyClientConnected for our client
|
||||
if(pack.uuid == handler.c->uuid)
|
||||
// TODO: restore
|
||||
//if(pack.uuid == handler.c->uuid)
|
||||
{
|
||||
handler.c->connectionID = pack.clientId;
|
||||
if(handler.mapToStart)
|
||||
|
@ -615,6 +615,7 @@ void CSimpleJoinScreen::startConnection(const std::string & addr, ui16 port)
|
||||
{
|
||||
// async call to prevent thread race
|
||||
GH.dispatchMainThread([this](){
|
||||
// FIXME: this enum value is never set!!!
|
||||
if(CSH->state == EClientState::CONNECTION_FAILED)
|
||||
{
|
||||
CInfoWindow::showInfoDialog(CGI->generaltexth->translate("vcmi.mainMenu.serverConnectionFailed"), {});
|
||||
|
@ -42,7 +42,7 @@ static std::string getCurrentTimeFormatted(int timeOffsetSeconds = 0)
|
||||
return timeFormatted.toString();
|
||||
}
|
||||
|
||||
void LobbyClient::onPacketReceived(const std::vector<uint8_t> & message)
|
||||
void LobbyClient::onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message)
|
||||
{
|
||||
// FIXME: find better approach
|
||||
const char * payloadBegin = reinterpret_cast<const char*>(message.data());
|
||||
@ -69,7 +69,7 @@ void LobbyClient::onPacketReceived(const std::vector<uint8_t> & message)
|
||||
}
|
||||
}
|
||||
|
||||
void LobbyClient::onConnectionEstablished()
|
||||
void LobbyClient::onConnectionEstablished(const std::shared_ptr<NetworkConnection> &)
|
||||
{
|
||||
JsonNode toSend;
|
||||
toSend["type"].String() = "authentication";
|
||||
@ -84,7 +84,7 @@ void LobbyClient::onConnectionFailed(const std::string & errorMessage)
|
||||
CInfoWindow::showInfoDialog("Failed to connect to game lobby!\n" + errorMessage, {});
|
||||
}
|
||||
|
||||
void LobbyClient::onDisconnected()
|
||||
void LobbyClient::onDisconnected(const std::shared_ptr<NetworkConnection> &)
|
||||
{
|
||||
GH.windows().popWindows(1);
|
||||
CInfoWindow::showInfoDialog("Connection to game lobby was lost!", {});
|
||||
|
@ -32,10 +32,10 @@ class LobbyClient : public INetworkClientListener
|
||||
std::unique_ptr<NetworkClient> networkClient;
|
||||
LobbyWindow * window;
|
||||
|
||||
void onPacketReceived(const std::vector<uint8_t> & message) override;
|
||||
void onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message) override;
|
||||
void onConnectionFailed(const std::string & errorMessage) override;
|
||||
void onConnectionEstablished() override;
|
||||
void onDisconnected() override;
|
||||
void onConnectionEstablished(const std::shared_ptr<NetworkConnection> &) override;
|
||||
void onDisconnected(const std::shared_ptr<NetworkConnection> &) override;
|
||||
|
||||
public:
|
||||
explicit LobbyClient(LobbyWindow * window);
|
||||
|
@ -56,11 +56,12 @@ void NetworkClient::onConnected(const boost::system::error_code & ec)
|
||||
connection = std::make_shared<NetworkConnection>(socket, *this);
|
||||
connection->start();
|
||||
|
||||
listener.onConnectionEstablished();
|
||||
listener.onConnectionEstablished(connection);
|
||||
}
|
||||
|
||||
void NetworkClient::run()
|
||||
{
|
||||
boost::asio::executor_work_guard<decltype(io->get_executor())> work{io->get_executor()};
|
||||
io->run();
|
||||
}
|
||||
|
||||
@ -69,6 +70,11 @@ void NetworkClient::poll()
|
||||
io->poll();
|
||||
}
|
||||
|
||||
void NetworkClient::stop()
|
||||
{
|
||||
io->stop();
|
||||
}
|
||||
|
||||
void NetworkClient::sendPacket(const std::vector<uint8_t> & message)
|
||||
{
|
||||
connection->sendPacket(message);
|
||||
@ -76,12 +82,12 @@ void NetworkClient::sendPacket(const std::vector<uint8_t> & message)
|
||||
|
||||
void NetworkClient::onDisconnected(const std::shared_ptr<NetworkConnection> & connection)
|
||||
{
|
||||
listener.onDisconnected();
|
||||
listener.onDisconnected(connection);
|
||||
}
|
||||
|
||||
void NetworkClient::onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message)
|
||||
{
|
||||
listener.onPacketReceived(message);
|
||||
listener.onPacketReceived(connection, message);
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
void start(const std::string & host, uint16_t port);
|
||||
void run();
|
||||
void poll();
|
||||
void stop();
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -16,7 +16,9 @@ NetworkConnection::NetworkConnection(const std::shared_ptr<NetworkSocket> & sock
|
||||
: socket(socket)
|
||||
, listener(listener)
|
||||
{
|
||||
|
||||
socket->set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
socket->set_option(boost::asio::socket_base::send_buffer_size(4194304));
|
||||
socket->set_option(boost::asio::socket_base::receive_buffer_size(4194304));
|
||||
}
|
||||
|
||||
void NetworkConnection::start()
|
||||
|
@ -17,7 +17,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
class DLL_LINKAGE NetworkConnection :public std::enable_shared_from_this<NetworkConnection>, boost::noncopyable
|
||||
{
|
||||
static const int messageHeaderSize = sizeof(uint32_t);
|
||||
static const int messageMaxSize = 65536; // arbitrary size to prevent potential massive allocation if we receive garbage input
|
||||
static const int messageMaxSize = 64 * 1024 * 1024; // arbitrary size to prevent potential massive allocation if we receive garbage input
|
||||
|
||||
std::shared_ptr<NetworkSocket> socket;
|
||||
|
||||
|
@ -34,14 +34,12 @@ protected:
|
||||
~INetworkServerListener() = default;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE INetworkClientListener
|
||||
class DLL_LINKAGE INetworkClientListener : public INetworkConnectionListener
|
||||
{
|
||||
friend class NetworkClient;
|
||||
protected:
|
||||
virtual void onPacketReceived(const std::vector<uint8_t> & message) = 0;
|
||||
virtual void onConnectionFailed(const std::string & errorMessage) = 0;
|
||||
virtual void onConnectionEstablished() = 0;
|
||||
virtual void onDisconnected() = 0;
|
||||
virtual void onConnectionEstablished(const std::shared_ptr<NetworkConnection> &) = 0;
|
||||
|
||||
~INetworkClientListener() = default;
|
||||
};
|
||||
|
@ -13,397 +13,150 @@
|
||||
#include "BinaryDeserializer.h"
|
||||
#include "BinarySerializer.h"
|
||||
|
||||
//#include "../networkPacks/NetPacksBase.h"
|
||||
#include "../networkPacks/NetPacksBase.h"
|
||||
#include "../network/NetworkConnection.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class DLL_LINKAGE ConnectionPackWriter final : public IBinaryWriter
|
||||
{
|
||||
public:
|
||||
std::vector<uint8_t> buffer;
|
||||
|
||||
int write(const void * data, unsigned size) final;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ConnectionPackReader final : public IBinaryReader
|
||||
{
|
||||
public:
|
||||
const std::vector<uint8_t> * buffer;
|
||||
size_t position;
|
||||
|
||||
int read(void * data, unsigned size) final;
|
||||
};
|
||||
|
||||
int ConnectionPackWriter::write(const void * data, unsigned size)
|
||||
{
|
||||
const uint8_t * begin_ptr = static_cast<const uint8_t *>(data);
|
||||
const uint8_t * end_ptr = begin_ptr + size;
|
||||
buffer.insert(buffer.end(), begin_ptr, end_ptr);
|
||||
return size;
|
||||
}
|
||||
|
||||
int ConnectionPackReader::read(void * data, unsigned size)
|
||||
{
|
||||
if (position + size > buffer->size())
|
||||
throw std::runtime_error("End of file reached when reading received network pack!");
|
||||
|
||||
uint8_t * begin_ptr = static_cast<uint8_t *>(data);
|
||||
|
||||
std::copy_n(buffer->begin() + position, size, begin_ptr);
|
||||
position += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
CConnection::CConnection(std::weak_ptr<NetworkConnection> networkConnection)
|
||||
: networkConnection(networkConnection)
|
||||
, packReader(std::make_unique<ConnectionPackReader>())
|
||||
, packWriter(std::make_unique<ConnectionPackWriter>())
|
||||
, deserializer(std::make_unique<BinaryDeserializer>(packReader.get()))
|
||||
, serializer(std::make_unique<BinarySerializer>(packWriter.get()))
|
||||
, connectionID(-1)
|
||||
{
|
||||
assert(networkConnection.lock() != nullptr);
|
||||
|
||||
enableSmartPointerSerialization();
|
||||
disableStackSendingByID();
|
||||
deserializer->fileVersion = SERIALIZATION_VERSION;
|
||||
}
|
||||
|
||||
CConnection::~CConnection() = default;
|
||||
|
||||
void CConnection::sendPack(const CPack * pack)
|
||||
{
|
||||
auto connectionPtr = networkConnection.lock();
|
||||
|
||||
if (!connectionPtr)
|
||||
throw std::runtime_error("Attempt to send packet on a closed connection!");
|
||||
|
||||
*serializer & pack;
|
||||
|
||||
logNetwork->trace("Sending a pack of type %s", typeid(*pack).name());
|
||||
|
||||
connectionPtr->sendPacket(packWriter->buffer);
|
||||
packWriter->buffer.clear();
|
||||
}
|
||||
|
||||
CPack * CConnection::retrievePack(const std::vector<uint8_t> & data)
|
||||
{
|
||||
return nullptr;
|
||||
CPack * result;
|
||||
|
||||
packReader->buffer = &data;
|
||||
packReader->position = 0;
|
||||
|
||||
*deserializer & result;
|
||||
|
||||
logNetwork->trace("Received CPack of type %s", (result ? typeid(*result).name() : "nullptr"));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CConnection::isMyConnection(const std::shared_ptr<NetworkConnection> & otherConnection) const
|
||||
{
|
||||
return otherConnection != nullptr && networkConnection.lock() == otherConnection;
|
||||
}
|
||||
|
||||
void CConnection::disableStackSendingByID()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CConnection::enterLobbyConnectionMode()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CConnection::enterGameplayConnectionMode(CGameState * gs)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CConnection::write(const void * data, unsigned size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CConnection::read(void * data, unsigned size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
using namespace boost;
|
||||
using namespace boost::asio::ip;
|
||||
|
||||
struct ConnectionBuffers
|
||||
{
|
||||
boost::asio::streambuf readBuffer;
|
||||
boost::asio::streambuf writeBuffer;
|
||||
};
|
||||
|
||||
void CConnection::init()
|
||||
{
|
||||
enableBufferedWrite = false;
|
||||
enableBufferedRead = false;
|
||||
connectionBuffers = std::make_unique<ConnectionBuffers>();
|
||||
|
||||
socket->set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
try
|
||||
{
|
||||
socket->set_option(boost::asio::socket_base::send_buffer_size(4194304));
|
||||
socket->set_option(boost::asio::socket_base::receive_buffer_size(4194304));
|
||||
}
|
||||
catch (const boost::system::system_error & e)
|
||||
{
|
||||
logNetwork->error("error setting socket option: %s", e.what());
|
||||
}
|
||||
|
||||
enableSmartPointerSerialization();
|
||||
disableStackSendingByID();
|
||||
#ifndef VCMI_ENDIAN_BIG
|
||||
myEndianess = true;
|
||||
#else
|
||||
myEndianess = false;
|
||||
#endif
|
||||
connected = true;
|
||||
std::string pom;
|
||||
//we got connection
|
||||
oser & std::string("Aiya!\n") & name & uuid & myEndianess; //identify ourselves
|
||||
iser & pom & pom & contactUuid & contactEndianess;
|
||||
logNetwork->info("Established connection with %s. UUID: %s", pom, contactUuid);
|
||||
mutexRead = std::make_shared<boost::mutex>();
|
||||
mutexWrite = std::make_shared<boost::mutex>();
|
||||
|
||||
iser.fileVersion = SERIALIZATION_VERSION;
|
||||
}
|
||||
|
||||
CConnection::CConnection(const std::string & host, ui16 port, std::string Name, std::string UUID):
|
||||
io_service(std::make_shared<asio::io_service>()),
|
||||
iser(this),
|
||||
oser(this),
|
||||
name(std::move(Name)),
|
||||
uuid(std::move(UUID))
|
||||
{
|
||||
int i = 0;
|
||||
boost::system::error_code error = asio::error::host_not_found;
|
||||
socket = std::make_shared<tcp::socket>(*io_service);
|
||||
|
||||
tcp::resolver resolver(*io_service);
|
||||
tcp::resolver::iterator end;
|
||||
tcp::resolver::iterator pom;
|
||||
tcp::resolver::iterator endpoint_iterator = resolver.resolve(tcp::resolver::query(host, std::to_string(port)), error);
|
||||
if(error)
|
||||
{
|
||||
logNetwork->error("Problem with resolving: \n%s", error.message());
|
||||
throw std::runtime_error("Problem with resolving");
|
||||
}
|
||||
pom = endpoint_iterator;
|
||||
if(pom != end)
|
||||
logNetwork->info("Found endpoints:");
|
||||
else
|
||||
{
|
||||
logNetwork->error("Critical problem: No endpoints found!");
|
||||
throw std::runtime_error("No endpoints found!");
|
||||
}
|
||||
while(pom != end)
|
||||
{
|
||||
logNetwork->info("\t%d:%s", i, (boost::asio::ip::tcp::endpoint&)*pom);
|
||||
pom++;
|
||||
}
|
||||
i=0;
|
||||
while(endpoint_iterator != end)
|
||||
{
|
||||
logNetwork->info("Trying connection to %s(%d)", (boost::asio::ip::tcp::endpoint&)*endpoint_iterator, i++);
|
||||
socket->connect(*endpoint_iterator, error);
|
||||
if(!error)
|
||||
{
|
||||
init();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Failed to connect!");
|
||||
}
|
||||
endpoint_iterator++;
|
||||
}
|
||||
}
|
||||
|
||||
CConnection::CConnection(std::shared_ptr<TSocket> Socket, std::string Name, std::string UUID):
|
||||
iser(this),
|
||||
oser(this),
|
||||
socket(std::move(Socket)),
|
||||
name(std::move(Name)),
|
||||
uuid(std::move(UUID))
|
||||
{
|
||||
init();
|
||||
}
|
||||
CConnection::CConnection(const std::shared_ptr<TAcceptor> & acceptor,
|
||||
const std::shared_ptr<boost::asio::io_service> & io_service,
|
||||
std::string Name,
|
||||
std::string UUID):
|
||||
io_service(io_service),
|
||||
iser(this),
|
||||
oser(this),
|
||||
name(std::move(Name)),
|
||||
uuid(std::move(UUID))
|
||||
{
|
||||
boost::system::error_code error = asio::error::host_not_found;
|
||||
socket = std::make_shared<tcp::socket>(*io_service);
|
||||
acceptor->accept(*socket,error);
|
||||
if (error)
|
||||
{
|
||||
logNetwork->error("Error on accepting: %s", error.message());
|
||||
socket.reset();
|
||||
throw std::runtime_error("Can't establish connection :(");
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
void CConnection::flushBuffers()
|
||||
{
|
||||
if(!enableBufferedWrite)
|
||||
return;
|
||||
|
||||
if (!socket)
|
||||
throw std::runtime_error("Can't write to closed socket!");
|
||||
|
||||
try
|
||||
{
|
||||
asio::write(*socket, connectionBuffers->writeBuffer);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
//connection has been lost
|
||||
connected = false;
|
||||
throw;
|
||||
}
|
||||
|
||||
enableBufferedWrite = false;
|
||||
}
|
||||
|
||||
int CConnection::write(const void * data, unsigned size)
|
||||
{
|
||||
if (!socket)
|
||||
throw std::runtime_error("Can't write to closed socket!");
|
||||
|
||||
try
|
||||
{
|
||||
if(enableBufferedWrite)
|
||||
{
|
||||
std::ostream ostream(&connectionBuffers->writeBuffer);
|
||||
|
||||
ostream.write(static_cast<const char *>(data), size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int ret = static_cast<int>(asio::write(*socket, asio::const_buffers_1(asio::const_buffer(data, size))));
|
||||
return ret;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
//connection has been lost
|
||||
connected = false;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
int CConnection::read(void * data, unsigned size)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(enableBufferedRead)
|
||||
{
|
||||
auto available = connectionBuffers->readBuffer.size();
|
||||
|
||||
while(available < size)
|
||||
{
|
||||
auto bytesRead = socket->read_some(connectionBuffers->readBuffer.prepare(1024));
|
||||
connectionBuffers->readBuffer.commit(bytesRead);
|
||||
available = connectionBuffers->readBuffer.size();
|
||||
}
|
||||
|
||||
std::istream istream(&connectionBuffers->readBuffer);
|
||||
|
||||
istream.read(static_cast<char *>(data), size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int ret = static_cast<int>(asio::read(*socket,asio::mutable_buffers_1(asio::mutable_buffer(data,size))));
|
||||
return ret;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
//connection has been lost
|
||||
connected = false;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
CConnection::~CConnection()
|
||||
{
|
||||
close();
|
||||
|
||||
if(handler)
|
||||
{
|
||||
// ugly workaround to avoid self-join if last strong reference to shared_ptr that owns this class has been released in this very thread, e.g. on netpack processing
|
||||
if (boost::this_thread::get_id() != handler->get_id())
|
||||
handler->join();
|
||||
else
|
||||
handler->detach();
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
CConnection & CConnection::operator&(const T &t) {
|
||||
// throw std::exception();
|
||||
//XXX this is temporaly ? solution to fix gcc (4.3.3, other?) compilation
|
||||
// problem for more details contact t0@czlug.icis.pcz.pl or impono@gmail.com
|
||||
// do not remove this exception it shoudnt be called
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CConnection::close()
|
||||
{
|
||||
if(socket)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket->shutdown(boost::asio::ip::tcp::socket::shutdown_receive);
|
||||
}
|
||||
catch (const boost::system::system_error & e)
|
||||
{
|
||||
logNetwork->error("error closing socket: %s", e.what());
|
||||
}
|
||||
|
||||
socket->close();
|
||||
socket.reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool CConnection::isOpen() const
|
||||
{
|
||||
return socket && connected;
|
||||
}
|
||||
|
||||
void CConnection::reportState(vstd::CLoggerBase * out)
|
||||
{
|
||||
out->debug("CConnection");
|
||||
if(socket && socket->is_open())
|
||||
{
|
||||
out->debug("\tWe have an open and valid socket");
|
||||
out->debug("\t %d bytes awaiting", socket->available());
|
||||
}
|
||||
}
|
||||
|
||||
CPack * CConnection::retrievePack()
|
||||
{
|
||||
enableBufferedRead = true;
|
||||
|
||||
CPack * pack = nullptr;
|
||||
boost::unique_lock<boost::mutex> lock(*mutexRead);
|
||||
iser & pack;
|
||||
logNetwork->trace("Received CPack of type %s", (pack ? typeid(*pack).name() : "nullptr"));
|
||||
if(pack == nullptr)
|
||||
logNetwork->error("Received a nullptr CPack! You should check whether client and server ABI matches.");
|
||||
|
||||
enableBufferedRead = false;
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
void CConnection::sendPack(const CPack * pack)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(*mutexWrite);
|
||||
logNetwork->trace("Sending a pack of type %s", typeid(*pack).name());
|
||||
|
||||
enableBufferedWrite = true;
|
||||
|
||||
oser & pack;
|
||||
|
||||
flushBuffers();
|
||||
}
|
||||
|
||||
void CConnection::disableStackSendingByID()
|
||||
{
|
||||
CSerializer::sendStackInstanceByIds = false;
|
||||
packReader->sendStackInstanceByIds = false;
|
||||
packWriter->sendStackInstanceByIds = false;
|
||||
}
|
||||
|
||||
void CConnection::enableStackSendingByID()
|
||||
{
|
||||
CSerializer::sendStackInstanceByIds = true;
|
||||
}
|
||||
|
||||
void CConnection::disableSmartPointerSerialization()
|
||||
{
|
||||
iser.smartPointerSerialization = oser.smartPointerSerialization = false;
|
||||
}
|
||||
|
||||
void CConnection::enableSmartPointerSerialization()
|
||||
{
|
||||
iser.smartPointerSerialization = oser.smartPointerSerialization = true;
|
||||
packReader->sendStackInstanceByIds = true;
|
||||
packWriter->sendStackInstanceByIds = true;
|
||||
}
|
||||
|
||||
void CConnection::enterLobbyConnectionMode()
|
||||
{
|
||||
iser.loadedPointers.clear();
|
||||
oser.savedPointers.clear();
|
||||
deserializer->loadedPointers.clear();
|
||||
serializer->savedPointers.clear();
|
||||
disableSmartVectorMemberSerialization();
|
||||
disableSmartPointerSerialization();
|
||||
disableStackSendingByID();
|
||||
}
|
||||
|
||||
void CConnection::enterGameplayConnectionMode(CGameState * gs)
|
||||
{
|
||||
enableStackSendingByID();
|
||||
disableSmartPointerSerialization();
|
||||
addStdVecItems(gs);
|
||||
|
||||
packReader->addStdVecItems(gs);
|
||||
packWriter->addStdVecItems(gs);
|
||||
}
|
||||
|
||||
void CConnection::disableSmartPointerSerialization()
|
||||
{
|
||||
deserializer->smartPointerSerialization = false;
|
||||
serializer->smartPointerSerialization = false;
|
||||
}
|
||||
|
||||
void CConnection::enableSmartPointerSerialization()
|
||||
{
|
||||
deserializer->smartPointerSerialization = true;
|
||||
serializer->smartPointerSerialization = true;
|
||||
}
|
||||
|
||||
void CConnection::disableSmartVectorMemberSerialization()
|
||||
{
|
||||
CSerializer::smartVectorMembersSerialization = false;
|
||||
packReader->smartVectorMembersSerialization = false;
|
||||
packWriter->smartVectorMembersSerialization = false;
|
||||
}
|
||||
|
||||
void CConnection::enableSmartVectorMemberSerializatoin()
|
||||
{
|
||||
CSerializer::smartVectorMembersSerialization = true;
|
||||
}
|
||||
|
||||
std::string CConnection::toString() const
|
||||
{
|
||||
boost::format fmt("Connection with %s (ID: %d UUID: %s)");
|
||||
fmt % name % connectionID % uuid;
|
||||
return fmt.str();
|
||||
packReader->smartVectorMembersSerialization = true;
|
||||
packWriter->smartVectorMembersSerialization = true;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
@ -9,84 +9,49 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "CSerializer.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class BinaryDeserializer;
|
||||
class BinarySerializer;
|
||||
struct CPack;
|
||||
struct ConnectionBuffers;
|
||||
class NetworkConnection;
|
||||
class ConnectionPackReader;
|
||||
class ConnectionPackWriter;
|
||||
class CGameState;
|
||||
|
||||
/// Main class for network communication
|
||||
/// Allows establishing connection and bidirectional read-write
|
||||
class DLL_LINKAGE CConnection : public IBinaryReader, public IBinaryWriter, public std::enable_shared_from_this<CConnection>
|
||||
/// Wrapper class for game connection
|
||||
/// Handles serialization and deserialization of data received from network
|
||||
class DLL_LINKAGE CConnection : boost::noncopyable
|
||||
{
|
||||
/// Non-owning pointer to underlying connection
|
||||
std::weak_ptr<NetworkConnection> networkConnection;
|
||||
|
||||
// void init();
|
||||
// void reportState(vstd::CLoggerBase * out) override;
|
||||
//
|
||||
int write(const void * data, unsigned size) override;
|
||||
int read(void * data, unsigned size) override;
|
||||
// void flushBuffers();
|
||||
//
|
||||
// bool enableBufferedWrite;
|
||||
// bool enableBufferedRead;
|
||||
// std::unique_ptr<ConnectionBuffers> connectionBuffers;
|
||||
//
|
||||
std::unique_ptr<BinaryDeserializer> iser;
|
||||
std::unique_ptr<BinarySerializer> oser;
|
||||
//
|
||||
// std::string contactUuid;
|
||||
// std::string name; //who uses this connection
|
||||
std::unique_ptr<ConnectionPackReader> packReader;
|
||||
std::unique_ptr<ConnectionPackWriter> packWriter;
|
||||
std::unique_ptr<BinaryDeserializer> deserializer;
|
||||
std::unique_ptr<BinarySerializer> serializer;
|
||||
|
||||
void disableStackSendingByID();
|
||||
void enableStackSendingByID();
|
||||
void disableSmartPointerSerialization();
|
||||
void enableSmartPointerSerialization();
|
||||
void disableSmartVectorMemberSerialization();
|
||||
void enableSmartVectorMemberSerializatoin();
|
||||
|
||||
public:
|
||||
bool isMyConnection(const std::shared_ptr<NetworkConnection> & otherConnection) const;
|
||||
|
||||
std::string uuid;
|
||||
int connectionID;
|
||||
|
||||
CConnection(std::weak_ptr<NetworkConnection> networkConnection);
|
||||
// CConnection(const std::string & host, ui16 port, std::string Name, std::string UUID);
|
||||
// CConnection(const std::shared_ptr<TAcceptor> & acceptor, const std::shared_ptr<boost::asio::io_service> & Io_service, std::string Name, std::string UUID);
|
||||
// CConnection(std::shared_ptr<TSocket> Socket, std::string Name, std::string UUID); //use immediately after accepting connection into socket
|
||||
// virtual ~CConnection();
|
||||
~CConnection();
|
||||
|
||||
// void close();
|
||||
// bool isOpen() const;
|
||||
//
|
||||
// CPack * retrievePack();
|
||||
void sendPack(const CPack * pack);
|
||||
|
||||
CPack * retrievePack(const std::vector<uint8_t> & data);
|
||||
// std::vector<uint8_t> serializePack(const CPack * pack);
|
||||
//
|
||||
void disableStackSendingByID();
|
||||
// void enableStackSendingByID();
|
||||
// void disableSmartPointerSerialization();
|
||||
// void enableSmartPointerSerialization();
|
||||
// void disableSmartVectorMemberSerialization();
|
||||
// void enableSmartVectorMemberSerializatoin();
|
||||
//
|
||||
|
||||
void enterLobbyConnectionMode();
|
||||
void enterGameplayConnectionMode(CGameState * gs);
|
||||
//
|
||||
// std::string toString() const;
|
||||
//
|
||||
// template<class T>
|
||||
// CConnection & operator>>(T &t)
|
||||
// {
|
||||
// iser & t;
|
||||
// return * this;
|
||||
// }
|
||||
//
|
||||
// template<class T>
|
||||
// CConnection & operator<<(const T &t)
|
||||
// {
|
||||
// oser & t;
|
||||
// return * this;
|
||||
// }
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -177,7 +177,10 @@ void CVCMIServer::onNewConnection(const std::shared_ptr<NetworkConnection> & con
|
||||
establishOutgoingConnection();
|
||||
|
||||
if(state == EServerState::LOBBY)
|
||||
{
|
||||
activeConnections.push_back(std::make_shared<CConnection>(connection));//, SERVER_NAME, uuid);)
|
||||
activeConnections.back()->enterLobbyConnectionMode();
|
||||
}
|
||||
// TODO: else: deny connection
|
||||
// TODO: else: try to reconnect / send state to reconnected client
|
||||
}
|
||||
@ -193,26 +196,16 @@ void CVCMIServer::onPacketReceived(const std::shared_ptr<NetworkConnection> & co
|
||||
//FIXME: delete pack?
|
||||
}
|
||||
|
||||
void CVCMIServer::onPacketReceived(const std::vector<uint8_t> & message)
|
||||
{
|
||||
//TODO: handle pack received from lobby
|
||||
}
|
||||
|
||||
void CVCMIServer::onConnectionFailed(const std::string & errorMessage)
|
||||
{
|
||||
//TODO: handle failure to connect to lobby
|
||||
}
|
||||
|
||||
void CVCMIServer::onConnectionEstablished()
|
||||
void CVCMIServer::onConnectionEstablished(const std::shared_ptr<NetworkConnection> &)
|
||||
{
|
||||
//TODO: handle connection to lobby - login?
|
||||
}
|
||||
|
||||
void CVCMIServer::onDisconnected()
|
||||
{
|
||||
//TODO: handle disconnection from lobby
|
||||
}
|
||||
|
||||
void CVCMIServer::setState(EServerState value)
|
||||
{
|
||||
state.store(value);
|
||||
@ -225,9 +218,13 @@ EServerState CVCMIServer::getState() const
|
||||
|
||||
std::shared_ptr<CConnection> CVCMIServer::findConnection(const std::shared_ptr<NetworkConnection> & netConnection)
|
||||
{
|
||||
//TODO
|
||||
assert(0);
|
||||
return nullptr;
|
||||
for (auto const & gameConnection : activeConnections)
|
||||
{
|
||||
if (gameConnection->isMyConnection(netConnection))
|
||||
return gameConnection;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unknown connection received in CVCMIServer::findConnection");
|
||||
}
|
||||
|
||||
void CVCMIServer::run()
|
||||
@ -294,10 +291,8 @@ void CVCMIServer::prepareToRestart()
|
||||
}
|
||||
|
||||
for(auto c : activeConnections)
|
||||
{
|
||||
c->enterLobbyConnectionMode();
|
||||
c->disableStackSendingByID();
|
||||
}
|
||||
|
||||
boost::unique_lock<boost::recursive_mutex> queueLock(mx);
|
||||
gh = nullptr;
|
||||
}
|
||||
@ -417,8 +412,8 @@ void CVCMIServer::announcePack(std::unique_ptr<CPackForLobby> pack)
|
||||
{
|
||||
// FIXME: we need to avoid sending something to client that not yet get answer for LobbyClientConnected
|
||||
// Until UUID set we only pass LobbyClientConnected to this client
|
||||
if(c->uuid == uuid && !dynamic_cast<LobbyClientConnected *>(pack.get()))
|
||||
continue;
|
||||
//if(c->uuid == uuid && !dynamic_cast<LobbyClientConnected *>(pack.get()))
|
||||
// continue;
|
||||
|
||||
c->sendPack(pack.get());
|
||||
}
|
||||
|
@ -70,16 +70,12 @@ private:
|
||||
std::unique_ptr<boost::thread> remoteConnectionsThread;
|
||||
std::atomic<EServerState> state;
|
||||
|
||||
// INetworkServerListener impl
|
||||
// INetworkListener impl
|
||||
void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) override;
|
||||
void onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message) override;
|
||||
void onNewConnection(const std::shared_ptr<NetworkConnection> &) override;
|
||||
|
||||
// INetworkClientListener impl
|
||||
void onPacketReceived(const std::vector<uint8_t> & message) override;
|
||||
void onConnectionFailed(const std::string & errorMessage) override;
|
||||
void onConnectionEstablished() override;
|
||||
void onDisconnected() override;
|
||||
void onConnectionEstablished(const std::shared_ptr<NetworkConnection> &) override;
|
||||
|
||||
void establishOutgoingConnection();
|
||||
|
||||
|
@ -210,10 +210,7 @@ void ApplyOnServerNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack)
|
||||
void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack)
|
||||
{
|
||||
for(auto & c : srv.activeConnections)
|
||||
{
|
||||
c->enterLobbyConnectionMode();
|
||||
c->disableStackSendingByID();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientPermissionsCheckerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
|
||||
|
Loading…
Reference in New Issue
Block a user