Răsfoiți Sursa

Fix connection to game lobby & map load

Ivan Savenko 1 an în urmă
părinte
comite
22f0ca67c6

+ 38 - 19
client/CServerHandler.cpp

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

+ 8 - 4
client/CServerHandler.h

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

+ 2 - 1
client/NetPacksLobbyClient.cpp

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

+ 1 - 0
client/mainmenu/CMainMenu.cpp

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

+ 3 - 3
client/serverLobby/LobbyWindow.cpp

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

+ 3 - 3
client/serverLobby/LobbyWindow.h

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

+ 9 - 3
lib/network/NetworkClient.cpp

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

+ 1 - 0
lib/network/NetworkClient.h

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

+ 3 - 1
lib/network/NetworkConnection.cpp

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

+ 1 - 1
lib/network/NetworkConnection.h

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

+ 2 - 4
lib/network/NetworkListener.h

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

+ 78 - 325
lib/serializer/Connection.cpp

@@ -13,397 +13,150 @@
 #include "BinaryDeserializer.h"
 #include "BinarySerializer.h"
 
-//#include "../networkPacks/NetPacksBase.h"
+#include "../networkPacks/NetPacksBase.h"
+#include "../network/NetworkConnection.h"
 
-CConnection::CConnection(std::weak_ptr<NetworkConnection> networkConnection)
-{
-
-}
+VCMI_LIB_NAMESPACE_BEGIN
 
-void CConnection::sendPack(const CPack * pack)
+class DLL_LINKAGE ConnectionPackWriter final : public IBinaryWriter
 {
+public:
+	std::vector<uint8_t> buffer;
 
-}
-
-CPack * CConnection::retrievePack(const std::vector<uint8_t> & data)
-{
-	return nullptr;
-}
+	int write(const void * data, unsigned size) final;
+};
 
-void CConnection::disableStackSendingByID()
+class DLL_LINKAGE ConnectionPackReader final : public IBinaryReader
 {
+public:
+	const std::vector<uint8_t> * buffer;
+	size_t position;
 
-}
+	int read(void * data, unsigned size) final;
+};
 
-void CConnection::enterLobbyConnectionMode()
+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;
 }
 
-void CConnection::enterGameplayConnectionMode(CGameState * gs)
+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);
 
-int CConnection::write(const void * data, unsigned size)
-{
-	return 0;
+	std::copy_n(buffer->begin() + position, size, begin_ptr);
+	position += size;
+	return size;
 }
 
-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()
+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)
 {
-	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());
-    }
+	assert(networkConnection.lock() != nullptr);
 
 	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;
-	}
+	deserializer->fileVersion = SERIALIZATION_VERSION;
 }
 
-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() = default;
 
-CConnection::~CConnection()
+void CConnection::sendPack(const CPack * pack)
 {
-	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();
-	}
-}
+	auto connectionPtr = networkConnection.lock();
 
-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 [email protected] or [email protected]
-//    do not remove this exception it shoudnt be called
-	return *this;
-}
+	if (!connectionPtr)
+		throw std::runtime_error("Attempt to send packet on a closed connection!");
 
-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();
-	}
-}
+	*serializer & pack;
 
-bool CConnection::isOpen() const
-{
-	return socket && connected;
-}
+	logNetwork->trace("Sending a pack of type %s", typeid(*pack).name());
 
-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());
-	}
+	connectionPtr->sendPacket(packWriter->buffer);
+	packWriter->buffer.clear();
 }
 
-CPack * CConnection::retrievePack()
+CPack * CConnection::retrievePack(const std::vector<uint8_t> & data)
 {
-	enableBufferedRead = true;
+	CPack * result;
 
-	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.");
+	packReader->buffer = &data;
+	packReader->position = 0;
 
-	enableBufferedRead = false;
+	*deserializer & result;
 
-	return pack;
+	logNetwork->trace("Received CPack of type %s", (result ? typeid(*result).name() : "nullptr"));
+	return result;
 }
 
-void CConnection::sendPack(const CPack * pack)
+bool CConnection::isMyConnection(const std::shared_ptr<NetworkConnection> & otherConnection) const
 {
-	boost::unique_lock<boost::mutex> lock(*mutexWrite);
-	logNetwork->trace("Sending a pack of type %s", typeid(*pack).name());
-
-	enableBufferedWrite = true;
-
-	oser & pack;
-
-	flushBuffers();
+	return otherConnection != nullptr && networkConnection.lock() == otherConnection;
 }
 
 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::disableSmartVectorMemberSerialization()
+void CConnection::disableSmartPointerSerialization()
 {
-	CSerializer::smartVectorMembersSerialization = false;
+	deserializer->smartPointerSerialization = false;
+	serializer->smartPointerSerialization = false;
 }
 
-void CConnection::enableSmartVectorMemberSerializatoin()
+void CConnection::enableSmartPointerSerialization()
+{
+	deserializer->smartPointerSerialization = true;
+	serializer->smartPointerSerialization = true;
+}
+
+void CConnection::disableSmartVectorMemberSerialization()
 {
-	CSerializer::smartVectorMembersSerialization = true;
+	packReader->smartVectorMembersSerialization = false;
+	packWriter->smartVectorMembersSerialization = false;
 }
 
-std::string CConnection::toString() const
+void CConnection::enableSmartVectorMemberSerializatoin()
 {
-	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

+ 21 - 56
lib/serializer/Connection.h

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

+ 14 - 19
server/CVCMIServer.cpp

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

+ 2 - 6
server/CVCMIServer.h

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

+ 0 - 3
server/NetPacksLobbyServer.cpp

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