aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/config
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenserver/config')
-rw-r--r--src/zenserver/config/config.cpp216
-rw-r--r--src/zenserver/config/config.h32
2 files changed, 229 insertions, 19 deletions
diff --git a/src/zenserver/config/config.cpp b/src/zenserver/config/config.cpp
index e36352dae..2a89fc637 100644
--- a/src/zenserver/config/config.cpp
+++ b/src/zenserver/config/config.cpp
@@ -12,12 +12,16 @@
#include <zencore/compactbinaryutil.h>
#include <zencore/compactbinaryvalidation.h>
#include <zencore/except.h>
+#include <zencore/filesystem.h>
#include <zencore/fmtutils.h>
#include <zencore/iobuffer.h>
#include <zencore/logging.h>
#include <zencore/string.h>
#include <zenutil/config/commandlineoptions.h>
#include <zenutil/config/environmentoptions.h>
+#include <zenutil/consoletui.h>
+
+#include <charconv>
ZEN_THIRD_PARTY_INCLUDES_START
#include <fmt/format.h>
@@ -130,6 +134,7 @@ ZenServerConfiguratorBase::AddCommonConfigOptions(LuaConfig::Options& LuaOptions
// server
LuaOptions.AddOption("server.dedicated"sv, ServerOptions.IsDedicated, "dedicated"sv);
+ LuaOptions.AddOption("server.allowportprobing"sv, ServerOptions.AllowPortProbing, "allow-port-probing"sv);
LuaOptions.AddOption("server.sentry.disable"sv, ServerOptions.SentryConfig.Disable, "no-sentry"sv);
LuaOptions.AddOption("server.sentry.allowpersonalinfo"sv, ServerOptions.SentryConfig.AllowPII, "sentry-allow-personal-info"sv);
LuaOptions.AddOption("server.sentry.dsn"sv, ServerOptions.SentryConfig.Dsn, "sentry-dsn"sv);
@@ -144,10 +149,16 @@ ZenServerConfiguratorBase::AddCommonConfigOptions(LuaConfig::Options& LuaOptions
////// network
+ LuaOptions.AddOption("network.httpclientbackend"sv, ServerOptions.HttpClient.Backend, "httpclient"sv);
LuaOptions.AddOption("network.httpserverclass"sv, ServerOptions.HttpConfig.ServerClass, "http"sv);
LuaOptions.AddOption("network.httpserverthreads"sv, ServerOptions.HttpConfig.ThreadCount, "http-threads"sv);
LuaOptions.AddOption("network.port"sv, ServerOptions.BasePort, "port"sv);
LuaOptions.AddOption("network.forceloopback"sv, ServerOptions.HttpConfig.ForceLoopback, "http-forceloopback"sv);
+ LuaOptions.AddOption("network.unixsocket"sv, ServerOptions.HttpConfig.UnixSocketPath, "unix-socket"sv);
+ LuaOptions.AddOption("network.nonetwork"sv, ServerOptions.HttpConfig.NoNetwork, "no-network"sv);
+ LuaOptions.AddOption("network.https.port"sv, ServerOptions.HttpConfig.HttpsPort, "https-port"sv);
+ LuaOptions.AddOption("network.https.certfile"sv, ServerOptions.HttpConfig.CertFile, "cert-file"sv);
+ LuaOptions.AddOption("network.https.keyfile"sv, ServerOptions.HttpConfig.KeyFile, "key-file"sv);
#if ZEN_WITH_HTTPSYS
LuaOptions.AddOption("network.httpsys.async.workthreads"sv,
@@ -159,6 +170,10 @@ ZenServerConfiguratorBase::AddCommonConfigOptions(LuaConfig::Options& LuaOptions
LuaOptions.AddOption("network.httpsys.requestlogging"sv,
ServerOptions.HttpConfig.HttpSys.IsRequestLoggingEnabled,
"httpsys-enable-request-logging"sv);
+ LuaOptions.AddOption("network.httpsys.httpsport"sv, ServerOptions.HttpConfig.HttpSys.HttpsPort, "httpsys-https-port"sv);
+ LuaOptions.AddOption("network.httpsys.certthumbprint"sv, ServerOptions.HttpConfig.HttpSys.CertThumbprint, "httpsys-cert-thumbprint"sv);
+ LuaOptions.AddOption("network.httpsys.certstorename"sv, ServerOptions.HttpConfig.HttpSys.CertStoreName, "httpsys-cert-store"sv);
+ LuaOptions.AddOption("network.httpsys.httpsonly"sv, ServerOptions.HttpConfig.HttpSys.HttpsOnly, "httpsys-https-only"sv);
#endif
#if ZEN_WITH_TRACE
@@ -188,6 +203,8 @@ struct ZenServerCmdLineOptions
std::string DataDir;
std::string BaseSnapshotDir;
std::string SecurityConfigPath;
+ std::string UnixSocketPath;
+ std::string PortStr;
ZenLoggingCmdLineOptions LoggingOptions;
@@ -208,8 +225,11 @@ ZenServerCmdLineOptions::AddCliOptions(cxxopts::Options& options, ZenServerConfi
#endif
options.add_options()("dedicated",
- "Enable dedicated server mode",
+ "Enable dedicated server mode, disables '--allow-port-probing' and allocates more resources.",
cxxopts::value<bool>(ServerOptions.IsDedicated)->default_value("false"));
+ options.add_options()("allow-port-probing",
+ "Allow searching for an available port, disabled if '--dedicated' is enabled.",
+ cxxopts::value<bool>(ServerOptions.AllowPortProbing)->default_value("true"));
options.add_options()("d, debug", "Enable debugging", cxxopts::value<bool>(ServerOptions.IsDebug)->default_value("false"));
options.add_options()("clean",
"Clean out all state at startup",
@@ -247,6 +267,10 @@ ZenServerCmdLineOptions::AddCliOptions(cxxopts::Options& options, ZenServerConfi
options.add_options()("powercycle",
"Exit immediately after initialization is complete",
cxxopts::value<bool>(ServerOptions.IsPowerCycle));
+ options.add_options()("enable-execution-history",
+ "Record this invocation in the per-user execution history "
+ "(use --enable-execution-history=false to suppress)",
+ cxxopts::value<bool>()->default_value("true")->implicit_value("true"));
options.add_option("diagnostics",
"",
@@ -292,7 +316,7 @@ ZenServerCmdLineOptions::AddCliOptions(cxxopts::Options& options, ZenServerConfi
"p",
"port",
"Select HTTP port",
- cxxopts::value<int>(ServerOptions.BasePort)->default_value("8558"),
+ cxxopts::value<std::string>(PortStr)->default_value("auto"),
"<port number>");
options.add_option("network",
@@ -304,6 +328,41 @@ ZenServerCmdLineOptions::AddCliOptions(cxxopts::Options& options, ZenServerConfi
options.add_option("network",
"",
+ "unix-socket",
+ "Unix domain socket path to listen on (in addition to TCP)",
+ cxxopts::value<std::string>(UnixSocketPath),
+ "<path>");
+
+ options.add_option("network",
+ "",
+ "no-network",
+ "Disable TCP/HTTPS listeners; only accept connections via --unix-socket",
+ cxxopts::value<bool>(ServerOptions.HttpConfig.NoNetwork)->default_value("false"),
+ "");
+
+ options.add_option("network",
+ "",
+ "https-port",
+ "HTTPS listen port (0 = disabled)",
+ cxxopts::value<int>(ServerOptions.HttpConfig.HttpsPort)->default_value("0"),
+ "<port>");
+
+ options.add_option("network",
+ "",
+ "cert-file",
+ "Path to PEM certificate chain file for HTTPS",
+ cxxopts::value<std::string>(ServerOptions.HttpConfig.CertFile),
+ "<path>");
+
+ options.add_option("network",
+ "",
+ "key-file",
+ "Path to PEM private key file for HTTPS",
+ cxxopts::value<std::string>(ServerOptions.HttpConfig.KeyFile),
+ "<path>");
+
+ options.add_option("network",
+ "",
"security-config-path",
"Path to http security configuration file",
cxxopts::value<std::string>(SecurityConfigPath),
@@ -330,10 +389,45 @@ ZenServerCmdLineOptions::AddCliOptions(cxxopts::Options& options, ZenServerConfi
"Enables Httpsys request logging",
cxxopts::value<bool>(ServerOptions.HttpConfig.HttpSys.IsRequestLoggingEnabled),
"<httpsys request logging>");
+
+ options.add_option("httpsys",
+ "",
+ "httpsys-https-port",
+ "HTTPS listen port for http.sys (0 = disabled)",
+ cxxopts::value<int>(ServerOptions.HttpConfig.HttpSys.HttpsPort)->default_value("0"),
+ "<port>");
+
+ options.add_option("httpsys",
+ "",
+ "httpsys-cert-thumbprint",
+ "SHA-1 certificate thumbprint for auto SSL binding",
+ cxxopts::value<std::string>(ServerOptions.HttpConfig.HttpSys.CertThumbprint),
+ "<thumbprint>");
+
+ options.add_option("httpsys",
+ "",
+ "httpsys-cert-store",
+ "Windows certificate store name for SSL binding",
+ cxxopts::value<std::string>(ServerOptions.HttpConfig.HttpSys.CertStoreName)->default_value("MY"),
+ "<store name>");
+
+ options.add_option("httpsys",
+ "",
+ "httpsys-https-only",
+ "Disable HTTP listener when HTTPS is active",
+ cxxopts::value<bool>(ServerOptions.HttpConfig.HttpSys.HttpsOnly)->default_value("false"),
+ "");
#endif
options.add_option("network",
"",
+ "httpclient",
+ "Select HTTP client implementation",
+ cxxopts::value<std::string>(ServerOptions.HttpClient.Backend)->default_value("curl"),
+ "<http client>");
+
+ options.add_option("network",
+ "",
"http",
"Select HTTP server implementation (asio|"
#if ZEN_WITH_HTTPSYS
@@ -389,14 +483,112 @@ ZenServerCmdLineOptions::ApplyOptions(cxxopts::Options& options, ZenServerConfig
throw std::runtime_error(fmt::format("'--snapshot-dir' ('{}') must be a directory", ServerOptions.BaseSnapshotDir));
}
- ServerOptions.SystemRootDir = MakeSafeAbsolutePath(SystemRootDir);
- ServerOptions.DataDir = MakeSafeAbsolutePath(DataDir);
- ServerOptions.ContentDir = MakeSafeAbsolutePath(ContentDir);
- ServerOptions.ConfigFile = MakeSafeAbsolutePath(ConfigFile);
- ServerOptions.BaseSnapshotDir = MakeSafeAbsolutePath(BaseSnapshotDir);
+ SystemRootDir = ExpandEnvironmentVariables(SystemRootDir);
+ ServerOptions.SystemRootDir = MakeSafeAbsolutePath(SystemRootDir);
+
+ DataDir = ExpandEnvironmentVariables(DataDir);
+ ServerOptions.DataDir = MakeSafeAbsolutePath(DataDir);
+
+ ContentDir = ExpandEnvironmentVariables(ContentDir);
+ ServerOptions.ContentDir = MakeSafeAbsolutePath(ContentDir);
+
+ ConfigFile = ExpandEnvironmentVariables(ConfigFile);
+ ServerOptions.ConfigFile = MakeSafeAbsolutePath(ConfigFile);
+
+ BaseSnapshotDir = ExpandEnvironmentVariables(BaseSnapshotDir);
+ ServerOptions.BaseSnapshotDir = MakeSafeAbsolutePath(BaseSnapshotDir);
+
+ ExpandEnvironmentVariables(SecurityConfigPath);
ServerOptions.SecurityConfigPath = MakeSafeAbsolutePath(SecurityConfigPath);
+ if (!UnixSocketPath.empty())
+ {
+ UnixSocketPath = ExpandEnvironmentVariables(UnixSocketPath);
+ ServerOptions.HttpConfig.UnixSocketPath = MakeSafeAbsolutePath(UnixSocketPath);
+ }
+
+ if (PortStr != "auto")
+ {
+ int Port = 0;
+ auto [Ptr, Ec] = std::from_chars(PortStr.data(), PortStr.data() + PortStr.size(), Port);
+ if (Ec != std::errc{} || Ptr != PortStr.data() + PortStr.size() || Port <= 0 || Port > 65535)
+ {
+ throw OptionParseException(fmt::format("invalid port '{}': expected 'auto' or a number between 1 and 65535", PortStr),
+ options.help());
+ }
+ ServerOptions.BasePort = Port;
+ }
+
LoggingOptions.ApplyOptions(ServerOptions.LoggingConfig);
+
+#if ZEN_WITH_HTTPSYS
+ // Validate HTTPS options
+ const auto& HttpSys = ServerOptions.HttpConfig.HttpSys;
+ if (HttpSys.HttpsOnly && HttpSys.HttpsPort == 0)
+ {
+ throw OptionParseException("'--httpsys-https-only' requires '--httpsys-https-port' to be set", options.help());
+ }
+ if (!HttpSys.CertThumbprint.empty() && HttpSys.CertThumbprint.size() != 40)
+ {
+ throw OptionParseException("'--httpsys-cert-thumbprint' must be exactly 40 hex characters (SHA-1)", options.help());
+ }
+ if (!HttpSys.CertThumbprint.empty())
+ {
+ for (char Ch : HttpSys.CertThumbprint)
+ {
+ if (!((Ch >= '0' && Ch <= '9') || (Ch >= 'a' && Ch <= 'f') || (Ch >= 'A' && Ch <= 'F')))
+ {
+ throw OptionParseException("'--httpsys-cert-thumbprint' contains non-hex characters", options.help());
+ }
+ }
+ }
+ if (HttpSys.HttpsPort > 0 && HttpSys.HttpsPort == ServerOptions.BasePort && !HttpSys.HttpsOnly)
+ {
+ throw OptionParseException("'--httpsys-https-port' must differ from '--port' when both HTTP and HTTPS are active", options.help());
+ }
+#endif
+
+ // Validate --no-network
+ if (ServerOptions.HttpConfig.NoNetwork)
+ {
+ if (ServerOptions.HttpConfig.UnixSocketPath.empty())
+ {
+ throw OptionParseException("'--no-network' requires '--unix-socket' to be set", options.help());
+ }
+#if ZEN_WITH_HTTPSYS
+ if (ServerOptions.HttpConfig.ServerClass == "httpsys")
+ {
+ throw OptionParseException("'--no-network' is not compatible with '--http=httpsys'", options.help());
+ }
+#endif
+ if (ServerOptions.HttpConfig.ServerClass.empty())
+ {
+ ServerOptions.HttpConfig.ServerClass = "asio";
+ }
+ }
+
+ // Validate generic HTTPS options (used by ASIO backend)
+ if (ServerOptions.HttpConfig.HttpsPort > 0)
+ {
+ if (ServerOptions.HttpConfig.CertFile.empty() || ServerOptions.HttpConfig.KeyFile.empty())
+ {
+ throw OptionParseException("'--https-port' requires both '--cert-file' and '--key-file' to be set", options.help());
+ }
+ if (!std::filesystem::exists(ServerOptions.HttpConfig.CertFile))
+ {
+ throw OptionParseException(fmt::format("'--cert-file' path '{}' does not exist", ServerOptions.HttpConfig.CertFile),
+ options.help());
+ }
+ if (!std::filesystem::exists(ServerOptions.HttpConfig.KeyFile))
+ {
+ throw OptionParseException(fmt::format("'--key-file' path '{}' does not exist", ServerOptions.HttpConfig.KeyFile),
+ options.help());
+ }
+ if (ServerOptions.HttpConfig.HttpsPort == ServerOptions.BasePort)
+ {
+ throw OptionParseException("'--https-port' must differ from '--port'", options.help());
+ }
+ }
}
//////////////////////////////////////////////////////////////////////////
@@ -423,6 +615,7 @@ ZenServerConfiguratorBase::Configure(int argc, char* argv[])
}
cxxopts::Options options("zenserver", "Zen Storage Server");
+ options.set_width(TuiConsoleColumns(80));
ZenServerCmdLineOptions BaseOptions;
BaseOptions.AddCliOptions(options, m_ServerOptions);
@@ -487,6 +680,14 @@ ZenServerConfiguratorBase::Configure(int argc, char* argv[])
}
ValidateOptions(); // subclass validation
+
+ // Resolve auto port: subclass ValidateOptions may have set a
+ // mode-specific default; if BasePort is still 0, fall back to the
+ // global default.
+ if (m_ServerOptions.BasePort == 0)
+ {
+ m_ServerOptions.BasePort = ZenServerConfig::kDefaultBasePort;
+ }
}
catch (const OptionParseException& e)
{
@@ -511,6 +712,7 @@ ZenServerConfiguratorBase::Configure(int argc, char* argv[])
}
m_ServerOptions.HttpConfig.IsDedicatedServer = m_ServerOptions.IsDedicated;
+ m_ServerOptions.HttpConfig.AllowPortProbing = !m_ServerOptions.IsDedicated && m_ServerOptions.AllowPortProbing;
}
void
diff --git a/src/zenserver/config/config.h b/src/zenserver/config/config.h
index 55aee07f9..d35a1a8c7 100644
--- a/src/zenserver/config/config.h
+++ b/src/zenserver/config/config.h
@@ -38,24 +38,32 @@ struct ZenSentryConfig
bool Debug = false; // Enable debug mode for Sentry
};
+struct HttpClientConfig
+{
+ std::string Backend = "curl"; // Choice of HTTP client implementation
+};
+
struct ZenServerConfig
{
+ HttpClientConfig HttpClient;
HttpServerConfig HttpConfig;
ZenSentryConfig SentryConfig;
ZenStatsConfig StatsConfig;
ZenLoggingConfig LoggingConfig;
- int BasePort = 8558; // Service listen port (used for both UDP and TCP)
- int OwnerPid = 0; // Parent process id (zero for standalone)
- bool IsDebug = false;
- bool IsCleanStart = false; // Indicates whether all state should be wiped on startup or not
- bool IsPowerCycle = false; // When true, the process shuts down immediately after initialization
- bool IsTest = false;
- bool Detach = true; // Whether zenserver should detach from existing process group (Mac/Linux)
- int CoreLimit = 0; // If set, hardware concurrency queries are capped at this number
- int LieCpu = 0;
- bool IsDedicated = false; // Indicates a dedicated/shared instance, with larger resource requirements
- bool ShouldCrash = false; // Option for testing crash handling
- bool IsFirstRun = false;
+ static constexpr int kDefaultBasePort = 8558;
+ int BasePort = 0; // Service listen port; 0 = auto (resolved per mode)
+ int OwnerPid = 0; // Parent process id (zero for standalone)
+ bool IsDebug = false;
+ bool IsCleanStart = false; // Indicates whether all state should be wiped on startup or not
+ bool IsPowerCycle = false; // When true, the process shuts down immediately after initialization
+ bool IsTest = false;
+ bool Detach = true; // Whether zenserver should detach from existing process group (Mac/Linux)
+ int CoreLimit = 0; // If set, hardware concurrency queries are capped at this number
+ int LieCpu = 0;
+ bool IsDedicated = false; // Indicates a dedicated/shared instance, with larger resource requirements
+ bool AllowPortProbing = true; // Automatically false if IsDedicated is true
+ bool ShouldCrash = false; // Option for testing crash handling
+ bool IsFirstRun = false;
std::filesystem::path ConfigFile; // Path to Lua config file
std::filesystem::path SystemRootDir; // System root directory (used for machine level config)
std::filesystem::path ContentDir; // Root directory for serving frontend content (experimental)