aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPer Larsson <[email protected]>2022-02-21 15:00:02 +0100
committerPer Larsson <[email protected]>2022-02-21 15:00:02 +0100
commit41782efc63d7f88525596d6724a1bb86d6fdcfa4 (patch)
tree80567b8cc256c361abb8f81b53680f2fa6ec6fcc
parentRefactored websocket message. (diff)
downloadzen-41782efc63d7f88525596d6724a1bb86d6fdcfa4.tar.xz
zen-41782efc63d7f88525596d6724a1bb86d6fdcfa4.zip
Added option to enable websockets.
-rw-r--r--zenhttp/include/zenhttp/websocket.h8
-rw-r--r--zenhttp/websocketasio.cpp51
-rw-r--r--zenserver-test/zenserver-test.cpp2
-rw-r--r--zenserver/config.cpp14
-rw-r--r--zenserver/config.h24
-rw-r--r--zenserver/zenserver.cpp20
6 files changed, 75 insertions, 44 deletions
diff --git a/zenhttp/include/zenhttp/websocket.h b/zenhttp/include/zenhttp/websocket.h
index 336d98b42..a514e6002 100644
--- a/zenhttp/include/zenhttp/websocket.h
+++ b/zenhttp/include/zenhttp/websocket.h
@@ -139,7 +139,7 @@ private:
*/
struct WebSocketServerOptions
{
- uint16_t Port = 8848;
+ uint16_t Port = 2337;
uint32_t ThreadCount = 1;
};
@@ -151,8 +151,8 @@ class WebSocketServer
public:
virtual ~WebSocketServer() = default;
- virtual bool Run(const WebSocketServerOptions& Options) = 0;
- virtual void Shutdown() = 0;
+ virtual bool Run() = 0;
+ virtual void Shutdown() = 0;
virtual void RegisterService(WebSocketService& Service) = 0;
virtual void RegisterNotificationHandler(std::string_view Key, WebSocketService& Service) = 0;
@@ -161,7 +161,7 @@ public:
virtual void SendNotification(WebSocketMessage&& Notification) = 0;
virtual void SendResponse(WebSocketMessage&& Response) = 0;
- static std::unique_ptr<WebSocketServer> Create();
+ static std::unique_ptr<WebSocketServer> Create(const WebSocketServerOptions& Options);
};
/**
diff --git a/zenhttp/websocketasio.cpp b/zenhttp/websocketasio.cpp
index 13d0177ee..c2ce7ca64 100644
--- a/zenhttp/websocketasio.cpp
+++ b/zenhttp/websocketasio.cpp
@@ -582,10 +582,10 @@ WsThreadPool::Stop()
class WsServer final : public WebSocketServer
{
public:
- WsServer() = default;
+ WsServer(const WebSocketServerOptions& Options) : m_Options(Options) {}
virtual ~WsServer() { Shutdown(); }
- virtual bool Run(const WebSocketServerOptions& Options) override;
+ virtual bool Run() override;
virtual void Shutdown() override;
virtual void RegisterService(WebSocketService& Service) override;
@@ -614,6 +614,7 @@ private:
using RequestHandlerMap = std::unordered_map<std::string_view, WebSocketService*>;
using NotificationHandlerMap = std::unordered_map<std::string_view, std::vector<WebSocketService*>>;
+ WebSocketServerOptions m_Options;
asio::io_service m_IoSvc;
std::unique_ptr<asio::ip::tcp::acceptor> m_Acceptor;
std::unique_ptr<WsThreadPool> m_ThreadPool;
@@ -634,7 +635,7 @@ WsServer::RegisterService(WebSocketService& Service)
}
bool
-WsServer::Run(const WebSocketServerOptions& Options)
+WsServer::Run()
{
m_Acceptor = std::make_unique<asio::ip::tcp::acceptor>(m_IoSvc, asio::ip::tcp::v6());
@@ -645,7 +646,7 @@ WsServer::Run(const WebSocketServerOptions& Options)
m_Acceptor->set_option(asio::socket_base::send_buffer_size(256 * 1024));
asio::error_code Ec;
- m_Acceptor->bind(asio::ip::tcp::endpoint(asio::ip::address_v6::any(), Options.Port), Ec);
+ m_Acceptor->bind(asio::ip::tcp::endpoint(asio::ip::address_v6::any(), m_Options.Port), Ec);
if (Ec)
{
@@ -657,12 +658,12 @@ WsServer::Run(const WebSocketServerOptions& Options)
m_Acceptor->listen();
m_Running = true;
- ZEN_LOG_INFO(LogWebSocket, "web socket server running on port '{}'", Options.Port);
+ ZEN_LOG_INFO(LogWebSocket, "web socket server running on port '{}'", m_Options.Port);
AcceptConnection();
m_ThreadPool = std::make_unique<WsThreadPool>(m_IoSvc);
- m_ThreadPool->Start(Options.ThreadCount);
+ m_ThreadPool->Start(m_Options.ThreadCount);
return true;
}
@@ -720,29 +721,29 @@ WsServer::AcceptConnection()
asio::ip::tcp::socket& SocketRef = *Socket.get();
m_Acceptor->async_accept(SocketRef, [this, ConnectedSocket = std::move(Socket)](const asio::error_code& Ec) mutable {
- if (Ec)
- {
- ZEN_LOG_WARN(LogWebSocket, "accept connection FAILED, reason '{}'", Ec.message());
- }
- else
+ if (m_Running)
{
- auto Connection = std::make_shared<WsConnection>(WebSocketId::New(), std::move(ConnectedSocket));
-
- ZEN_LOG_DEBUG(LogWebSocket, "accept connection '#{} {}' OK", Connection->Id().Value(), Connection->RemoteAddr());
-
+ if (Ec)
{
- std::unique_lock _(m_ConnMutex);
- m_Connections[Connection->Id()] = Connection;
+ ZEN_LOG_WARN(LogWebSocket, "accept connection FAILED, reason '{}'", Ec.message());
}
+ else
+ {
+ auto Connection = std::make_shared<WsConnection>(WebSocketId::New(), std::move(ConnectedSocket));
- Connection->SetParser(std::make_unique<HttpMessageParser>(HttpMessageParserType::kRequest));
- Connection->SetState(WebSocketState::kHandshaking);
+ ZEN_LOG_DEBUG(LogWebSocket, "accept connection '#{} {}' OK", Connection->Id().Value(), Connection->RemoteAddr());
- ReadMessage(Connection);
- }
+ {
+ std::unique_lock _(m_ConnMutex);
+ m_Connections[Connection->Id()] = Connection;
+ }
+
+ Connection->SetParser(std::make_unique<HttpMessageParser>(HttpMessageParserType::kRequest));
+ Connection->SetState(WebSocketState::kHandshaking);
+
+ ReadMessage(Connection);
+ }
- if (m_Running)
- {
AcceptConnection();
}
});
@@ -1522,9 +1523,9 @@ WebSocketService::Configure(WebSocketServer& Server)
}
std::unique_ptr<WebSocketServer>
-WebSocketServer::Create()
+WebSocketServer::Create(const WebSocketServerOptions& Options)
{
- return std::make_unique<websocket::WsServer>();
+ return std::make_unique<websocket::WsServer>(Options);
}
std::shared_ptr<WebSocketClient>
diff --git a/zenserver-test/zenserver-test.cpp b/zenserver-test/zenserver-test.cpp
index 78829a2d1..aac43f43a 100644
--- a/zenserver-test/zenserver-test.cpp
+++ b/zenserver-test/zenserver-test.cpp
@@ -2089,7 +2089,7 @@ TEST_CASE("websocket.basic")
ZenServerInstance Inst(TestEnv);
Inst.SetTestDir(TestDir);
- Inst.SpawnServer(PortNumber);
+ Inst.SpawnServer(PortNumber, "--websocket-port=8848"sv);
Inst.WaitUntilReady();
asio::io_context IoCtx;
diff --git a/zenserver/config.cpp b/zenserver/config.cpp
index cb6d5ea6d..bcacc16c0 100644
--- a/zenserver/config.cpp
+++ b/zenserver/config.cpp
@@ -193,6 +193,20 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
cxxopts::value<int>(ServerOptions.BasePort)->default_value("1337"),
"<port number>");
+ options.add_option("network",
+ "",
+ "websocket-port",
+ "Websocket server port",
+ cxxopts::value<int>(ServerOptions.WebSocketPort)->default_value("0"),
+ "<port number>");
+
+ options.add_option("network",
+ "",
+ "websocket-threads",
+ "Number of websocket I/O thread(s) (0 == hardware concurrency)",
+ cxxopts::value<int>(ServerOptions.WebSocketThreads)->default_value("0"),
+ "");
+
#if ZEN_ENABLE_MESH
options.add_option("network",
"m",
diff --git a/zenserver/config.h b/zenserver/config.h
index 69e65498c..fd569bdb1 100644
--- a/zenserver/config.h
+++ b/zenserver/config.h
@@ -87,17 +87,19 @@ struct ZenServerOptions
{
ZenUpstreamCacheConfig UpstreamCacheConfig;
ZenGcConfig GcConfig;
- std::filesystem::path DataDir; // Root directory for state (used for testing)
- std::filesystem::path ContentDir; // Root directory for serving frontend content (experimental)
- std::filesystem::path AbsLogFile; // Absolute path to main log file
- std::filesystem::path ConfigFile; // Path to Lua config file
- std::string ChildId; // Id assigned by parent process (used for lifetime management)
- std::string LogId; // Id for tagging log output
- std::string HttpServerClass; // Choice of HTTP server implementation
- std::string EncryptionKey; // 256 bit AES encryption key
- std::string EncryptionIV; // 128 bit AES initialization vector
- int BasePort = 1337; // Service listen port (used for both UDP and TCP)
- int OwnerPid = 0; // Parent process id (zero for standalone)
+ std::filesystem::path DataDir; // Root directory for state (used for testing)
+ std::filesystem::path ContentDir; // Root directory for serving frontend content (experimental)
+ std::filesystem::path AbsLogFile; // Absolute path to main log file
+ std::filesystem::path ConfigFile; // Path to Lua config file
+ std::string ChildId; // Id assigned by parent process (used for lifetime management)
+ std::string LogId; // Id for tagging log output
+ std::string HttpServerClass; // Choice of HTTP server implementation
+ std::string EncryptionKey; // 256 bit AES encryption key
+ std::string EncryptionIV; // 128 bit AES initialization vector
+ int BasePort = 1337; // Service listen port (used for both UDP and TCP)
+ int OwnerPid = 0; // Parent process id (zero for standalone)
+ int WebSocketPort = 0; // Web socket port (Zero = disabled)
+ int WebSocketThreads = 0;
bool InstallService = false; // Flag used to initiate service install (temporary)
bool UninstallService = false; // Flag used to initiate service uninstall (temporary)
bool IsDebug = false;
diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp
index 08abfdecd..78a62e202 100644
--- a/zenserver/zenserver.cpp
+++ b/zenserver/zenserver.cpp
@@ -205,7 +205,14 @@ public:
m_Http = zen::CreateHttpServer(ServerOptions.HttpServerClass);
int EffectiveBasePort = m_Http->Initialize(ServerOptions.BasePort);
- m_WebSocket = zen::WebSocketServer::Create();
+ if (ServerOptions.WebSocketPort != 0)
+ {
+ const uint32 ThreadCount =
+ ServerOptions.WebSocketThreads > 0 ? uint32_t(ServerOptions.WebSocketThreads) : std::thread::hardware_concurrency();
+
+ m_WebSocket = zen::WebSocketServer::Create(
+ {.Port = gsl::narrow<uint16_t>(ServerOptions.WebSocketPort), .ThreadCount = Max(ThreadCount, uint32_t(16))});
+ }
// Setup authentication manager
{
@@ -305,9 +312,13 @@ public:
m_Http->RegisterService(m_TestService); // NOTE: this is intentionally not limited to test mode as it's useful for diagnostics
m_Http->RegisterService(m_TestingService);
- m_WebSocket->RegisterService(m_TestingService);
m_Http->RegisterService(m_AdminService);
+ if (m_WebSocket)
+ {
+ m_WebSocket->RegisterService(m_TestingService);
+ }
+
if (m_HttpProjectService)
{
m_Http->RegisterService(*m_HttpProjectService);
@@ -400,7 +411,10 @@ public:
OnReady();
- m_WebSocket->Run({.Port = 8848});
+ if (m_WebSocket)
+ {
+ m_WebSocket->Run();
+ }
m_Http->Run(IsInteractiveMode);