aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/main.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-10-13 13:42:25 +0200
committerGitHub Enterprise <[email protected]>2025-10-13 13:42:25 +0200
commite5a05c01ba5f1b9517108fe95d54b4066190d66d (patch)
tree591d18ecf12753104ee05f868c1155b0a7941e4a /src/zenserver/main.cpp
parentrefactor builds cmd (#566) (diff)
downloadzen-e5a05c01ba5f1b9517108fe95d54b4066190d66d.tar.xz
zen-e5a05c01ba5f1b9517108fe95d54b4066190d66d.zip
extract storage server into separate source files (#569)
this change moves common base service code into `zenserver.(cpp|h)` and storage server code into `zenstorageserver.(cpp|h)` to more clearly separate concerns but also to make way for another service
Diffstat (limited to 'src/zenserver/main.cpp')
-rw-r--r--src/zenserver/main.cpp347
1 files changed, 5 insertions, 342 deletions
diff --git a/src/zenserver/main.cpp b/src/zenserver/main.cpp
index 0dc390797..f1c1a9394 100644
--- a/src/zenserver/main.cpp
+++ b/src/zenserver/main.cpp
@@ -1,6 +1,6 @@
// Copyright Epic Games, Inc. All Rights Reserved.
-#include "zenserver.h"
+#include "zenstorageserver.h"
#include <zencore/compactbinarybuilder.h>
#include <zencore/compactbinaryvalidation.h>
@@ -59,342 +59,13 @@ SignalCallbackHandler(int SigNum)
namespace zen {
-static const FLLMTag&
-GetZenserverTag()
-{
- static FLLMTag _("zenserver");
-
- return _;
-}
-
using namespace std::literals;
-////////////////////////////////////////////////////////////////////////////////
-
-class ZenServerMain
-{
-public:
- ZenServerMain(ZenServerOptions& ServerOptions);
- ~ZenServerMain();
-
- int Run();
-
- ZenServerMain(const ZenServerMain&) = delete;
- ZenServerMain& operator=(const ZenServerMain&) = delete;
-
-protected:
- ZenServerOptions& m_ServerOptions;
- LockFile m_LockFile;
-
- virtual void DoRun(ZenServerState::ZenServerEntry* Entry) = 0;
-
- void NotifyReady()
- {
- if (!m_ServerOptions.ChildId.empty())
- {
- NamedEvent ParentEvent{m_ServerOptions.ChildId};
- ParentEvent.Set();
- }
- }
-
- CbObject MakeLockData(bool IsReady)
- {
- return MakeLockFilePayload({.Pid = GetCurrentProcessId(),
- .SessionId = GetSessionId(),
- .EffectiveListenPort = gsl::narrow<uint16_t>(m_ServerOptions.BasePort),
- .Ready = IsReady,
- .DataDir = m_ServerOptions.DataDir,
- .ExecutablePath = GetRunningExecutablePath()});
- };
-};
-
-ZenServerMain::ZenServerMain(ZenServerOptions& ServerOptions) : m_ServerOptions(ServerOptions)
-{
-}
-
-ZenServerMain::~ZenServerMain()
-{
-}
-
-int
-ZenServerMain::Run()
-{
- // On Linux this has the unfortunate side effect of making `top` and other tools display
- // `main` as the program name since threads and processes have a closer relationship
- // there. So we don't name the main thread explicitly there.
-
-#ifndef ZEN_PLATFORM_LINUX
- zen::SetCurrentThreadName("main");
-#endif
-
-#if ZEN_USE_SENTRY
- SentryIntegration Sentry;
-
- if (m_ServerOptions.SentryConfig.Disable == false)
- {
- std::string SentryDatabasePath = (m_ServerOptions.DataDir / ".sentry-native").string();
- std::string SentryAttachmentPath = m_ServerOptions.AbsLogFile.string();
-
- Sentry.Initialize({.DatabasePath = SentryDatabasePath,
- .AttachmentsPath = SentryAttachmentPath,
- .Dsn = m_ServerOptions.SentryConfig.Dsn,
- .Environment = m_ServerOptions.SentryConfig.Environment,
- .AllowPII = m_ServerOptions.SentryConfig.AllowPII,
- .Debug = m_ServerOptions.SentryConfig.Debug},
- m_ServerOptions.CommandLine);
- }
-#endif
-
- try
- {
- // Mutual exclusion and synchronization
- ZenServerState ServerState;
- ServerState.Initialize();
- ServerState.Sweep();
-
- uint32_t AttachSponsorProcessRetriesLeft = 3;
- ZenServerState::ZenServerEntry* Entry = ServerState.Lookup(m_ServerOptions.BasePort);
- while (Entry)
- {
- if (m_ServerOptions.OwnerPid)
- {
- std::error_code Ec;
- if (!IsProcessRunning(m_ServerOptions.OwnerPid, Ec))
- {
- if (Ec)
- {
- ZEN_WARN(ZEN_APP_NAME
- " exiting, sponsor owner pid {} can not be checked for running state, reason: '{}'. Will not add sponsor "
- "to process "
- "listening to port {} (pid: {})",
- m_ServerOptions.OwnerPid,
- Ec.message(),
- m_ServerOptions.BasePort,
- Entry->Pid.load());
- }
- else
- {
- ZEN_WARN(ZEN_APP_NAME
- " exiting, sponsor owner pid {} is no longer running, will not add sponsor to process listening to port "
- "{} (pid: {})",
- m_ServerOptions.OwnerPid,
- m_ServerOptions.BasePort,
- Entry->Pid.load());
- }
- std::exit(1);
- }
- ZEN_INFO(
- "Looks like there is already a process listening to this port {} (pid: {}), attaching owner pid {} to running instance",
- m_ServerOptions.BasePort,
- Entry->Pid.load(),
- m_ServerOptions.OwnerPid);
-
- // Sponsor processes are checked every second, so 2 second wait time should be enough
- if (Entry->AddSponsorProcess(m_ServerOptions.OwnerPid, 2000))
- {
- NotifyReady();
- std::exit(0);
- }
- if (AttachSponsorProcessRetriesLeft-- > 0)
- {
- Entry = ServerState.Lookup(m_ServerOptions.BasePort);
- }
- else
- {
- ZEN_WARN(ZEN_APP_NAME " exiting, failed to add sponsor owner pid {} to process listening to port {} (pid: {})",
- m_ServerOptions.OwnerPid,
- m_ServerOptions.BasePort,
- Entry->Pid.load());
- std::exit(1);
- }
- }
- else
- {
- ZEN_WARN(ZEN_APP_NAME " exiting, there is already a process listening to port {} (pid: {})",
- m_ServerOptions.BasePort,
- Entry->Pid.load());
- std::exit(1);
- }
- }
-
- std::error_code Ec;
-
- std::filesystem::path LockFilePath = m_ServerOptions.DataDir / ".lock";
-
- m_LockFile.Create(LockFilePath, MakeLockData(false), Ec);
-
- if (Ec)
- {
- ZEN_INFO(ZEN_APP_NAME " unable to grab lock at '{}' (reason: '{}'), retrying", LockFilePath, Ec.message());
- Sleep(100);
-
- m_LockFile.Create(LockFilePath, MakeLockData(false), Ec);
- if (Ec)
- {
- ZEN_INFO(ZEN_APP_NAME " unable to grab lock at '{}' (reason: '{}'), retrying", LockFilePath, Ec.message());
- Sleep(500);
- if (Ec)
- {
- ZEN_WARN(ZEN_APP_NAME " exiting, unable to grab lock at '{}' (reason: '{}')", LockFilePath, Ec.message());
- std::exit(99);
- }
- }
- }
-
- InitializeServerLogging(m_ServerOptions);
-
- ZEN_INFO("Command line: {}", m_ServerOptions.CommandLine);
-
-#if ZEN_USE_SENTRY
- Sentry.LogStartupInformation();
-#endif
-
- MaximizeOpenFileCount();
-
- ZEN_INFO(ZEN_APP_NAME " - using lock file at '{}'", LockFilePath);
-
- ZEN_INFO(ZEN_APP_NAME " - starting on port {}, version '{}'", m_ServerOptions.BasePort, ZEN_CFG_VERSION_BUILD_STRING_FULL);
-
- Entry = ServerState.Register(m_ServerOptions.BasePort);
-
- if (m_ServerOptions.OwnerPid)
- {
- // We are adding a sponsor process to our own entry, can't wait for pick since the code is not run until later
- Entry->AddSponsorProcess(m_ServerOptions.OwnerPid, 0);
- }
-
- // Run the actual application logic
-
- DoRun(Entry);
- }
- catch (const AssertException& AssertEx)
- {
- ZEN_CRITICAL(ZEN_APP_NAME " caught assert exception in main for process {}: {}",
- zen::GetCurrentProcessId(),
- AssertEx.FullDescription());
- RequestApplicationExit(1);
- }
- catch (const std::system_error& e)
- {
- ZEN_CRITICAL(ZEN_APP_NAME " caught system error exception in main for process {}: {} ({})",
- zen::GetCurrentProcessId(),
- e.what(),
- e.code().value());
- RequestApplicationExit(1);
- }
- catch (const std::exception& e)
- {
- ZEN_CRITICAL(ZEN_APP_NAME " caught exception in main for process {}: {}", zen::GetCurrentProcessId(), e.what());
- RequestApplicationExit(1);
- }
-
- ShutdownServerLogging();
-
- ReportServiceStatus(ServiceStatus::Stopped);
-
- return ApplicationExitCode();
-}
-
-//////////////////////////////////////////////////////////////////////////
-class ZenStorageServerMain : public ZenServerMain
-{
-public:
- ZenStorageServerMain(ZenStorageServerOptions& ServerOptions);
- virtual void DoRun(ZenServerState::ZenServerEntry* Entry) override;
-
- ZenStorageServerMain(const ZenStorageServerMain&) = delete;
- ZenStorageServerMain& operator=(const ZenStorageServerMain&) = delete;
-
-private:
- ZenStorageServerOptions& m_ServerOptions;
-};
-
-ZenStorageServerMain::ZenStorageServerMain(ZenStorageServerOptions& ServerOptions)
-: ZenServerMain(ServerOptions)
-, m_ServerOptions(ServerOptions)
-{
-}
-
-void
-ZenStorageServerMain::DoRun(ZenServerState::ZenServerEntry* Entry)
-{
- ZenStorageServer Server;
- Server.SetDataRoot(m_ServerOptions.DataDir);
- Server.SetContentRoot(m_ServerOptions.ContentDir);
- Server.SetTestMode(m_ServerOptions.IsTest);
- Server.SetDedicatedMode(m_ServerOptions.IsDedicated);
-
- auto ServerCleanup = MakeGuard([&Server] { Server.Cleanup(); });
-
- int EffectiveBasePort = Server.Initialize(m_ServerOptions, Entry);
- if (EffectiveBasePort == -1)
- {
- // Server.Initialize has already logged what the issue is - just exit with failure code here.
- std::exit(1);
- }
-
- Entry->EffectiveListenPort = uint16_t(EffectiveBasePort);
- if (EffectiveBasePort != m_ServerOptions.BasePort)
- {
- ZEN_INFO(ZEN_APP_NAME " - relocated to base port {}", EffectiveBasePort);
- m_ServerOptions.BasePort = EffectiveBasePort;
- }
-
- std::unique_ptr<std::thread> ShutdownThread;
- std::unique_ptr<NamedEvent> ShutdownEvent;
-
- ExtendableStringBuilder<64> ShutdownEventName;
- ShutdownEventName << "Zen_" << m_ServerOptions.BasePort << "_Shutdown";
- ShutdownEvent.reset(new NamedEvent{ShutdownEventName});
-
- // Monitor shutdown signals
-
- ShutdownThread.reset(new std::thread{[&] {
- SetCurrentThreadName("shutdown_monitor");
-
- ZEN_INFO("shutdown monitor thread waiting for shutdown signal '{}' for process {}", ShutdownEventName, zen::GetCurrentProcessId());
-
- if (ShutdownEvent->Wait())
- {
- ZEN_INFO("shutdown signal for pid {} received", zen::GetCurrentProcessId());
- Server.RequestExit(0);
- }
- else
- {
- ZEN_INFO("shutdown signal wait() failed");
- }
- }});
-
- auto CleanupShutdown = MakeGuard([&ShutdownEvent, &ShutdownThread] {
- ReportServiceStatus(ServiceStatus::Stopping);
-
- if (ShutdownEvent)
- {
- ShutdownEvent->Set();
- }
- if (ShutdownThread && ShutdownThread->joinable())
- {
- ShutdownThread->join();
- }
- });
-
- // If we have a parent process, establish the mechanisms we need
- // to be able to communicate readiness with the parent
-
- Server.SetIsReadyFunc([&] {
- std::error_code Ec;
- m_LockFile.Update(MakeLockData(true), Ec);
- ReportServiceStatus(ServiceStatus::Running);
- NotifyReady();
- });
-
- Server.Run();
-}
-
//////////////////////////////////////////////////////////////////////////
#if ZEN_PLATFORM_WINDOWS
+template<class T>
class ZenWindowsService : public WindowsService
{
public:
@@ -403,18 +74,12 @@ public:
ZenWindowsService(const ZenWindowsService&) = delete;
ZenWindowsService& operator=(const ZenWindowsService&) = delete;
- virtual int Run() override;
+ virtual int Run() override { return m_EntryPoint.Run(); }
private:
- ZenStorageServerMain m_EntryPoint;
+ T m_EntryPoint;
};
-int
-ZenWindowsService::Run()
-{
- return m_EntryPoint.Run();
-}
-
#endif // ZEN_PLATFORM_WINDOWS
} // namespace zen
@@ -425,8 +90,6 @@ ZenWindowsService::Run()
int
test_main(int argc, char** argv)
{
- zen::zenserver_forcelinktests();
-
zen::logging::InitializeLogging();
zen::logging::SetLogLevel(zen::logging::level::Debug);
@@ -537,7 +200,7 @@ main(int argc, char* argv[])
std::exit(0);
}
- ZenWindowsService App(ServerOptions);
+ ZenWindowsService<ZenStorageServerMain> App(ServerOptions);
return App.ServiceMain();
#else
if (ServerOptions.InstallService || ServerOptions.UninstallService)