From 80e960bc8ec690a0bbb800f0482d208221831edf Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 12 Jan 2024 01:10:41 +0200 Subject: [PATCH] Finalized new TCP networking API --- client/CServerHandler.cpp | 18 ++-- client/CServerHandler.h | 13 +-- client/globalLobby/GlobalLobbyClient.cpp | 28 ++---- client/globalLobby/GlobalLobbyClient.h | 14 ++- client/gui/InterfaceObjectConfigurable.cpp | 7 +- cmake_modules/VCMI_lib.cmake | 4 +- lib/network/NetworkClient.cpp | 37 ++------ lib/network/NetworkClient.h | 22 ++--- lib/network/NetworkConnection.cpp | 2 +- lib/network/NetworkConnection.h | 7 +- lib/network/NetworkDefines.h | 4 +- lib/network/NetworkHandler.cpp | 57 +++++++++++ lib/network/NetworkHandler.h | 31 ++++++ lib/network/NetworkInterface.h | 104 +++++++++++++++++++++ lib/network/NetworkListener.h | 56 ----------- lib/network/NetworkServer.cpp | 37 ++------ lib/network/NetworkServer.h | 24 ++--- lib/serializer/Connection.cpp | 6 +- lib/serializer/Connection.h | 8 +- lobby/LobbyServer.cpp | 12 +-- lobby/LobbyServer.h | 12 +-- server/CVCMIServer.cpp | 24 ++--- server/CVCMIServer.h | 20 ++-- 23 files changed, 306 insertions(+), 241 deletions(-) create mode 100644 lib/network/NetworkHandler.cpp create mode 100644 lib/network/NetworkHandler.h create mode 100644 lib/network/NetworkInterface.h delete mode 100644 lib/network/NetworkListener.h diff --git a/client/CServerHandler.cpp b/client/CServerHandler.cpp index 8983c9db1..a592ba61d 100644 --- a/client/CServerHandler.cpp +++ b/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(*this)) + , networkHandler(INetworkHandler::createHandler()) + , networkClient(networkHandler->createClientTCP(*this)) , applier(std::make_unique>()) - , lobbyClient(std::make_unique()) + , lobbyClient(std::make_unique(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 & netConnection) +void CServerHandler::onConnectionEstablished(const std::shared_ptr & netConnection) { logNetwork->info("Connection established"); c = std::make_shared(netConnection); @@ -852,7 +852,7 @@ public: } }; -void CServerHandler::onPacketReceived(const std::shared_ptr &, const std::vector & message) +void CServerHandler::onPacketReceived(const std::shared_ptr &, const std::vector & message) { CPack * pack = c->retrievePack(message); if(state == EClientState::DISCONNECTING) @@ -868,7 +868,7 @@ void CServerHandler::onPacketReceived(const std::shared_ptr & } } -void CServerHandler::onDisconnected(const std::shared_ptr &) +void CServerHandler::onDisconnected(const std::shared_ptr &) { if(state == EClientState::DISCONNECTING) { diff --git a/client/CServerHandler.h b/client/CServerHandler.h index 2d0ea27b3..7b761d2cc 100644 --- a/client/CServerHandler.h +++ b/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; + std::unique_ptr networkHandler; + std::unique_ptr networkClient; std::unique_ptr lobbyClient; std::unique_ptr> applier; std::shared_ptr 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 &, const std::vector & message) override; + void onPacketReceived(const std::shared_ptr &, const std::vector & message) override; void onConnectionFailed(const std::string & errorMessage) override; - void onConnectionEstablished(const std::shared_ptr &) override; - void onDisconnected(const std::shared_ptr &) override; + void onConnectionEstablished(const std::shared_ptr &) override; + void onDisconnected(const std::shared_ptr &) override; void onTimer() override; void applyPackOnLobbyScreen(CPackForLobby & pack); diff --git a/client/globalLobby/GlobalLobbyClient.cpp b/client/globalLobby/GlobalLobbyClient.cpp index a6af74c60..491d8f4e1 100644 --- a/client/globalLobby/GlobalLobbyClient.cpp +++ b/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(*this)) -{ - networkThread = std::make_unique([this](){ - networkClient->run(); - }); -} +GlobalLobbyClient::GlobalLobbyClient(const std::unique_ptr & 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 &, const std::vector & message) +void GlobalLobbyClient::onPacketReceived(const std::shared_ptr &, const std::vector & 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 &) +void GlobalLobbyClient::onConnectionEstablished(const std::shared_ptr &) { JsonNode toSend; @@ -198,17 +189,12 @@ void GlobalLobbyClient::onConnectionFailed(const std::string & errorMessage) loginWindowPtr->onConnectionFailed(errorMessage); } -void GlobalLobbyClient::onDisconnected(const std::shared_ptr &) +void GlobalLobbyClient::onDisconnected(const std::shared_ptr &) { 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); diff --git a/client/globalLobby/GlobalLobbyClient.h b/client/globalLobby/GlobalLobbyClient.h index 335c4dc3e..92569c3dd 100644 --- a/client/globalLobby/GlobalLobbyClient.h +++ b/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 networkThread; - std::unique_ptr networkClient; + std::unique_ptr networkClient; std::weak_ptr loginWindow; std::weak_ptr lobbyWindow; std::shared_ptr lobbyWindowLock; // helper strong reference to prevent window destruction on closing - void onPacketReceived(const std::shared_ptr &, const std::vector & message) override; + void onPacketReceived(const std::shared_ptr &, const std::vector & message) override; void onConnectionFailed(const std::string & errorMessage) override; - void onConnectionEstablished(const std::shared_ptr &) override; - void onDisconnected(const std::shared_ptr &) override; - void onTimer() override; + void onConnectionEstablished(const std::shared_ptr &) override; + void onDisconnected(const std::shared_ptr &) 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 & handler); ~GlobalLobbyClient(); void sendMessage(const JsonNode & data); diff --git a/client/gui/InterfaceObjectConfigurable.cpp b/client/gui/InterfaceObjectConfigurable.cpp index beb9a55d4..b12bb75b1 100644 --- a/client/gui/InterfaceObjectConfigurable.cpp +++ b/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) diff --git a/cmake_modules/VCMI_lib.cmake b/cmake_modules/VCMI_lib.cmake index 6ad35ac43..65549110c 100644 --- a/cmake_modules/VCMI_lib.cmake +++ b/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 diff --git a/lib/network/NetworkClient.cpp b/lib/network/NetworkClient.cpp index 25462cf01..888660b3d 100644 --- a/lib/network/NetworkClient.cpp +++ b/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 & context) + : io(context) + , socket(std::make_shared(*context)) , listener(listener) { } @@ -39,54 +39,29 @@ void NetworkClient::onConnected(const boost::system::error_code & ec) return; } - connection = std::make_shared(socket, *this); + connection = std::make_shared(*this, socket); connection->start(); listener.onConnectionEstablished(connection); } -void NetworkClient::run() -{ - boost::asio::executor_work_guardget_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(*io, duration); - timer->async_wait([this, timer](const boost::system::error_code& error){ - if (!error) - listener.onTimer(); - }); -} - void NetworkClient::sendPacket(const std::vector & message) { connection->sendPacket(message); } -void NetworkClient::onDisconnected(const std::shared_ptr & connection) +void NetworkClient::onDisconnected(const std::shared_ptr & connection) { this->connection.reset(); listener.onDisconnected(connection); } -void NetworkClient::onPacketReceived(const std::shared_ptr & connection, const std::vector & message) +void NetworkClient::onPacketReceived(const std::shared_ptr & connection, const std::vector & message) { listener.onPacketReceived(connection, message); } diff --git a/lib/network/NetworkClient.h b/lib/network/NetworkClient.h index cc244aa50..301d3d00d 100644 --- a/lib/network/NetworkClient.h +++ b/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 io; + std::shared_ptr io; std::shared_ptr socket; std::shared_ptr 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 & connection) override; - void onPacketReceived(const std::shared_ptr & connection, const std::vector & message) override; + void onDisconnected(const std::shared_ptr & connection) override; + void onPacketReceived(const std::shared_ptr & connection, const std::vector & message) override; public: - NetworkClient(INetworkClientListener & listener); - virtual ~NetworkClient() = default; + NetworkClient(INetworkClientListener & listener, const std::shared_ptr & context); - bool isConnected() const; + bool isConnected() const override; - void setTimer(std::chrono::milliseconds duration); - void sendPacket(const std::vector & message); + void sendPacket(const std::vector & 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 diff --git a/lib/network/NetworkConnection.cpp b/lib/network/NetworkConnection.cpp index 7c068147b..b2fce0160 100644 --- a/lib/network/NetworkConnection.cpp +++ b/lib/network/NetworkConnection.cpp @@ -12,7 +12,7 @@ VCMI_LIB_NAMESPACE_BEGIN -NetworkConnection::NetworkConnection(const std::shared_ptr & socket, INetworkConnectionListener & listener) +NetworkConnection::NetworkConnection(INetworkConnectionListener & listener, const std::shared_ptr & socket) : socket(socket) , listener(listener) { diff --git a/lib/network/NetworkConnection.h b/lib/network/NetworkConnection.h index ab315c7c5..afdc7d967 100644 --- a/lib/network/NetworkConnection.h +++ b/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, boost::noncopyable +class NetworkConnection : public INetworkConnection, public std::enable_shared_from_this { 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 & socket, INetworkConnectionListener & listener); + NetworkConnection(INetworkConnectionListener & listener, const std::shared_ptr & socket); void start(); - void sendPacket(const std::vector & message); + void sendPacket(const std::vector & message) override; }; VCMI_LIB_NAMESPACE_END diff --git a/lib/network/NetworkDefines.h b/lib/network/NetworkDefines.h index 0dce17821..6b86ff23a 100644 --- a/lib/network/NetworkDefines.h +++ b/lib/network/NetworkDefines.h @@ -11,9 +11,11 @@ #include +#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; diff --git a/lib/network/NetworkHandler.cpp b/lib/network/NetworkHandler.cpp new file mode 100644 index 000000000..ed5503f73 --- /dev/null +++ b/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::createHandler() +{ + return std::make_unique(); +} + +NetworkHandler::NetworkHandler() + : io(std::make_shared()) +{} + +std::unique_ptr NetworkHandler::createServerTCP(INetworkServerListener & listener) +{ + return std::make_unique(listener, io); +} + +std::unique_ptr NetworkHandler::createClientTCP(INetworkClientListener & listener) +{ + return std::make_unique(listener, io); +} + +void NetworkHandler::run() +{ + boost::asio::executor_work_guardget_executor())> work{io->get_executor()}; + io->run(); +} + +void NetworkHandler::createTimer(INetworkTimerListener & listener, std::chrono::milliseconds duration) +{ + auto timer = std::make_shared(*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 diff --git a/lib/network/NetworkHandler.h b/lib/network/NetworkHandler.h new file mode 100644 index 000000000..d41933869 --- /dev/null +++ b/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 io; + +public: + NetworkHandler(); + + std::unique_ptr createServerTCP(INetworkServerListener & listener) override; + std::unique_ptr createClientTCP(INetworkClientListener & listener) override; + void createTimer(INetworkTimerListener & listener, std::chrono::milliseconds duration) override; + + void run() override; + void stop() override; +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/network/NetworkInterface.h b/lib/network/NetworkInterface.h new file mode 100644 index 000000000..4d3072992 --- /dev/null +++ b/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 & message) = 0; +}; + +using NetworkConnectionPtr = std::shared_ptr; +using NetworkConnectionWeakPtr = std::weak_ptr; + +/// 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 & 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 &, const std::vector & message) = 0; + virtual void closeConnection(const std::shared_ptr &) = 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 & connection) = 0; + virtual void onPacketReceived(const std::shared_ptr & connection, const std::vector & 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 &) = 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 &) = 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 createHandler(); + + /// Creates an instance of TCP server that allows to receiving connections on a local port + virtual std::unique_ptr 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 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 diff --git a/lib/network/NetworkListener.h b/lib/network/NetworkListener.h deleted file mode 100644 index f1ee7885d..000000000 --- a/lib/network/NetworkListener.h +++ /dev/null @@ -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; -using NetworkConnectionWeakPtr = std::weak_ptr; - -class DLL_LINKAGE INetworkConnectionListener -{ - friend class NetworkConnection; -protected: - virtual void onDisconnected(const std::shared_ptr & connection) = 0; - virtual void onPacketReceived(const std::shared_ptr & connection, const std::vector & message) = 0; - -public: - virtual ~INetworkConnectionListener() = default; -}; - -class DLL_LINKAGE INetworkServerListener : public INetworkConnectionListener -{ - friend class NetworkServer; -protected: - virtual void onNewConnection(const std::shared_ptr &) = 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 &) = 0; - virtual void onTimer() = 0; - -public: - virtual ~INetworkClientListener() = default; -}; - - -VCMI_LIB_NAMESPACE_END diff --git a/lib/network/NetworkServer.cpp b/lib/network/NetworkServer.cpp index e96cae41e..546d0b652 100644 --- a/lib/network/NetworkServer.cpp +++ b/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 & context) + : listener(listener) + , io(context) { } void NetworkServer::start(uint16_t port) { - io = std::make_shared(); acceptor = std::make_shared(*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 upcomingConnection, const boost::system::error_code & ec) { if(ec) @@ -50,44 +39,34 @@ void NetworkServer::connectionAccepted(std::shared_ptr upcomingCo } logNetwork->info("We got a new connection! :)"); - auto connection = std::make_shared(upcomingConnection, *this); + auto connection = std::make_shared(*this, upcomingConnection); connections.insert(connection); connection->start(); listener.onNewConnection(connection); startAsyncAccept(); } -void NetworkServer::sendPacket(const std::shared_ptr & connection, const std::vector & message) +void NetworkServer::sendPacket(const std::shared_ptr & connection, const std::vector & message) { connection->sendPacket(message); } -void NetworkServer::closeConnection(const std::shared_ptr & connection) +void NetworkServer::closeConnection(const std::shared_ptr & connection) { assert(connections.count(connection)); connections.erase(connection); } -void NetworkServer::onDisconnected(const std::shared_ptr & connection) +void NetworkServer::onDisconnected(const std::shared_ptr & connection) { assert(connections.count(connection)); connections.erase(connection); listener.onDisconnected(connection); } -void NetworkServer::onPacketReceived(const std::shared_ptr & connection, const std::vector & message) +void NetworkServer::onPacketReceived(const std::shared_ptr & connection, const std::vector & message) { listener.onPacketReceived(connection, message); } -void NetworkServer::setTimer(std::chrono::milliseconds duration) -{ - auto timer = std::make_shared(*io, duration); - timer->async_wait([this, timer](const boost::system::error_code& error){ - if (!error) - listener.onTimer(); - }); -} - - VCMI_LIB_NAMESPACE_END diff --git a/lib/network/NetworkServer.h b/lib/network/NetworkServer.h index 363032ee1..4c1c57aa2 100644 --- a/lib/network/NetworkServer.h +++ b/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 io; + std::shared_ptr io; std::shared_ptr acceptor; - std::set> connections; + std::set> connections; INetworkServerListener & listener; void connectionAccepted(std::shared_ptr, const boost::system::error_code & ec); void startAsyncAccept(); - void onDisconnected(const std::shared_ptr & connection) override; - void onPacketReceived(const std::shared_ptr & connection, const std::vector & message) override; + void onDisconnected(const std::shared_ptr & connection) override; + void onPacketReceived(const std::shared_ptr & connection, const std::vector & message) override; public: - explicit NetworkServer(INetworkServerListener & listener); + NetworkServer(INetworkServerListener & listener, const std::shared_ptr & context); - void sendPacket(const std::shared_ptr &, const std::vector & message); - void closeConnection(const std::shared_ptr &); - void setTimer(std::chrono::milliseconds duration); + void sendPacket(const std::shared_ptr &, const std::vector & message) override; + void closeConnection(const std::shared_ptr &) override; - void start(uint16_t port); - void run(std::chrono::milliseconds duration); - void run(); + void start(uint16_t port) override; }; VCMI_LIB_NAMESPACE_END diff --git a/lib/serializer/Connection.cpp b/lib/serializer/Connection.cpp index ad0dfd852..8005e947c 100644 --- a/lib/serializer/Connection.cpp +++ b/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) +CConnection::CConnection(std::weak_ptr networkConnection) : networkConnection(networkConnection) , packReader(std::make_unique()) , packWriter(std::make_unique()) @@ -100,7 +100,7 @@ CPack * CConnection::retrievePack(const std::vector & data) return result; } -bool CConnection::isMyConnection(const std::shared_ptr & otherConnection) const +bool CConnection::isMyConnection(const std::shared_ptr & otherConnection) const { return otherConnection != nullptr && networkConnection.lock() == otherConnection; } diff --git a/lib/serializer/Connection.h b/lib/serializer/Connection.h index 7d5f307b7..5c739b955 100644 --- a/lib/serializer/Connection.h +++ b/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; + std::weak_ptr networkConnection; std::unique_ptr packReader; std::unique_ptr packWriter; @@ -39,12 +39,12 @@ class DLL_LINKAGE CConnection : boost::noncopyable void enableSmartVectorMemberSerializatoin(); public: - bool isMyConnection(const std::shared_ptr & otherConnection) const; + bool isMyConnection(const std::shared_ptr & otherConnection) const; std::string uuid; int connectionID; - CConnection(std::weak_ptr networkConnection); + CConnection(std::weak_ptr networkConnection); ~CConnection(); void sendPack(const CPack * pack); diff --git a/lobby/LobbyServer.cpp b/lobby/LobbyServer.cpp index 52c8f5e49..6f079e41f 100644 --- a/lobby/LobbyServer.cpp +++ b/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 #include @@ -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(); } diff --git a/lobby/LobbyServer.h b/lobby/LobbyServer.h index a7215f806..640cad245 100644 --- a/lobby/LobbyServer.h +++ b/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 accountConnection; - std::weak_ptr roomConnection; + std::weak_ptr accountConnection; + std::weak_ptr roomConnection; }; /// list of connected proxies. All messages received from (key) will be redirected to (value) connection - std::map> activeProxies; + std::map> activeProxies; /// list of half-established proxies from server that are still waiting for client to connect std::vector awaitingProxies; @@ -52,7 +52,8 @@ class LobbyServer : public INetworkServerListener std::map activeGameRooms; std::unique_ptr database; - std::unique_ptr networkServer; + std::unique_ptr networkHandler; + std::unique_ptr 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 & message) override; - void onTimer() override; void sendMessage(const NetworkConnectionPtr & target, const JsonNode & json); diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index bb677deae..b9e3ee66d 100644 --- a/server/CVCMIServer.cpp +++ b/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(); logNetwork->info("Port %d will be used", port); - networkServer = std::make_unique(*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 & connection) +void CVCMIServer::onNewConnection(const std::shared_ptr & connection) { if (activeConnections.empty()) establishOutgoingConnection(); @@ -187,7 +186,7 @@ void CVCMIServer::onNewConnection(const std::shared_ptr & con } } -void CVCMIServer::onPacketReceived(const std::shared_ptr & connection, const std::vector & message) +void CVCMIServer::onPacketReceived(const std::shared_ptr & connection, const std::vector & message) { std::shared_ptr 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 &) +void CVCMIServer::onConnectionEstablished(const std::shared_ptr &) { //TODO: handle connection to lobby - login? } @@ -216,7 +215,7 @@ EServerState CVCMIServer::getState() const return state; } -std::shared_ptr CVCMIServer::findConnection(const std::shared_ptr & netConnection) +std::shared_ptr CVCMIServer::findConnection(const std::shared_ptr & 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(*this); + outgoingConnection = networkHandler->createClientTCP(*this); outgoingConnection->start(hostname, port); } @@ -370,7 +369,7 @@ void CVCMIServer::startGameImmediately() onTimer(); } -void CVCMIServer::onDisconnected(const std::shared_ptr & connection) +void CVCMIServer::onDisconnected(const std::shared_ptr & 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(), "port at which server will listen to connections from client"); + ("port", po::value(), "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) { diff --git a/server/CVCMIServer.h b/server/CVCMIServer.h index 030e44e81..346d135d7 100644 --- a/server/CVCMIServer.h +++ b/server/CVCMIServer.h @@ -9,7 +9,7 @@ */ #pragma once -#include "../lib/network/NetworkListener.h" +#include "../lib/network/NetworkInterface.h" #include "../lib/StartInfo.h" #include @@ -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 networkHandler; + /// Network server instance that receives and processes incoming connections on active socket - std::unique_ptr networkServer; + std::unique_ptr networkServer; /// Outgoing connection established by this server to game lobby for proxy mode (only in lobby game) - std::unique_ptr outgoingConnection; + std::unique_ptr 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 & connection) override; - void onPacketReceived(const std::shared_ptr & connection, const std::vector & message) override; - void onNewConnection(const std::shared_ptr &) override; + void onDisconnected(const std::shared_ptr & connection) override; + void onPacketReceived(const std::shared_ptr & connection, const std::vector & message) override; + void onNewConnection(const std::shared_ptr &) override; void onConnectionFailed(const std::string & errorMessage) override; - void onConnectionEstablished(const std::shared_ptr &) override; + void onConnectionEstablished(const std::shared_ptr &) override; void onTimer() override; void establishOutgoingConnection(); - std::shared_ptr findConnection(const std::shared_ptr &); + std::shared_ptr findConnection(const std::shared_ptr &); int currentClientId; ui8 currentPlayerId;