aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2023-11-09 20:50:46 +0100
committerGitHub <[email protected]>2023-11-09 20:50:46 +0100
commitc289d408765fe47d54987bd49fcf277f2419104a (patch)
treed76ac1fae0a2413f080c4ecfb0e7f281ed50f271 /src
parent0.2.31-pre1 (diff)
downloadzen-c289d408765fe47d54987bd49fcf277f2419104a.tar.xz
zen-c289d408765fe47d54987bd49fcf277f2419104a.zip
option for zenserver - `--http-forceloopback` (#516)
* New option for zenserver - `--http-forceloopback` which forces opening of the server http server using loopback (local) connection (UE-199776) * add fallback to local connection for asio if we get access denied on public port
Diffstat (limited to 'src')
-rw-r--r--src/zenhttp/httpserver.cpp5
-rw-r--r--src/zenhttp/include/zenhttp/httpserver.h3
-rw-r--r--src/zenhttp/servers/httpasio.cpp47
-rw-r--r--src/zenhttp/servers/httpasio.h2
-rw-r--r--src/zenhttp/servers/httpsys.cpp27
-rw-r--r--src/zenhttp/servers/httpsys.h1
-rw-r--r--src/zenserver/config.cpp12
7 files changed, 67 insertions, 30 deletions
diff --git a/src/zenhttp/httpserver.cpp b/src/zenhttp/httpserver.cpp
index 9c303c62d..fa75060db 100644
--- a/src/zenhttp/httpserver.cpp
+++ b/src/zenhttp/httpserver.cpp
@@ -732,7 +732,7 @@ CreateHttpServerClass(HttpServerClass Class, const HttpServerConfig& Config)
default:
case HttpServerClass::kHttpAsio:
ZEN_INFO("using asio HTTP server implementation");
- return CreateHttpAsioServer(Config.ThreadCount);
+ return CreateHttpAsioServer(Config.ForceLoopback, Config.ThreadCount);
case HttpServerClass::kHttpMulti:
{
@@ -784,7 +784,8 @@ CreateHttpServerClass(HttpServerClass Class, const HttpServerConfig& Config)
.AsyncWorkThreadCount = Config.HttpSys.AsyncWorkThreadCount,
.IsAsyncResponseEnabled = Config.HttpSys.IsAsyncResponseEnabled,
.IsRequestLoggingEnabled = Config.HttpSys.IsRequestLoggingEnabled,
- .IsDedicatedServer = Config.IsDedicatedServer}));
+ .IsDedicatedServer = Config.IsDedicatedServer,
+ .ForceLoopback = Config.ForceLoopback}));
#endif
case HttpServerClass::kHttpNull:
diff --git a/src/zenhttp/include/zenhttp/httpserver.h b/src/zenhttp/include/zenhttp/httpserver.h
index 5d01e380a..eabad4728 100644
--- a/src/zenhttp/include/zenhttp/httpserver.h
+++ b/src/zenhttp/include/zenhttp/httpserver.h
@@ -186,7 +186,8 @@ struct HttpServerConfig
{
bool IsDedicatedServer = false; // Should be set to true for shared servers
std::string ServerClass; // Choice of HTTP server implementation
- unsigned int ThreadCount = 0;
+ bool ForceLoopback = false;
+ unsigned int ThreadCount = 0;
struct
{
diff --git a/src/zenhttp/servers/httpasio.cpp b/src/zenhttp/servers/httpasio.cpp
index 75852fe89..c62aca001 100644
--- a/src/zenhttp/servers/httpasio.cpp
+++ b/src/zenhttp/servers/httpasio.cpp
@@ -62,7 +62,7 @@ public:
HttpAsioServerImpl();
~HttpAsioServerImpl();
- int Start(uint16_t Port, int ThreadCount);
+ int Start(uint16_t Port, bool ForceLooopback, int ThreadCount);
void Stop();
void RegisterService(const char* UrlPath, HttpService& Service);
HttpService* RouteRequest(std::string_view Url);
@@ -569,7 +569,7 @@ HttpServerConnection::HandleRequest()
struct HttpAcceptor
{
- HttpAcceptor(HttpAsioServerImpl& Server, asio::io_service& IoService, uint16_t BasePort)
+ HttpAcceptor(HttpAsioServerImpl& Server, asio::io_service& IoService, uint16_t BasePort, bool ForceLoopback)
: m_Server(Server)
, m_IoService(IoService)
, m_Acceptor(m_IoService, asio::ip::tcp::v6())
@@ -587,25 +587,36 @@ struct HttpAcceptor
m_Acceptor.set_option(asio::socket_base::receive_buffer_size(128 * 1024));
m_Acceptor.set_option(asio::socket_base::send_buffer_size(256 * 1024));
- uint16_t EffectivePort = BasePort;
+ asio::ip::address_v6 BindAddress = ForceLoopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any();
+ uint16_t EffectivePort = BasePort;
asio::error_code BindErrorCode;
- m_Acceptor.bind(asio::ip::tcp::endpoint(asio::ip::address_v6::any(), EffectivePort), BindErrorCode);
+ m_Acceptor.bind(asio::ip::tcp::endpoint(BindAddress, EffectivePort), BindErrorCode);
+ if (BindErrorCode == asio::error::access_denied && !BindAddress.is_loopback())
+ {
+ // Access denied for a public port - lets try fall back to local port only
+ BindAddress = asio::ip::address_v6::loopback();
+ m_Acceptor.bind(asio::ip::tcp::endpoint(BindAddress, EffectivePort), BindErrorCode);
+ }
// Sharing violation implies the port is being used by another process
for (uint16_t PortOffset = 1; (BindErrorCode == asio::error::address_in_use) && (PortOffset < 10); ++PortOffset)
{
EffectivePort = BasePort + (PortOffset * 100);
- m_Acceptor.bind(asio::ip::tcp::endpoint(asio::ip::address_v6::any(), EffectivePort), BindErrorCode);
+ m_Acceptor.bind(asio::ip::tcp::endpoint(BindAddress, EffectivePort), BindErrorCode);
}
if (BindErrorCode == asio::error::access_denied)
{
EffectivePort = 0;
- m_Acceptor.bind(asio::ip::tcp::endpoint(asio::ip::address_v6::any(), EffectivePort), BindErrorCode);
+ m_Acceptor.bind(asio::ip::tcp::endpoint(BindAddress, EffectivePort), BindErrorCode);
}
if (BindErrorCode)
{
ZEN_ERROR("Unable open asio service, error '{}'", BindErrorCode.message());
}
+ else if (BindAddress.is_loopback())
+ {
+ ZEN_INFO("Registered local-only handler 'http://{}:{}/' - this is not accessible from remote hosts", "[::1]", EffectivePort);
+ }
#if ZEN_PLATFORM_WINDOWS
// On Windows, loopback connections can take advantage of a faster code path optionally with this flag.
@@ -627,7 +638,7 @@ struct HttpAcceptor
#endif
m_Acceptor.listen();
- ZEN_INFO("Started asio server at port '{}'", EffectivePort);
+ ZEN_INFO("Started asio server at 'http://{}:{}'", BindAddress.is_loopback() ? "[::1]" : "*", EffectivePort);
}
void Start()
@@ -831,13 +842,13 @@ HttpAsioServerImpl::~HttpAsioServerImpl()
}
int
-HttpAsioServerImpl::Start(uint16_t Port, int ThreadCount)
+HttpAsioServerImpl::Start(uint16_t Port, bool ForceLooopback, int ThreadCount)
{
ZEN_ASSERT(ThreadCount > 0);
ZEN_INFO("starting asio http with {} service threads", ThreadCount);
- m_Acceptor.reset(new asio_http::HttpAcceptor(*this, m_IoService, Port));
+ m_Acceptor.reset(new asio_http::HttpAcceptor(*this, m_IoService, Port, ForceLooopback));
m_Acceptor->Start();
// This should consist of a set of minimum threads and grow on demand to
@@ -926,7 +937,7 @@ namespace zen {
class HttpAsioServer : public HttpServer
{
public:
- HttpAsioServer(unsigned int ThreadCount);
+ HttpAsioServer(bool ForceLoopback, unsigned int ThreadCount);
~HttpAsioServer();
virtual void RegisterService(HttpService& Service) override;
@@ -937,14 +948,16 @@ public:
private:
Event m_ShutdownEvent;
- int m_BasePort = 0;
- unsigned int m_ThreadCount = 0;
+ int m_BasePort = 0;
+ bool m_ForceLoopback = false;
+ unsigned int m_ThreadCount = 0;
std::unique_ptr<asio_http::HttpAsioServerImpl> m_Impl;
};
-HttpAsioServer::HttpAsioServer(unsigned int ThreadCount)
-: m_ThreadCount(ThreadCount != 0 ? ThreadCount : Max(std::thread::hardware_concurrency(), 8u))
+HttpAsioServer::HttpAsioServer(bool ForceLoopback, unsigned int ThreadCount)
+: m_ForceLoopback(ForceLoopback)
+, m_ThreadCount(ThreadCount != 0 ? ThreadCount : Max(std::thread::hardware_concurrency(), 8u))
, m_Impl(std::make_unique<asio_http::HttpAsioServerImpl>())
{
ZEN_DEBUG("Request object size: {} ({:#x})", sizeof(HttpRequestParser), sizeof(HttpRequestParser));
@@ -981,7 +994,7 @@ HttpAsioServer::RegisterService(HttpService& Service)
int
HttpAsioServer::Initialize(int BasePort)
{
- m_BasePort = m_Impl->Start(gsl::narrow<uint16_t>(BasePort), m_ThreadCount);
+ m_BasePort = m_Impl->Start(gsl::narrow<uint16_t>(BasePort), m_ForceLoopback, m_ThreadCount);
return m_BasePort;
}
@@ -1036,9 +1049,9 @@ HttpAsioServer::RequestExit()
}
Ref<HttpServer>
-CreateHttpAsioServer(unsigned int ThreadCount)
+CreateHttpAsioServer(bool ForceLoopback, unsigned int ThreadCount)
{
- return Ref<HttpServer>{new HttpAsioServer(ThreadCount)};
+ return Ref<HttpServer>{new HttpAsioServer(ForceLoopback, ThreadCount)};
}
} // namespace zen
diff --git a/src/zenhttp/servers/httpasio.h b/src/zenhttp/servers/httpasio.h
index 2366f3437..36f988a65 100644
--- a/src/zenhttp/servers/httpasio.h
+++ b/src/zenhttp/servers/httpasio.h
@@ -6,6 +6,6 @@
namespace zen {
-Ref<HttpServer> CreateHttpAsioServer(unsigned int ThreadCount);
+Ref<HttpServer> CreateHttpAsioServer(bool ForceLoopback, unsigned int ThreadCount);
} // namespace zen
diff --git a/src/zenhttp/servers/httpsys.cpp b/src/zenhttp/servers/httpsys.cpp
index 4eeab6662..0b11d396b 100644
--- a/src/zenhttp/servers/httpsys.cpp
+++ b/src/zenhttp/servers/httpsys.cpp
@@ -1003,18 +1003,27 @@ HttpSysServer::InitializeServer(int BasePort)
int EffectivePort = BasePort;
- Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, WildcardUrlPath.c_str(), HTTP_URL_CONTEXT(0), 0);
-
- if ((Result == ERROR_SHARING_VIOLATION) && AllowPortProbing)
+ if (m_InitialConfig.ForceLoopback)
+ {
+ // Force trigger of opening using local port
+ ZEN_ASSERT(AllowLocalOnly);
+ Result = ERROR_ACCESS_DENIED;
+ }
+ else
{
- // Sharing violation implies the port is being used by another process
- for (int PortOffset = 1; (Result == ERROR_SHARING_VIOLATION) && (PortOffset < 10); ++PortOffset)
+ Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, WildcardUrlPath.c_str(), HTTP_URL_CONTEXT(0), 0);
+
+ if ((Result == ERROR_SHARING_VIOLATION) && AllowPortProbing)
{
- EffectivePort = BasePort + (PortOffset * 100);
- WildcardUrlPath.Reset();
- WildcardUrlPath << u8"http://*:"sv << int64_t(EffectivePort) << u8"/"sv;
+ // Sharing violation implies the port is being used by another process
+ for (int PortOffset = 1; (Result == ERROR_SHARING_VIOLATION) && (PortOffset < 10); ++PortOffset)
+ {
+ EffectivePort = BasePort + (PortOffset * 100);
+ WildcardUrlPath.Reset();
+ WildcardUrlPath << u8"http://*:"sv << int64_t(EffectivePort) << u8"/"sv;
- Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, WildcardUrlPath.c_str(), HTTP_URL_CONTEXT(0), 0);
+ Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, WildcardUrlPath.c_str(), HTTP_URL_CONTEXT(0), 0);
+ }
}
}
diff --git a/src/zenhttp/servers/httpsys.h b/src/zenhttp/servers/httpsys.h
index 6a6b16525..b2fe7475b 100644
--- a/src/zenhttp/servers/httpsys.h
+++ b/src/zenhttp/servers/httpsys.h
@@ -21,6 +21,7 @@ struct HttpSysConfig
bool IsAsyncResponseEnabled = true;
bool IsRequestLoggingEnabled = false;
bool IsDedicatedServer = false;
+ bool ForceLoopback = false;
};
Ref<HttpServer> CreateHttpSysServer(HttpSysConfig Config);
diff --git a/src/zenserver/config.cpp b/src/zenserver/config.cpp
index 8fe4213cb..08ba6dc95 100644
--- a/src/zenserver/config.cpp
+++ b/src/zenserver/config.cpp
@@ -99,6 +99,10 @@ ValidateOptions(ZenServerOptions& ServerOptions)
throw zen::OptionParseException("Invalid AES initialization vector");
}
}
+ if (ServerOptions.HttpServerConfig.ForceLoopback && ServerOptions.IsDedicated)
+ {
+ throw zen::OptionParseException("Dedicated server can not be used with forced local server address");
+ }
}
UpstreamCachePolicy
@@ -788,6 +792,7 @@ ParseConfigFile(const std::filesystem::path& Path,
LuaOptions.AddOption("network.httpserverclass"sv, ServerOptions.HttpServerConfig.ServerClass, "http"sv);
LuaOptions.AddOption("network.httpserverthreads"sv, ServerOptions.HttpServerConfig.ThreadCount, "http-threads"sv);
LuaOptions.AddOption("network.port"sv, ServerOptions.BasePort, "port"sv);
+ LuaOptions.AddOption("network.forceloopback"sv, ServerOptions.HttpServerConfig.ForceLoopback, "http-forceloopback"sv);
LuaOptions.AddOption("network.httpsys.async.workthreads"sv,
ServerOptions.HttpServerConfig.HttpSys.AsyncWorkThreadCount,
@@ -1031,6 +1036,13 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
cxxopts::value<int>(ServerOptions.BasePort)->default_value("8558"),
"<port number>");
+ options.add_option("network",
+ "",
+ "http-forceloopback",
+ "Force using local loopback interface",
+ cxxopts::value<bool>(ServerOptions.HttpServerConfig.ForceLoopback)->default_value("false"),
+ "<http forceloopback>");
+
options.add_option("httpsys",
"",
"httpsys-async-work-threads",