1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

Fix connection to game lobby & map load

This commit is contained in:
Ivan Savenko 2023-12-25 21:23:27 +02:00
parent 0a1153e1c6
commit 22f0ca67c6
16 changed files with 211 additions and 473 deletions

View File

@ -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)
{

View File

@ -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;

View File

@ -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)

View File

@ -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"), {});

View File

@ -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!", {});

View File

@ -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);

View File

@ -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);
}

View File

@ -42,6 +42,7 @@ public:
void start(const std::string & host, uint16_t port);
void run();
void poll();
void stop();
};
VCMI_LIB_NAMESPACE_END

View File

@ -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()

View File

@ -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;

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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());
}

View File

@ -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();

View File

@ -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)