aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/servers/httpasio.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenhttp/servers/httpasio.cpp')
-rw-r--r--src/zenhttp/servers/httpasio.cpp98
1 files changed, 63 insertions, 35 deletions
diff --git a/src/zenhttp/servers/httpasio.cpp b/src/zenhttp/servers/httpasio.cpp
index e148072c8..3970dea12 100644
--- a/src/zenhttp/servers/httpasio.cpp
+++ b/src/zenhttp/servers/httpasio.cpp
@@ -161,7 +161,7 @@ public:
~HttpAsioServerImpl();
void Initialize(std::filesystem::path DataDir);
- int Start(uint16_t Port, bool ForceLooopback, int ThreadCount);
+ int Start(uint16_t Port, const AsioConfig& Config);
void Stop();
void RegisterService(const char* UrlPath, HttpService& Service);
HttpService* RouteRequest(std::string_view Url);
@@ -717,7 +717,7 @@ HttpServerConnection::HandleRequest()
struct HttpAcceptor
{
- HttpAcceptor(HttpAsioServerImpl& Server, asio::io_service& IoService, uint16_t BasePort, bool ForceLoopback)
+ HttpAcceptor(HttpAsioServerImpl& Server, asio::io_service& IoService, uint16_t BasePort, bool ForceLoopback, bool AllowPortProbing)
: m_Server(Server)
, m_IoService(IoService)
, m_Acceptor(m_IoService, asio::ip::tcp::v6())
@@ -751,13 +751,13 @@ struct HttpAcceptor
if (IsUsingIPv6)
{
- BoundBaseUrl = BindAcceptor<asio::ip::address_v6>(BasePort, ForceLoopback);
+ BoundBaseUrl = BindAcceptor<asio::ip::address_v6>(BasePort, ForceLoopback, AllowPortProbing);
}
else
{
ZEN_INFO("NOTE: ipv6 support is disabled, binding to ipv4 only");
- BoundBaseUrl = BindAcceptor<asio::ip::address_v4>(BasePort, ForceLoopback);
+ BoundBaseUrl = BindAcceptor<asio::ip::address_v4>(BasePort, ForceLoopback, AllowPortProbing);
}
if (!IsValid())
@@ -816,7 +816,7 @@ struct HttpAcceptor
}
template<typename AddressType>
- std::string BindAcceptor(uint16_t BasePort, bool ForceLoopback)
+ std::string BindAcceptor(uint16_t BasePort, bool ForceLoopback, bool AllowPortProbing)
{
uint16_t EffectivePort = BasePort;
@@ -858,27 +858,40 @@ struct HttpAcceptor
if (BindErrorCode == asio::error::address_in_use)
{
ZEN_INFO("Desired port {} is in use (error: '{}'), retrying", EffectivePort, BindErrorCode.message());
- Sleep(100);
+ Sleep(500);
m_Acceptor.bind(asio::ip::tcp::endpoint(BindAddress, EffectivePort), BindErrorCode);
}
- // Try some alternative ports
- for (uint16_t PortOffset = 1; BindErrorCode && (PortOffset < 10); ++PortOffset)
+ if (AllowPortProbing)
{
- EffectivePort = BasePort + (PortOffset * 100);
- m_Acceptor.bind(asio::ip::tcp::endpoint(BindAddress, EffectivePort), BindErrorCode);
- }
+ // Try some alternative ports
+ for (uint16_t PortOffset = 1; BindErrorCode && (PortOffset < 10); ++PortOffset)
+ {
+ EffectivePort = BasePort + (PortOffset * 100);
+ m_Acceptor.bind(asio::ip::tcp::endpoint(BindAddress, EffectivePort), BindErrorCode);
+ }
- if (BindErrorCode)
- {
- ZEN_INFO("Unable to bind to preferred port range, falling back to automatic assignment (error: '{}')", BindErrorCode.message());
+ if (BindErrorCode)
+ {
+ ZEN_INFO("Unable to bind to preferred port range, falling back to automatic assignment (error: '{}')",
+ BindErrorCode.message());
- EffectivePort = 0;
- m_Acceptor.bind(asio::ip::tcp::endpoint(BindAddress, EffectivePort), BindErrorCode);
+ EffectivePort = 0;
+ m_Acceptor.bind(asio::ip::tcp::endpoint(BindAddress, EffectivePort), BindErrorCode);
- if (!BindErrorCode)
+ if (!BindErrorCode)
+ {
+ EffectivePort = m_Acceptor.local_endpoint().port();
+ }
+ }
+ }
+ else
+ {
+ for (uint32_t Retries = 0; (BindErrorCode == asio::error::address_in_use) && (Retries < 3); Retries++)
{
- EffectivePort = m_Acceptor.local_endpoint().port();
+ ZEN_INFO("Desired port {} is in use (error: '{}'), retrying", EffectivePort, BindErrorCode.message());
+ Sleep(500);
+ m_Acceptor.bind(asio::ip::tcp::endpoint(BindAddress, EffectivePort), BindErrorCode);
}
}
@@ -1155,15 +1168,16 @@ HttpAsioServerImpl::Initialize(std::filesystem::path DataDir)
}
int
-HttpAsioServerImpl::Start(uint16_t Port, bool ForceLooopback, int ThreadCount)
+HttpAsioServerImpl::Start(uint16_t Port, const AsioConfig& Config)
{
ZEN_MEMSCOPE(GetHttpasioTag());
- ZEN_ASSERT(ThreadCount > 0);
+ ZEN_ASSERT(Config.ThreadCount > 0);
- ZEN_INFO("starting asio http with {} service threads", ThreadCount);
+ ZEN_INFO("starting asio http with {} service threads", Config.ThreadCount);
- m_Acceptor.reset(new asio_http::HttpAcceptor(*this, m_IoService, Port, ForceLooopback));
+ m_Acceptor.reset(
+ new asio_http::HttpAcceptor(*this, m_IoService, Port, Config.ForceLoopback, /*AllowPortProbing */ !Config.IsDedicatedServer));
if (!m_Acceptor->IsValid())
{
@@ -1181,7 +1195,7 @@ HttpAsioServerImpl::Start(uint16_t Port, bool ForceLooopback, int ThreadCount)
// from making progress. Or at the very least, thread priorities should
// be considered.
- for (int i = 0; i < ThreadCount; ++i)
+ for (unsigned int i = 0; i < Config.ThreadCount; ++i)
{
m_ThreadPool.emplace_back([this, Index = i + 1] {
ZEN_MEMSCOPE(GetHttpasioTag());
@@ -1203,7 +1217,10 @@ HttpAsioServerImpl::Start(uint16_t Port, bool ForceLooopback, int ThreadCount)
});
}
- ZEN_INFO("asio http started (port {})", m_Acceptor->GetAcceptPort());
+ ZEN_INFO("asio http started in {} mode, using {} threads on port {}",
+ Config.IsDedicatedServer ? "DEDICATED" : "NORMAL",
+ Config.ThreadCount,
+ m_Acceptor->GetAcceptPort());
return m_Acceptor->GetAcceptPort();
}
@@ -1278,7 +1295,7 @@ namespace zen {
class HttpAsioServer : public HttpServer
{
public:
- HttpAsioServer(bool ForceLoopback, unsigned int ThreadCount);
+ HttpAsioServer(const AsioConfig& Config);
~HttpAsioServer();
virtual void RegisterService(HttpService& Service) override;
@@ -1288,17 +1305,15 @@ public:
virtual void Close() override;
private:
- Event m_ShutdownEvent;
- int m_BasePort = 0;
- bool m_ForceLoopback = false;
- unsigned int m_ThreadCount = 0;
+ Event m_ShutdownEvent;
+ int m_BasePort = 0;
+ const AsioConfig m_InitialConfig;
std::unique_ptr<asio_http::HttpAsioServerImpl> m_Impl;
};
-HttpAsioServer::HttpAsioServer(bool ForceLoopback, unsigned int ThreadCount)
-: m_ForceLoopback(ForceLoopback)
-, m_ThreadCount(ThreadCount != 0 ? ThreadCount : Max(GetHardwareConcurrency(), 8u))
+HttpAsioServer::HttpAsioServer(const AsioConfig& Config)
+: m_InitialConfig(Config)
, m_Impl(std::make_unique<asio_http::HttpAsioServerImpl>())
{
ZEN_DEBUG("Request object size: {} ({:#x})", sizeof(HttpRequestParser), sizeof(HttpRequestParser));
@@ -1338,7 +1353,20 @@ HttpAsioServer::Initialize(int BasePort, std::filesystem::path DataDir)
ZEN_TRACE_CPU("HttpAsioServer::Initialize");
m_Impl->Initialize(DataDir);
- m_BasePort = m_Impl->Start(gsl::narrow<uint16_t>(BasePort), m_ForceLoopback, m_ThreadCount);
+ AsioConfig Config = m_InitialConfig;
+
+ Config.ThreadCount = m_InitialConfig.ThreadCount != 0 ? m_InitialConfig.ThreadCount : Max(GetHardwareConcurrency(), 8u);
+
+ if (Config.IsDedicatedServer && m_InitialConfig.ThreadCount == 0)
+ {
+ // In order to limit the potential impact of threads stuck
+ // in locks we allow the thread pool to be oversubscribed
+ // by a fair amount
+
+ Config.ThreadCount *= 2;
+ }
+
+ m_BasePort = m_Impl->Start(gsl::narrow<uint16_t>(BasePort), Config);
return m_BasePort;
}
@@ -1394,12 +1422,12 @@ HttpAsioServer::RequestExit()
}
Ref<HttpServer>
-CreateHttpAsioServer(bool ForceLoopback, unsigned int ThreadCount)
+CreateHttpAsioServer(const AsioConfig& Config)
{
ZEN_TRACE_CPU("CreateHttpAsioServer");
ZEN_MEMSCOPE(GetHttpasioTag());
- return Ref<HttpServer>{new HttpAsioServer(ForceLoopback, ThreadCount)};
+ return Ref<HttpServer>{new HttpAsioServer(Config)};
}
} // namespace zen