Explorar el Código

Merge pull request #4253 from smanolloff/random-port

Bind VCMI server to a random TCP port
Ivan Savenko hace 1 año
padre
commit
696cce7f7f

+ 2 - 2
client/CServerHandler.cpp

@@ -238,9 +238,9 @@ void CServerHandler::startLocalServerAndConnect(bool connectToLobby)
 	si->difficulty = lastDifficulty.Integer();
 
 	logNetwork->trace("\tStarting local server");
-	serverRunner->start(getLocalPort(), connectToLobby, si);
+	uint16_t srvport = serverRunner->start(getLocalPort(), connectToLobby, si);
 	logNetwork->trace("\tConnecting to local server");
-	connectToServer(getLocalHostname(), getLocalPort());
+	connectToServer(getLocalHostname(), srvport);
 	logNetwork->trace("\tWaiting for connection");
 }
 

+ 19 - 4
client/ServerRunner.cpp

@@ -20,22 +20,35 @@
 #include <boost/process/io.hpp>
 #endif
 
+#include <future>
+
 ServerThreadRunner::ServerThreadRunner() = default;
 ServerThreadRunner::~ServerThreadRunner() = default;
 
-void ServerThreadRunner::start(uint16_t port, bool connectToLobby, std::shared_ptr<StartInfo> startingInfo)
+uint16_t ServerThreadRunner::start(uint16_t cfgport, bool connectToLobby, std::shared_ptr<StartInfo> startingInfo)
 {
-	server = std::make_unique<CVCMIServer>(port, connectToLobby, true);
+	// cfgport may be 0 -- the real port is returned after calling prepare()
+	server = std::make_unique<CVCMIServer>(cfgport, true);
 
 	if (startingInfo)
 	{
 		server->si = startingInfo; //Else use default
 	}
 
-	threadRunLocalServer = boost::thread([this]{
+	std::promise<uint16_t> promise;
+
+	threadRunLocalServer = boost::thread([this, connectToLobby, &promise]{
 		setThreadName("runServer");
+		uint16_t port = server->prepare(connectToLobby);
+		promise.set_value(port);
 		server->run();
 	});
+
+	logNetwork->trace("Waiting for server port...");
+	auto srvport = promise.get_future().get();
+	logNetwork->debug("Server port: %d", srvport);
+
+	return srvport;
 }
 
 void ServerThreadRunner::shutdown()
@@ -73,7 +86,7 @@ int ServerProcessRunner::exitCode()
 	return child->exit_code();
 }
 
-void ServerProcessRunner::start(uint16_t port, bool connectToLobby, std::shared_ptr<StartInfo> startingInfo)
+uint16_t ServerProcessRunner::start(uint16_t port, bool connectToLobby, std::shared_ptr<StartInfo> startingInfo)
 {
 	boost::filesystem::path serverPath = VCMIDirs::get().serverPath();
 	boost::filesystem::path logPath = VCMIDirs::get().userLogsPath() / "server_log.txt";
@@ -88,6 +101,8 @@ void ServerProcessRunner::start(uint16_t port, bool connectToLobby, std::shared_
 
 	if (ec)
 		throw std::runtime_error("Failed to start server! Reason: " + ec.message());
+
+	return port;
 }
 
 #endif

+ 3 - 3
client/ServerRunner.h

@@ -20,7 +20,7 @@ class CVCMIServer;
 class IServerRunner
 {
 public:
-	virtual void start(uint16_t port, bool connectToLobby, std::shared_ptr<StartInfo> startingInfo) = 0;
+	virtual uint16_t start(uint16_t port, bool connectToLobby, std::shared_ptr<StartInfo> startingInfo) = 0;
 	virtual void shutdown() = 0;
 	virtual void wait() = 0;
 	virtual int exitCode() = 0;
@@ -34,7 +34,7 @@ class ServerThreadRunner : public IServerRunner, boost::noncopyable
 	std::unique_ptr<CVCMIServer> server;
 	boost::thread threadRunLocalServer;
 public:
-	void start(uint16_t port, bool connectToLobby, std::shared_ptr<StartInfo> startingInfo) override;
+	uint16_t start(uint16_t port, bool connectToLobby, std::shared_ptr<StartInfo> startingInfo) override;
 	void shutdown() override;
 	void wait() override;
 	int exitCode() override;
@@ -56,7 +56,7 @@ class ServerProcessRunner : public IServerRunner, boost::noncopyable
 	std::unique_ptr<boost::process::child> child;
 
 public:
-	void start(uint16_t port, bool connectToLobby, std::shared_ptr<StartInfo> startingInfo) override;
+	uint16_t start(uint16_t port, bool connectToLobby, std::shared_ptr<StartInfo> startingInfo) override;
 	void shutdown() override;
 	void wait() override;
 	int exitCode() override;

+ 1 - 1
lib/network/NetworkInterface.h

@@ -40,7 +40,7 @@ class DLL_LINKAGE INetworkServer : boost::noncopyable
 public:
 	virtual ~INetworkServer() = default;
 
-	virtual void start(uint16_t port) = 0;
+	virtual uint16_t start(uint16_t port) = 0;
 };
 
 /// Base interface that must be implemented by user of networking API to handle any connection callbacks

+ 4 - 3
lib/network/NetworkServer.cpp

@@ -19,16 +19,17 @@ NetworkServer::NetworkServer(INetworkServerListener & listener, const std::share
 {
 }
 
-void NetworkServer::start(uint16_t port)
+uint16_t NetworkServer::start(uint16_t port)
 {
 	acceptor = std::make_shared<NetworkAcceptor>(*io, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port));
-	startAsyncAccept();
+	return startAsyncAccept();
 }
 
-void NetworkServer::startAsyncAccept()
+uint16_t NetworkServer::startAsyncAccept()
 {
 	auto upcomingConnection = std::make_shared<NetworkSocket>(*io);
 	acceptor->async_accept(*upcomingConnection, [this, upcomingConnection](const auto & ec) { connectionAccepted(upcomingConnection, ec); });
+	return acceptor->local_endpoint().port();
 }
 
 void NetworkServer::connectionAccepted(std::shared_ptr<NetworkSocket> upcomingConnection, const boost::system::error_code & ec)

+ 2 - 2
lib/network/NetworkServer.h

@@ -22,14 +22,14 @@ class NetworkServer : public INetworkConnectionListener, public INetworkServer
 	INetworkServerListener & listener;
 
 	void connectionAccepted(std::shared_ptr<NetworkSocket>, const boost::system::error_code & ec);
-	void startAsyncAccept();
+	uint16_t startAsyncAccept();
 
 	void onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage) override;
 	void onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<std::byte> & message) override;
 public:
 	NetworkServer(INetworkServerListener & listener, const std::shared_ptr<NetworkContext> & context);
 
-	void start(uint16_t port) override;
+	uint16_t start(uint16_t port) override;
 };
 
 VCMI_LIB_NAMESPACE_END

+ 18 - 10
server/CVCMIServer.cpp

@@ -118,7 +118,7 @@ public:
 	}
 };
 
-CVCMIServer::CVCMIServer(uint16_t port, bool connectToLobby, bool runByClient)
+CVCMIServer::CVCMIServer(uint16_t port, bool runByClient)
 	: currentClientId(1)
 	, currentPlayerId(1)
 	, port(port)
@@ -130,22 +130,30 @@ CVCMIServer::CVCMIServer(uint16_t port, bool connectToLobby, bool runByClient)
 	registerTypesLobbyPacks(*applier);
 
 	networkHandler = INetworkHandler::createHandler();
-
-	if(connectToLobby)
-		lobbyProcessor = std::make_unique<GlobalLobbyProcessor>(*this);
-	else
-		startAcceptingIncomingConnections();
 }
 
 CVCMIServer::~CVCMIServer() = default;
 
-void CVCMIServer::startAcceptingIncomingConnections()
+uint16_t CVCMIServer::prepare(bool connectToLobby) {
+	if(connectToLobby) {
+		lobbyProcessor = std::make_unique<GlobalLobbyProcessor>(*this);
+		return 0;
+	} else {
+		return startAcceptingIncomingConnections();
+	}
+}
+
+uint16_t CVCMIServer::startAcceptingIncomingConnections()
 {
-	logNetwork->info("Port %d will be used", port);
+	port
+		? logNetwork->info("Port %d will be used", port)
+		: logNetwork->info("Randomly assigned port will be used");
 
+	// config port may be 0 => srvport will contain the OS-assigned port value
 	networkServer = networkHandler->createServerTCP(*this);
-	networkServer->start(port);
-	logNetwork->info("Listening for connections at port %d", port);
+	auto srvport = networkServer->start(port);
+	logNetwork->info("Listening for connections at port %d", srvport);
+	return srvport;
 }
 
 void CVCMIServer::onNewConnection(const std::shared_ptr<INetworkConnection> & connection)

+ 4 - 2
server/CVCMIServer.h

@@ -66,6 +66,8 @@ public:
 	/// List of all active connections
 	std::vector<std::shared_ptr<CConnection>> activeConnections;
 
+	uint16_t prepare(bool connectToLobby);
+
 	// INetworkListener impl
 	void onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage) override;
 	void onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<std::byte> & message) override;
@@ -74,7 +76,7 @@ public:
 
 	std::shared_ptr<CGameHandler> gh;
 
-	CVCMIServer(uint16_t port, bool connectToLobby, bool runByClient);
+	CVCMIServer(uint16_t port, bool runByClient);
 	~CVCMIServer();
 
 	void run();
@@ -83,7 +85,7 @@ public:
 	bool prepareToStartGame();
 	void prepareToRestart();
 	void startGameImmediately();
-	void startAcceptingIncomingConnections();
+	uint16_t startAcceptingIncomingConnections();
 
 	void threadHandleClient(std::shared_ptr<CConnection> c);
 

+ 4 - 3
serverapp/EntryPoint.cpp

@@ -15,6 +15,7 @@
 #include "../lib/logging/CBasicLogConfigurator.h"
 #include "../lib/VCMIDirs.h"
 #include "../lib/VCMI_Lib.h"
+#include "../lib/CConfigHandler.h"
 
 #include <boost/program_options.hpp>
 
@@ -86,12 +87,12 @@ int main(int argc, const char * argv[])
 	{
 		bool connectToLobby = opts.count("lobby");
 		bool runByClient = opts.count("runByClient");
-		uint16_t port = 3030;
+		uint16_t port = settings["server"]["localPort"].Integer();
 		if(opts.count("port"))
 			port = opts["port"].as<uint16_t>();
 
-		CVCMIServer server(port, connectToLobby, runByClient);
-
+		CVCMIServer server(port, runByClient);
+		server.prepare(connectToLobby);
 		server.run();
 
 		// CVCMIServer destructor must be called here - before VLC cleanup