浏览代码

Finalized new TCP networking API

Ivan Savenko 1 年之前
父节点
当前提交
80e960bc8e

+ 9 - 9
client/CServerHandler.cpp

@@ -46,7 +46,6 @@
 #include "../lib/mapping/CMapInfo.h"
 #include "../lib/mapObjects/MiscObjects.h"
 #include "../lib/modding/ModIncompatibility.h"
-#include "../lib/network/NetworkClient.h"
 #include "../lib/rmg/CMapGenOptions.h"
 #include "../lib/serializer/Connection.h"
 #include "../lib/filesystem/Filesystem.h"
@@ -132,15 +131,16 @@ static const std::string NAME = GameConstants::VCMI_VERSION + std::string(" (")
 
 CServerHandler::~CServerHandler()
 {
-	networkClient->stop();
+	networkHandler->stop();
 	threadNetwork->join();
 }
 
 CServerHandler::CServerHandler()
 	: state(EClientState::NONE)
-	, networkClient(std::make_unique<NetworkClient>(*this))
+	, networkHandler(INetworkHandler::createHandler())
+	, networkClient(networkHandler->createClientTCP(*this))
 	, applier(std::make_unique<CApplier<CBaseForLobbyApply>>())
-	, lobbyClient(std::make_unique<GlobalLobbyClient>())
+	, lobbyClient(std::make_unique<GlobalLobbyClient>(networkHandler))
 	, client(nullptr)
 	, loadMode(0)
 	, campaignStateToSend(nullptr)
@@ -155,7 +155,7 @@ void CServerHandler::threadRunNetwork()
 {
 	logGlobal->info("Starting network thread");
 	setThreadName("runNetwork");
-	networkClient->run();
+	networkHandler->run();
 	logGlobal->info("Ending network thread");
 }
 
@@ -277,7 +277,7 @@ void CServerHandler::onConnectionFailed(const std::string & errorMessage)
 	{
 		// retry - local server might be still starting up
 		logNetwork->debug("\nCannot establish connection. %s. Retrying...", errorMessage);
-		networkClient->setTimer(std::chrono::milliseconds(100));
+		networkHandler->createTimer(*this, std::chrono::milliseconds(100));
 	}
 	else
 	{
@@ -299,7 +299,7 @@ void CServerHandler::onTimer()
 	networkClient->start(getLocalHostname(), getLocalPort());
 }
 
-void CServerHandler::onConnectionEstablished(const std::shared_ptr<NetworkConnection> & netConnection)
+void CServerHandler::onConnectionEstablished(const std::shared_ptr<INetworkConnection> & netConnection)
 {
 	logNetwork->info("Connection established");
 	c = std::make_shared<CConnection>(netConnection);
@@ -852,7 +852,7 @@ public:
 	}
 };
 
-void CServerHandler::onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message)
+void CServerHandler::onPacketReceived(const std::shared_ptr<INetworkConnection> &, const std::vector<uint8_t> & message)
 {
 	CPack * pack = c->retrievePack(message);
 	if(state == EClientState::DISCONNECTING)
@@ -868,7 +868,7 @@ void CServerHandler::onPacketReceived(const std::shared_ptr<NetworkConnection> &
 	}
 }
 
-void CServerHandler::onDisconnected(const std::shared_ptr<NetworkConnection> &)
+void CServerHandler::onDisconnected(const std::shared_ptr<INetworkConnection> &)
 {
 	if(state == EClientState::DISCONNECTING)
 	{

+ 7 - 6
client/CServerHandler.h

@@ -11,7 +11,7 @@
 
 #include "../lib/CStopWatch.h"
 
-#include "../lib/network/NetworkListener.h"
+#include "../lib/network/NetworkInterface.h"
 #include "../lib/StartInfo.h"
 #include "../lib/CondSh.h"
 
@@ -82,11 +82,12 @@ public:
 };
 
 /// structure to handle running server and connecting to it
-class CServerHandler : public IServerAPI, public LobbyInfo, public INetworkClientListener, boost::noncopyable
+class CServerHandler : public IServerAPI, public LobbyInfo, public INetworkClientListener, public INetworkTimerListener, boost::noncopyable
 {
 	friend class ApplyOnLobbyHandlerNetPackVisitor;
 
-	std::unique_ptr<NetworkClient> networkClient;
+	std::unique_ptr<INetworkHandler> networkHandler;
+	std::unique_ptr<INetworkClient> networkClient;
 	std::unique_ptr<GlobalLobbyClient> lobbyClient;
 	std::unique_ptr<CApplier<CBaseForLobbyApply>> applier;
 	std::shared_ptr<CMapInfo> mapToStart;
@@ -98,10 +99,10 @@ class CServerHandler : public IServerAPI, public LobbyInfo, public INetworkClien
 	void onServerFinished();
 	void sendLobbyPack(const CPackForLobby & pack) const override;
 
-	void onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message) override;
+	void onPacketReceived(const std::shared_ptr<INetworkConnection> &, const std::vector<uint8_t> & message) override;
 	void onConnectionFailed(const std::string & errorMessage) override;
-	void onConnectionEstablished(const std::shared_ptr<NetworkConnection> &) override;
-	void onDisconnected(const std::shared_ptr<NetworkConnection> &) override;
+	void onConnectionEstablished(const std::shared_ptr<INetworkConnection> &) override;
+	void onDisconnected(const std::shared_ptr<INetworkConnection> &) override;
 	void onTimer() override;
 
 	void applyPackOnLobbyScreen(CPackForLobby & pack);

+ 7 - 21
client/globalLobby/GlobalLobbyClient.cpp

@@ -21,21 +21,12 @@
 #include "../../lib/CConfigHandler.h"
 #include "../../lib/MetaString.h"
 #include "../../lib/TextOperations.h"
-#include "../../lib/network/NetworkClient.h"
 
-GlobalLobbyClient::~GlobalLobbyClient()
-{
-	networkClient->stop();
-	networkThread->join();
-}
+GlobalLobbyClient::~GlobalLobbyClient() = default;
 
-GlobalLobbyClient::GlobalLobbyClient()
-	: networkClient(std::make_unique<NetworkClient>(*this))
-{
-	networkThread = std::make_unique<boost::thread>([this](){
-		networkClient->run();
-	});
-}
+GlobalLobbyClient::GlobalLobbyClient(const std::unique_ptr<INetworkHandler> & handler)
+	: networkClient(handler->createClientTCP(*this))
+{}
 
 static std::string getCurrentTimeFormatted(int timeOffsetSeconds = 0)
 {
@@ -46,7 +37,7 @@ static std::string getCurrentTimeFormatted(int timeOffsetSeconds = 0)
 	return TextOperations::getFormattedTimeLocal(std::chrono::system_clock::to_time_t(timeNowChrono));
 }
 
-void GlobalLobbyClient::onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message)
+void GlobalLobbyClient::onPacketReceived(const std::shared_ptr<INetworkConnection> &, const std::vector<uint8_t> & message)
 {
 	boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
 
@@ -158,7 +149,7 @@ void GlobalLobbyClient::receiveActiveAccounts(const JsonNode & json)
 	//}
 }
 
-void GlobalLobbyClient::onConnectionEstablished(const std::shared_ptr<NetworkConnection> &)
+void GlobalLobbyClient::onConnectionEstablished(const std::shared_ptr<INetworkConnection> &)
 {
 	JsonNode toSend;
 
@@ -198,17 +189,12 @@ void GlobalLobbyClient::onConnectionFailed(const std::string & errorMessage)
 	loginWindowPtr->onConnectionFailed(errorMessage);
 }
 
-void GlobalLobbyClient::onDisconnected(const std::shared_ptr<NetworkConnection> &)
+void GlobalLobbyClient::onDisconnected(const std::shared_ptr<INetworkConnection> &)
 {
 	GH.windows().popWindows(1);
 	CInfoWindow::showInfoDialog("Connection to game lobby was lost!", {});
 }
 
-void GlobalLobbyClient::onTimer()
-{
-	// no-op
-}
-
 void GlobalLobbyClient::sendMessage(const JsonNode & data)
 {
 	std::string payloadString = data.toJson(true);

+ 6 - 8
client/globalLobby/GlobalLobbyClient.h

@@ -9,7 +9,7 @@
  */
 #pragma once
 
-#include "../../lib/network/NetworkListener.h"
+#include "../../lib/network/NetworkInterface.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 class JsonNode;
@@ -20,18 +20,16 @@ class GlobalLobbyWindow;
 
 class GlobalLobbyClient : public INetworkClientListener, boost::noncopyable
 {
-	std::unique_ptr<boost::thread> networkThread;
-	std::unique_ptr<NetworkClient> networkClient;
+	std::unique_ptr<INetworkClient> networkClient;
 
 	std::weak_ptr<GlobalLobbyLoginWindow> loginWindow;
 	std::weak_ptr<GlobalLobbyWindow> lobbyWindow;
 	std::shared_ptr<GlobalLobbyWindow> lobbyWindowLock; // helper strong reference to prevent window destruction on closing
 
-	void onPacketReceived(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message) override;
+	void onPacketReceived(const std::shared_ptr<INetworkConnection> &, const std::vector<uint8_t> & message) override;
 	void onConnectionFailed(const std::string & errorMessage) override;
-	void onConnectionEstablished(const std::shared_ptr<NetworkConnection> &) override;
-	void onDisconnected(const std::shared_ptr<NetworkConnection> &) override;
-	void onTimer() override;
+	void onConnectionEstablished(const std::shared_ptr<INetworkConnection> &) override;
+	void onDisconnected(const std::shared_ptr<INetworkConnection> &) override;
 
 	void sendClientRegister();
 	void sendClientLogin();
@@ -44,7 +42,7 @@ class GlobalLobbyClient : public INetworkClientListener, boost::noncopyable
 	void receiveActiveAccounts(const JsonNode & json);
 
 public:
-	explicit GlobalLobbyClient();
+	explicit GlobalLobbyClient(const std::unique_ptr<INetworkHandler> & handler);
 	~GlobalLobbyClient();
 
 	void sendMessage(const JsonNode & data);

+ 5 - 2
client/gui/InterfaceObjectConfigurable.cpp

@@ -130,8 +130,11 @@ void InterfaceObjectConfigurable::build(const JsonNode &config)
 	for(const auto & item : items->Vector())
 		addWidget(item["name"].String(), buildWidget(item));
 
-	pos.w = config["width"].Integer();
-	pos.h = config["height"].Integer();
+	// load only if set
+	if (!config["width"].isNull())
+		pos.w = config["width"].Integer();
+	if (!config["height"].isNull())
+		pos.h = config["height"].Integer();
 }
 
 void InterfaceObjectConfigurable::addConditional(const std::string & name, bool active)

+ 3 - 1
cmake_modules/VCMI_lib.cmake

@@ -126,6 +126,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 
 		${MAIN_LIB_DIR}/network/NetworkClient.cpp
 		${MAIN_LIB_DIR}/network/NetworkConnection.cpp
+		${MAIN_LIB_DIR}/network/NetworkHandler.cpp
 		${MAIN_LIB_DIR}/network/NetworkServer.cpp
 
 		${MAIN_LIB_DIR}/networkPacks/NetPacksLib.cpp
@@ -478,7 +479,8 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/network/NetworkClient.h
 		${MAIN_LIB_DIR}/network/NetworkConnection.h
 		${MAIN_LIB_DIR}/network/NetworkDefines.h
-		${MAIN_LIB_DIR}/network/NetworkListener.h
+		${MAIN_LIB_DIR}/network/NetworkHandler.h
+		${MAIN_LIB_DIR}/network/NetworkInterface.h
 		${MAIN_LIB_DIR}/network/NetworkServer.h
 
 		${MAIN_LIB_DIR}/networkPacks/ArtifactLocation.h

+ 6 - 31
lib/network/NetworkClient.cpp

@@ -13,9 +13,9 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-NetworkClient::NetworkClient(INetworkClientListener & listener)
-	: io(new NetworkService)
-	, socket(new NetworkSocket(*io))
+NetworkClient::NetworkClient(INetworkClientListener & listener, const std::shared_ptr<NetworkContext> & context)
+	: io(context)
+	, socket(std::make_shared<NetworkSocket>(*context))
 	, listener(listener)
 {
 }
@@ -39,54 +39,29 @@ void NetworkClient::onConnected(const boost::system::error_code & ec)
 		return;
 	}
 
-	connection = std::make_shared<NetworkConnection>(socket, *this);
+	connection = std::make_shared<NetworkConnection>(*this, socket);
 	connection->start();
 
 	listener.onConnectionEstablished(connection);
 }
 
-void NetworkClient::run()
-{
-	boost::asio::executor_work_guard<decltype(io->get_executor())> work{io->get_executor()};
-	io->run();
-}
-
-void NetworkClient::poll()
-{
-	io->poll();
-}
-
-void NetworkClient::stop()
-{
-	io->stop();
-}
-
 bool NetworkClient::isConnected() const
 {
 	return connection != nullptr;
 }
 
-void NetworkClient::setTimer(std::chrono::milliseconds duration)
-{
-	auto timer = std::make_shared<NetworkTimer>(*io, duration);
-	timer->async_wait([this, timer](const boost::system::error_code& error){
-		if (!error)
-			listener.onTimer();
-	});
-}
-
 void NetworkClient::sendPacket(const std::vector<uint8_t> & message)
 {
 	connection->sendPacket(message);
 }
 
-void NetworkClient::onDisconnected(const std::shared_ptr<NetworkConnection> & connection)
+void NetworkClient::onDisconnected(const std::shared_ptr<INetworkConnection> & connection)
 {
 	this->connection.reset();
 	listener.onDisconnected(connection);
 }
 
-void NetworkClient::onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message)
+void NetworkClient::onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<uint8_t> & message)
 {
 	listener.onPacketReceived(connection, message);
 }

+ 8 - 14
lib/network/NetworkClient.h

@@ -10,15 +10,14 @@
 #pragma once
 
 #include "NetworkDefines.h"
-#include "NetworkListener.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
 class NetworkConnection;
 
-class DLL_LINKAGE NetworkClient : boost::noncopyable, public INetworkConnectionListener
+class NetworkClient : public INetworkConnectionListener, public INetworkClient
 {
-	std::shared_ptr<NetworkService> io;
+	std::shared_ptr<NetworkContext> io;
 	std::shared_ptr<NetworkSocket> socket;
 	std::shared_ptr<NetworkConnection> connection;
 
@@ -26,22 +25,17 @@ class DLL_LINKAGE NetworkClient : boost::noncopyable, public INetworkConnectionL
 
 	void onConnected(const boost::system::error_code & ec);
 
-	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 onDisconnected(const std::shared_ptr<INetworkConnection> & connection) override;
+	void onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<uint8_t> & message) override;
 
 public:
-	NetworkClient(INetworkClientListener & listener);
-	virtual ~NetworkClient() = default;
+	NetworkClient(INetworkClientListener & listener, const std::shared_ptr<NetworkContext> & context);
 
-	bool isConnected() const;
+	bool isConnected() const override;
 
-	void setTimer(std::chrono::milliseconds duration);
-	void sendPacket(const std::vector<uint8_t> & message);
+	void sendPacket(const std::vector<uint8_t> & message) override;
 
-	void start(const std::string & host, uint16_t port);
-	void run();
-	void poll();
-	void stop();
+	void start(const std::string & host, uint16_t port) override;
 };
 
 VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/network/NetworkConnection.cpp

@@ -12,7 +12,7 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-NetworkConnection::NetworkConnection(const std::shared_ptr<NetworkSocket> & socket, INetworkConnectionListener & listener)
+NetworkConnection::NetworkConnection(INetworkConnectionListener & listener, const std::shared_ptr<NetworkSocket> & socket)
 	: socket(socket)
 	, listener(listener)
 {

+ 3 - 4
lib/network/NetworkConnection.h

@@ -10,11 +10,10 @@
 #pragma once
 
 #include "NetworkDefines.h"
-#include "NetworkListener.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-class DLL_LINKAGE NetworkConnection :public std::enable_shared_from_this<NetworkConnection>, boost::noncopyable
+class NetworkConnection : public INetworkConnection, public std::enable_shared_from_this<NetworkConnection>
 {
 	static const int messageHeaderSize = sizeof(uint32_t);
 	static const int messageMaxSize = 64 * 1024 * 1024; // arbitrary size to prevent potential massive allocation if we receive garbage input
@@ -29,10 +28,10 @@ class DLL_LINKAGE NetworkConnection :public std::enable_shared_from_this<Network
 	uint32_t readPacketSize();
 
 public:
-	NetworkConnection(const std::shared_ptr<NetworkSocket> & socket, INetworkConnectionListener & listener);
+	NetworkConnection(INetworkConnectionListener & listener, const std::shared_ptr<NetworkSocket> & socket);
 
 	void start();
-	void sendPacket(const std::vector<uint8_t> & message);
+	void sendPacket(const std::vector<uint8_t> & message) override;
 };
 
 VCMI_LIB_NAMESPACE_END

+ 3 - 1
lib/network/NetworkDefines.h

@@ -11,9 +11,11 @@
 
 #include <boost/asio.hpp>
 
+#include "NetworkInterface.h"
+
 VCMI_LIB_NAMESPACE_BEGIN
 
-using NetworkService = boost::asio::io_service;
+using NetworkContext = boost::asio::io_service;
 using NetworkSocket = boost::asio::ip::tcp::socket;
 using NetworkAcceptor = boost::asio::ip::tcp::acceptor;
 using NetworkBuffer = boost::asio::streambuf;

+ 57 - 0
lib/network/NetworkHandler.cpp

@@ -0,0 +1,57 @@
+/*
+ * NetworkHandler.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "NetworkHandler.h"
+
+#include "NetworkClient.h"
+#include "NetworkServer.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+std::unique_ptr<INetworkHandler> INetworkHandler::createHandler()
+{
+	return std::make_unique<NetworkHandler>();
+}
+
+NetworkHandler::NetworkHandler()
+	: io(std::make_shared<NetworkContext>())
+{}
+
+std::unique_ptr<INetworkServer> NetworkHandler::createServerTCP(INetworkServerListener & listener)
+{
+	return std::make_unique<NetworkServer>(listener, io);
+}
+
+std::unique_ptr<INetworkClient> NetworkHandler::createClientTCP(INetworkClientListener & listener)
+{
+	return std::make_unique<NetworkClient>(listener, io);
+}
+
+void NetworkHandler::run()
+{
+	boost::asio::executor_work_guard<decltype(io->get_executor())> work{io->get_executor()};
+	io->run();
+}
+
+void NetworkHandler::createTimer(INetworkTimerListener & listener, std::chrono::milliseconds duration)
+{
+	auto timer = std::make_shared<NetworkTimer>(*io, duration);
+	timer->async_wait([&listener, timer](const boost::system::error_code& error){
+		if (!error)
+			listener.onTimer();
+	});
+}
+
+void NetworkHandler::stop()
+{
+	io->stop();
+}
+
+VCMI_LIB_NAMESPACE_END

+ 31 - 0
lib/network/NetworkHandler.h

@@ -0,0 +1,31 @@
+/*
+ * NetworkHandler.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "NetworkDefines.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+class NetworkHandler : public INetworkHandler
+{
+	std::shared_ptr<NetworkContext> io;
+
+public:
+	NetworkHandler();
+
+	std::unique_ptr<INetworkServer> createServerTCP(INetworkServerListener & listener) override;
+	std::unique_ptr<INetworkClient> createClientTCP(INetworkClientListener & listener) override;
+	void createTimer(INetworkTimerListener & listener, std::chrono::milliseconds duration) override;
+
+	void run() override;
+	void stop() override;
+};
+
+VCMI_LIB_NAMESPACE_END

+ 104 - 0
lib/network/NetworkInterface.h

@@ -0,0 +1,104 @@
+/*
+ * NetworkHandler.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+/// Base class for connections with other services, either incoming or outgoing
+class DLL_LINKAGE INetworkConnection : boost::noncopyable
+{
+public:
+	virtual ~INetworkConnection() = default;
+	virtual void sendPacket(const std::vector<uint8_t> & message) = 0;
+};
+
+using NetworkConnectionPtr = std::shared_ptr<INetworkConnection>;
+using NetworkConnectionWeakPtr = std::weak_ptr<INetworkConnection>;
+
+/// Base class for outgoing connections support
+class DLL_LINKAGE INetworkClient : boost::noncopyable
+{
+public:
+	virtual ~INetworkClient() = default;
+
+	virtual bool isConnected() const = 0;
+	virtual void sendPacket(const std::vector<uint8_t> & message) = 0;
+	virtual void start(const std::string & host, uint16_t port) = 0;
+};
+
+/// Base class for incoming connections support
+class DLL_LINKAGE INetworkServer : boost::noncopyable
+{
+public:
+	virtual ~INetworkServer() = default;
+
+	virtual void sendPacket(const std::shared_ptr<INetworkConnection> &, const std::vector<uint8_t> & message) = 0;
+	virtual void closeConnection(const std::shared_ptr<INetworkConnection> &) = 0;
+	virtual void start(uint16_t port) = 0;
+};
+
+/// Base interface that must be implemented by user of networking API to handle any connection callbacks
+class DLL_LINKAGE INetworkConnectionListener
+{
+public:
+	virtual void onDisconnected(const std::shared_ptr<INetworkConnection> & connection) = 0;
+	virtual void onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<uint8_t> & message) = 0;
+
+	virtual ~INetworkConnectionListener() = default;
+};
+
+/// Interface that must be implemented by user of networking API to handle outgoing connection callbacks
+class DLL_LINKAGE INetworkClientListener : public INetworkConnectionListener
+{
+public:
+	virtual void onConnectionFailed(const std::string & errorMessage) = 0;
+	virtual void onConnectionEstablished(const std::shared_ptr<INetworkConnection> &) = 0;
+};
+
+/// Interface that must be implemented by user of networking API to handle incoming connection callbacks
+class DLL_LINKAGE INetworkServerListener : public INetworkConnectionListener
+{
+public:
+	virtual void onNewConnection(const std::shared_ptr<INetworkConnection> &) = 0;
+};
+
+/// Interface that must be implemented by user of networking API to handle timers on network thread
+class DLL_LINKAGE INetworkTimerListener
+{
+public:
+	virtual ~INetworkTimerListener() = default;
+
+	virtual void onTimer() = 0;
+};
+
+/// Main class for handling of all network activity
+class DLL_LINKAGE INetworkHandler : boost::noncopyable
+{
+public:
+	virtual ~INetworkHandler() = default;
+
+	/// Constructs default implementation
+	static std::unique_ptr<INetworkHandler> createHandler();
+
+	/// Creates an instance of TCP server that allows to receiving connections on a local port
+	virtual std::unique_ptr<INetworkServer> createServerTCP(INetworkServerListener & listener) = 0;
+
+	/// Creates an instance of TCP client that allows to establish single outgoing connection to a remote port
+	virtual std::unique_ptr<INetworkClient> createClientTCP(INetworkClientListener & listener) = 0;
+
+	/// Creates a timer that will be called once, after specified interval has passed
+	virtual void createTimer(INetworkTimerListener & listener, std::chrono::milliseconds duration) = 0;
+
+	/// Starts network processing on this thread. Does not returns until networking processing has been terminated
+	virtual void run() = 0;
+	virtual void stop() = 0;
+};
+
+VCMI_LIB_NAMESPACE_END

+ 0 - 56
lib/network/NetworkListener.h

@@ -1,56 +0,0 @@
-/*
- * NetworkListener.h, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-#pragma once
-
-VCMI_LIB_NAMESPACE_BEGIN
-
-class NetworkConnection;
-class NetworkServer;
-class NetworkClient;
-
-using NetworkConnectionPtr = std::shared_ptr<NetworkConnection>;
-using NetworkConnectionWeakPtr = std::weak_ptr<NetworkConnection>;
-
-class DLL_LINKAGE INetworkConnectionListener
-{
-	friend class NetworkConnection;
-protected:
-	virtual void onDisconnected(const std::shared_ptr<NetworkConnection> & connection) = 0;
-	virtual void onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message) = 0;
-
-public:
-	virtual ~INetworkConnectionListener() = default;
-};
-
-class DLL_LINKAGE INetworkServerListener : public INetworkConnectionListener
-{
-	friend class NetworkServer;
-protected:
-	virtual void onNewConnection(const std::shared_ptr<NetworkConnection> &) = 0;
-	virtual void onTimer() = 0;
-
-public:
-	virtual ~INetworkServerListener() = default;
-};
-
-class DLL_LINKAGE INetworkClientListener : public INetworkConnectionListener
-{
-	friend class NetworkClient;
-protected:
-	virtual void onConnectionFailed(const std::string & errorMessage) = 0;
-	virtual void onConnectionEstablished(const std::shared_ptr<NetworkConnection> &) = 0;
-	virtual void onTimer() = 0;
-
-public:
-	virtual ~INetworkClientListener() = default;
-};
-
-
-VCMI_LIB_NAMESPACE_END

+ 8 - 29
lib/network/NetworkServer.cpp

@@ -13,16 +13,15 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-NetworkServer::NetworkServer(INetworkServerListener & listener)
-	:listener(listener)
+NetworkServer::NetworkServer(INetworkServerListener & listener, const std::shared_ptr<NetworkContext> & context)
+	: listener(listener)
+	, io(context)
 {
 }
 
 void NetworkServer::start(uint16_t port)
 {
-	io = std::make_shared<boost::asio::io_service>();
 	acceptor = std::make_shared<NetworkAcceptor>(*io, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port));
-
 	startAsyncAccept();
 }
 
@@ -32,16 +31,6 @@ void NetworkServer::startAsyncAccept()
 	acceptor->async_accept(*upcomingConnection, std::bind(&NetworkServer::connectionAccepted, this, upcomingConnection, _1));
 }
 
-void NetworkServer::run()
-{
-	io->run();
-}
-
-void NetworkServer::run(std::chrono::milliseconds duration)
-{
-	io->run_for(duration);
-}
-
 void NetworkServer::connectionAccepted(std::shared_ptr<NetworkSocket> upcomingConnection, const boost::system::error_code & ec)
 {
 	if(ec)
@@ -50,44 +39,34 @@ void NetworkServer::connectionAccepted(std::shared_ptr<NetworkSocket> upcomingCo
 	}
 
 	logNetwork->info("We got a new connection! :)");
-	auto connection = std::make_shared<NetworkConnection>(upcomingConnection, *this);
+	auto connection = std::make_shared<NetworkConnection>(*this, upcomingConnection);
 	connections.insert(connection);
 	connection->start();
 	listener.onNewConnection(connection);
 	startAsyncAccept();
 }
 
-void NetworkServer::sendPacket(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message)
+void NetworkServer::sendPacket(const std::shared_ptr<INetworkConnection> & connection, const std::vector<uint8_t> & message)
 {
 	connection->sendPacket(message);
 }
 
-void NetworkServer::closeConnection(const std::shared_ptr<NetworkConnection> & connection)
+void NetworkServer::closeConnection(const std::shared_ptr<INetworkConnection> & connection)
 {
 	assert(connections.count(connection));
 	connections.erase(connection);
 }
 
-void NetworkServer::onDisconnected(const std::shared_ptr<NetworkConnection> & connection)
+void NetworkServer::onDisconnected(const std::shared_ptr<INetworkConnection> & connection)
 {
 	assert(connections.count(connection));
 	connections.erase(connection);
 	listener.onDisconnected(connection);
 }
 
-void NetworkServer::onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message)
+void NetworkServer::onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<uint8_t> & message)
 {
 	listener.onPacketReceived(connection, message);
 }
 
-void NetworkServer::setTimer(std::chrono::milliseconds duration)
-{
-	auto timer = std::make_shared<NetworkTimer>(*io, duration);
-	timer->async_wait([this, timer](const boost::system::error_code& error){
-		if (!error)
-			listener.onTimer();
-	});
-}
-
-
 VCMI_LIB_NAMESPACE_END

+ 9 - 15
lib/network/NetworkServer.h

@@ -10,35 +10,29 @@
 #pragma once
 
 #include "NetworkDefines.h"
-#include "NetworkListener.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-class NetworkConnection;
-
-class DLL_LINKAGE NetworkServer : boost::noncopyable, public INetworkConnectionListener
+class NetworkServer : public INetworkConnectionListener, public INetworkServer
 {
-	std::shared_ptr<NetworkService> io;
+	std::shared_ptr<NetworkContext> io;
 	std::shared_ptr<NetworkAcceptor> acceptor;
-	std::set<std::shared_ptr<NetworkConnection>> connections;
+	std::set<std::shared_ptr<INetworkConnection>> connections;
 
 	INetworkServerListener & listener;
 
 	void connectionAccepted(std::shared_ptr<NetworkSocket>, const boost::system::error_code & ec);
 	void startAsyncAccept();
 
-	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 onDisconnected(const std::shared_ptr<INetworkConnection> & connection) override;
+	void onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<uint8_t> & message) override;
 public:
-	explicit NetworkServer(INetworkServerListener & listener);
+	NetworkServer(INetworkServerListener & listener, const std::shared_ptr<NetworkContext> & context);
 
-	void sendPacket(const std::shared_ptr<NetworkConnection> &, const std::vector<uint8_t> & message);
-	void closeConnection(const std::shared_ptr<NetworkConnection> &);
-	void setTimer(std::chrono::milliseconds duration);
+	void sendPacket(const std::shared_ptr<INetworkConnection> &, const std::vector<uint8_t> & message) override;
+	void closeConnection(const std::shared_ptr<INetworkConnection> &) override;
 
-	void start(uint16_t port);
-	void run(std::chrono::milliseconds duration);
-	void run();
+	void start(uint16_t port) override;
 };
 
 VCMI_LIB_NAMESPACE_END

+ 3 - 3
lib/serializer/Connection.cpp

@@ -14,7 +14,7 @@
 #include "BinarySerializer.h"
 
 #include "../networkPacks/NetPacksBase.h"
-#include "../network/NetworkConnection.h"
+#include "../network/NetworkInterface.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -55,7 +55,7 @@ int ConnectionPackReader::read(void * data, unsigned size)
 	return size;
 }
 
-CConnection::CConnection(std::weak_ptr<NetworkConnection> networkConnection)
+CConnection::CConnection(std::weak_ptr<INetworkConnection> networkConnection)
 	: networkConnection(networkConnection)
 	, packReader(std::make_unique<ConnectionPackReader>())
 	, packWriter(std::make_unique<ConnectionPackWriter>())
@@ -100,7 +100,7 @@ CPack * CConnection::retrievePack(const std::vector<uint8_t> & data)
 	return result;
 }
 
-bool CConnection::isMyConnection(const std::shared_ptr<NetworkConnection> & otherConnection) const
+bool CConnection::isMyConnection(const std::shared_ptr<INetworkConnection> & otherConnection) const
 {
 	return otherConnection != nullptr && networkConnection.lock() == otherConnection;
 }

+ 4 - 4
lib/serializer/Connection.h

@@ -14,7 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 class BinaryDeserializer;
 class BinarySerializer;
 struct CPack;
-class NetworkConnection;
+class INetworkConnection;
 class ConnectionPackReader;
 class ConnectionPackWriter;
 class CGameState;
@@ -24,7 +24,7 @@ class CGameState;
 class DLL_LINKAGE CConnection : boost::noncopyable
 {
 	/// Non-owning pointer to underlying connection
-	std::weak_ptr<NetworkConnection> networkConnection;
+	std::weak_ptr<INetworkConnection> networkConnection;
 
 	std::unique_ptr<ConnectionPackReader> packReader;
 	std::unique_ptr<ConnectionPackWriter> packWriter;
@@ -39,12 +39,12 @@ class DLL_LINKAGE CConnection : boost::noncopyable
 	void enableSmartVectorMemberSerializatoin();
 
 public:
-	bool isMyConnection(const std::shared_ptr<NetworkConnection> & otherConnection) const;
+	bool isMyConnection(const std::shared_ptr<INetworkConnection> & otherConnection) const;
 
 	std::string uuid;
 	int connectionID;
 
-	CConnection(std::weak_ptr<NetworkConnection> networkConnection);
+	CConnection(std::weak_ptr<INetworkConnection> networkConnection);
 	~CConnection();
 
 	void sendPack(const CPack * pack);

+ 3 - 9
lobby/LobbyServer.cpp

@@ -13,8 +13,6 @@
 #include "LobbyDatabase.h"
 
 #include "../lib/JsonNode.h"
-#include "../lib/network/NetworkConnection.h"
-#include "../lib/network/NetworkServer.h"
 
 #include <boost/uuid/uuid_generators.hpp>
 #include <boost/uuid/uuid_io.hpp>
@@ -199,11 +197,6 @@ void LobbyServer::sendChatMessage(const NetworkConnectionPtr & target, const std
 	sendMessage(target, reply);
 }
 
-void LobbyServer::onTimer()
-{
-	// no-op
-}
-
 void LobbyServer::onNewConnection(const NetworkConnectionPtr & connection)
 {
 	// no-op - waiting for incoming data
@@ -544,7 +537,8 @@ LobbyServer::~LobbyServer() = default;
 
 LobbyServer::LobbyServer(const boost::filesystem::path & databasePath)
 	: database(new LobbyDatabase(databasePath))
-	, networkServer(new NetworkServer(*this))
+	, networkHandler(INetworkHandler::createHandler())
+	, networkServer(networkHandler->createServerTCP(*this))
 {
 }
 
@@ -555,5 +549,5 @@ void LobbyServer::start(uint16_t port)
 
 void LobbyServer::run()
 {
-	networkServer->run();
+	networkHandler->run();
 }

+ 6 - 6
lobby/LobbyServer.h

@@ -9,7 +9,7 @@
  */
 #pragma once
 
-#include "../lib/network/NetworkListener.h"
+#include "../lib/network/NetworkInterface.h"
 #include "LobbyDefines.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -35,12 +35,12 @@ class LobbyServer : public INetworkServerListener
 	{
 		std::string accountID;
 		std::string roomID;
-		std::weak_ptr<NetworkConnection> accountConnection;
-		std::weak_ptr<NetworkConnection> roomConnection;
+		std::weak_ptr<INetworkConnection> accountConnection;
+		std::weak_ptr<INetworkConnection> roomConnection;
 	};
 
 	/// list of connected proxies. All messages received from (key) will be redirected to (value) connection
-	std::map<NetworkConnectionPtr, std::weak_ptr<NetworkConnection>> activeProxies;
+	std::map<NetworkConnectionPtr, std::weak_ptr<INetworkConnection>> activeProxies;
 
 	/// list of half-established proxies from server that are still waiting for client to connect
 	std::vector<AwaitingProxyState> awaitingProxies;
@@ -52,7 +52,8 @@ class LobbyServer : public INetworkServerListener
 	std::map<NetworkConnectionPtr, GameRoomState> activeGameRooms;
 
 	std::unique_ptr<LobbyDatabase> database;
-	std::unique_ptr<NetworkServer> networkServer;
+	std::unique_ptr<INetworkHandler> networkHandler;
+	std::unique_ptr<INetworkServer> networkServer;
 
 	std::string sanitizeChatMessage(const std::string & inputString) const;
 	bool isAccountNameValid(const std::string & accountName);
@@ -63,7 +64,6 @@ class LobbyServer : public INetworkServerListener
 	void onNewConnection(const NetworkConnectionPtr & connection) override;
 	void onDisconnected(const NetworkConnectionPtr & connection) override;
 	void onPacketReceived(const NetworkConnectionPtr & connection, const std::vector<uint8_t> & message) override;
-	void onTimer() override;
 
 	void sendMessage(const NetworkConnectionPtr & target, const JsonNode & json);
 

+ 12 - 12
server/CVCMIServer.cpp

@@ -36,8 +36,6 @@
 #include "CGameHandler.h"
 #include "processors/PlayerMessageProcessor.h"
 #include "../lib/mapping/CMapInfo.h"
-#include "../lib/network/NetworkServer.h"
-#include "../lib/network/NetworkClient.h"
 #include "../lib/GameConstants.h"
 #include "../lib/logging/CBasicLogConfigurator.h"
 #include "../lib/CConfigHandler.h"
@@ -164,14 +162,15 @@ CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts)
 		port = cmdLineOptions["port"].as<uint16_t>();
 	logNetwork->info("Port %d will be used", port);
 
-	networkServer = std::make_unique<NetworkServer>(*this);
+	networkHandler = INetworkHandler::createHandler();
+	networkServer = networkHandler->createServerTCP(*this);
 	networkServer->start(port);
 	logNetwork->info("Listening for connections at port %d", port);
 }
 
 CVCMIServer::~CVCMIServer() = default;
 
-void CVCMIServer::onNewConnection(const std::shared_ptr<NetworkConnection> & connection)
+void CVCMIServer::onNewConnection(const std::shared_ptr<INetworkConnection> & connection)
 {
 	if (activeConnections.empty())
 		establishOutgoingConnection();
@@ -187,7 +186,7 @@ void CVCMIServer::onNewConnection(const std::shared_ptr<NetworkConnection> & con
 	}
 }
 
-void CVCMIServer::onPacketReceived(const std::shared_ptr<NetworkConnection> & connection, const std::vector<uint8_t> & message)
+void CVCMIServer::onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<uint8_t> & message)
 {
 	std::shared_ptr<CConnection> c = findConnection(connection);
 	auto pack = c->retrievePack(message);
@@ -201,7 +200,7 @@ void CVCMIServer::onConnectionFailed(const std::string & errorMessage)
 	//TODO: handle failure to connect to lobby
 }
 
-void CVCMIServer::onConnectionEstablished(const std::shared_ptr<NetworkConnection> &)
+void CVCMIServer::onConnectionEstablished(const std::shared_ptr<INetworkConnection> &)
 {
 	//TODO: handle connection to lobby - login?
 }
@@ -216,7 +215,7 @@ EServerState CVCMIServer::getState() const
 	return state;
 }
 
-std::shared_ptr<CConnection> CVCMIServer::findConnection(const std::shared_ptr<NetworkConnection> & netConnection)
+std::shared_ptr<CConnection> CVCMIServer::findConnection(const std::shared_ptr<INetworkConnection> & netConnection)
 {
 	for (auto const & gameConnection : activeConnections)
 	{
@@ -236,7 +235,7 @@ void CVCMIServer::run()
 		vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "onServerReady");
 	}
 #endif
-	networkServer->run();
+	networkHandler->run();
 }
 
 void CVCMIServer::onTimer()
@@ -258,7 +257,7 @@ void CVCMIServer::onTimer()
 
 	if (msDelta.count())
 		gh->tick(msDelta.count());
-	networkServer->setTimer(serverUpdateInterval);
+	networkHandler->createTimer(*this, serverUpdateInterval);
 }
 
 void CVCMIServer::establishOutgoingConnection()
@@ -269,7 +268,7 @@ void CVCMIServer::establishOutgoingConnection()
 	std::string hostname = settings["lobby"]["hostname"].String();
 	int16_t port = settings["lobby"]["port"].Integer();
 
-	outgoingConnection = std::make_unique<NetworkClient>(*this);
+	outgoingConnection = networkHandler->createClientTCP(*this);
 	outgoingConnection->start(hostname, port);
 }
 
@@ -370,7 +369,7 @@ void CVCMIServer::startGameImmediately()
 	onTimer();
 }
 
-void CVCMIServer::onDisconnected(const std::shared_ptr<NetworkConnection> & connection)
+void CVCMIServer::onDisconnected(const std::shared_ptr<INetworkConnection> & connection)
 {
 	logNetwork->error("Network error receiving a pack. Connection has been closed");
 
@@ -998,7 +997,8 @@ static void handleCommandOptions(int argc, const char * argv[], boost::program_o
 	("help,h", "display help and exit")
 	("version,v", "display version information and exit")
 	("run-by-client", "indicate that server launched by client on same machine")
-	("port", po::value<ui16>(), "port at which server will listen to connections from client");
+	("port", po::value<ui16>(), "port at which server will listen to connections from client")
+	("lobby", "start server in lobby mode in which server connects to a global lobby");
 
 	if(argc > 1)
 	{

+ 11 - 9
server/CVCMIServer.h

@@ -9,7 +9,7 @@
  */
 #pragma once
 
-#include "../lib/network/NetworkListener.h"
+#include "../lib/network/NetworkInterface.h"
 #include "../lib/StartInfo.h"
 
 #include <boost/program_options/variables_map.hpp>
@@ -47,13 +47,15 @@ enum class EServerState : ui8
 	SHUTDOWN
 };
 
-class CVCMIServer : public LobbyInfo, public INetworkServerListener, public INetworkClientListener
+class CVCMIServer : public LobbyInfo, public INetworkServerListener, public INetworkClientListener, public INetworkTimerListener
 {
+	std::unique_ptr<INetworkHandler> networkHandler;
+
 	/// Network server instance that receives and processes incoming connections on active socket
-	std::unique_ptr<NetworkServer> networkServer;
+	std::unique_ptr<INetworkServer> networkServer;
 
 	/// Outgoing connection established by this server to game lobby for proxy mode (only in lobby game)
-	std::unique_ptr<NetworkClient> outgoingConnection;
+	std::unique_ptr<INetworkClient> outgoingConnection;
 
 	std::chrono::steady_clock::time_point gameplayStartTime;
 	std::chrono::steady_clock::time_point lastTimerUpdateTime;
@@ -70,16 +72,16 @@ private:
 	EServerState state;
 
 	// 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;
+	void onDisconnected(const std::shared_ptr<INetworkConnection> & connection) override;
+	void onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<uint8_t> & message) override;
+	void onNewConnection(const std::shared_ptr<INetworkConnection> &) override;
 	void onConnectionFailed(const std::string & errorMessage) override;
-	void onConnectionEstablished(const std::shared_ptr<NetworkConnection> &) override;
+	void onConnectionEstablished(const std::shared_ptr<INetworkConnection> &) override;
 	void onTimer() override;
 
 	void establishOutgoingConnection();
 
-	std::shared_ptr<CConnection> findConnection(const std::shared_ptr<NetworkConnection> &);
+	std::shared_ptr<CConnection> findConnection(const std::shared_ptr<INetworkConnection> &);
 
 	int currentClientId;
 	ui8 currentPlayerId;