system layer manager (llarp::sys::service_manager)

the win32 and sd_notify components provided a disjointed set of
similar high level functionality so we consolidate these duplicate
code paths into one that has the same lifecycle regardless of platform
to reduce complexity of this feature.

this new component is responsible for reporting state changes to the
system layer and optionally propagating state change to lokinet
requested by the system layer (used by windows service).
pull/2045/head
Jeff Becker 2 years ago
parent a7f3c3595b
commit 4103908a8d
No known key found for this signature in database
GPG Key ID: 025C02EE3A092F2D

@ -7,7 +7,10 @@
#include <llarp/util/str.hpp> #include <llarp/util/str.hpp>
#ifdef _WIN32 #ifdef _WIN32
#include <llarp/win32/service_manager.hpp>
#include <dbghelp.h> #include <dbghelp.h>
#else
#include <llarp/util/service_manager.hpp>
#endif #endif
#include <csignal> #include <csignal>
@ -21,19 +24,18 @@ int
lokinet_main(int, char**); lokinet_main(int, char**);
#ifdef _WIN32 #ifdef _WIN32
#include <strsafe.h>
extern "C" LONG FAR PASCAL extern "C" LONG FAR PASCAL
win32_signal_handler(EXCEPTION_POINTERS*); win32_signal_handler(EXCEPTION_POINTERS*);
extern "C" VOID FAR PASCAL extern "C" VOID FAR PASCAL
win32_daemon_entry(DWORD, LPTSTR*); win32_daemon_entry(DWORD, LPTSTR*);
BOOL ReportSvcStatus(DWORD, DWORD, DWORD);
VOID VOID
insert_description(); insert_description();
SERVICE_STATUS SvcStatus;
SERVICE_STATUS_HANDLE SvcStatusHandle;
bool start_as_daemon = false;
#endif #endif
bool run_as_daemon{false};
static auto logcat = llarp::log::Cat("main"); static auto logcat = llarp::log::Cat("main");
std::shared_ptr<llarp::Context> ctx; std::shared_ptr<llarp::Context> ctx;
std::promise<int> exit_code; std::promise<int> exit_code;
@ -84,9 +86,6 @@ install_win32_daemon()
llarp::LogError("Cannot install service ", GetLastError()); llarp::LogError("Cannot install service ", GetLastError());
return; return;
} }
// just put the flag here. we eat it later on and specify the
// config path in the daemon entry point
StringCchCat(szPath.data(), 1024, " --win32-daemon");
// Get a handle to the SCM database. // Get a handle to the SCM database.
schSCManager = OpenSCManager( schSCManager = OpenSCManager(
@ -294,37 +293,6 @@ run_main_context(std::optional<fs::path> confFile, const llarp::RuntimeOptions o
} }
#ifdef _WIN32 #ifdef _WIN32
void
TellWindowsServiceStopped()
{
::WSACleanup();
if (not start_as_daemon)
return;
llarp::LogInfo("Telling Windows the service has stopped.");
if (not ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0))
{
auto error_code = GetLastError();
if (error_code == ERROR_INVALID_DATA)
llarp::LogError(
"SetServiceStatus failed: \"The specified service status structure is invalid.\"");
else if (error_code == ERROR_INVALID_HANDLE)
llarp::LogError("SetServiceStatus failed: \"The specified handle is invalid.\"");
else
llarp::LogError("SetServiceStatus failed with an unknown error.");
}
}
class WindowsServiceStopped
{
public:
WindowsServiceStopped() = default;
~WindowsServiceStopped()
{
TellWindowsServiceStopped();
}
};
/// minidump generation for windows jizz /// minidump generation for windows jizz
/// will make a coredump when there is an unhandled exception /// will make a coredump when there is an unhandled exception
@ -370,9 +338,9 @@ main(int argc, char* argv[])
#else #else
SERVICE_TABLE_ENTRY DispatchTable[] = { SERVICE_TABLE_ENTRY DispatchTable[] = {
{strdup("lokinet"), (LPSERVICE_MAIN_FUNCTION)win32_daemon_entry}, {NULL, NULL}}; {strdup("lokinet"), (LPSERVICE_MAIN_FUNCTION)win32_daemon_entry}, {NULL, NULL}};
if (lstrcmpi(argv[1], "--win32-daemon") == 0) if (std::string{argv[1]} == "--win32-daemon")
{ {
start_as_daemon = true; run_as_daemon = true;
StartServiceCtrlDispatcher(DispatchTable); StartServiceCtrlDispatcher(DispatchTable);
} }
else else
@ -383,6 +351,10 @@ main(int argc, char* argv[])
int int
lokinet_main(int argc, char** argv) lokinet_main(int argc, char** argv)
{ {
// if we are not running as a service disable reporting
if (llarp::platform::is_windows and not run_as_daemon)
llarp::sys::service_manager->disable();
if (auto result = Lokinet_INIT()) if (auto result = Lokinet_INIT())
return result; return result;
@ -398,7 +370,6 @@ lokinet_main(int argc, char** argv)
opts.showBanner = false; opts.showBanner = false;
#ifdef _WIN32 #ifdef _WIN32
WindowsServiceStopped stopped_raii;
if (startWinsock()) if (startWinsock())
return -1; return -1;
SetConsoleCtrlHandler(handle_signal_win32, TRUE); SetConsoleCtrlHandler(handle_signal_win32, TRUE);
@ -545,13 +516,9 @@ lokinet_main(int argc, char** argv)
SetUnhandledExceptionFilter(&GenerateDump); SetUnhandledExceptionFilter(&GenerateDump);
#endif #endif
std::thread main_thread{[&] { run_main_context(configFile, opts); }}; std::thread main_thread{[configFile, opts] { run_main_context(configFile, opts); }};
auto ftr = exit_code.get_future(); auto ftr = exit_code.get_future();
#ifdef _WIN32
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
#endif
do do
{ {
// do periodic non lokinet related tasks here // do periodic non lokinet related tasks here
@ -582,9 +549,7 @@ lokinet_main(int argc, char** argv)
llarp::log::critical(deadlock_cat, wtf); llarp::log::critical(deadlock_cat, wtf);
llarp::log::flush(); llarp::log::flush();
} }
#ifdef _WIN32 llarp::sys::service_manager->failed();
TellWindowsServiceStopped();
#endif
std::abort(); std::abort();
} }
} while (ftr.wait_for(std::chrono::seconds(1)) != std::future_status::ready); } while (ftr.wait_for(std::chrono::seconds(1)) != std::future_status::ready);
@ -609,6 +574,7 @@ lokinet_main(int argc, char** argv)
} }
llarp::log::flush(); llarp::log::flush();
llarp::sys::service_manager->stopped();
if (ctx) if (ctx)
{ {
ctx.reset(); ctx.reset();
@ -617,29 +583,6 @@ lokinet_main(int argc, char** argv)
} }
#ifdef _WIN32 #ifdef _WIN32
BOOL
ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
// Fill in the SERVICE_STATUS structure.
SvcStatus.dwCurrentState = dwCurrentState;
SvcStatus.dwWin32ExitCode = dwWin32ExitCode;
SvcStatus.dwWaitHint = dwWaitHint;
if (dwCurrentState == SERVICE_START_PENDING)
SvcStatus.dwControlsAccepted = 0;
else
SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED))
SvcStatus.dwCheckPoint = 0;
else
SvcStatus.dwCheckPoint = dwCheckPoint++;
// Report the status of the service to the SCM.
return SetServiceStatus(SvcStatusHandle, &SvcStatus);
}
VOID FAR PASCAL VOID FAR PASCAL
SvcCtrlHandler(DWORD dwCtrl) SvcCtrlHandler(DWORD dwCtrl)
@ -651,14 +594,13 @@ SvcCtrlHandler(DWORD dwCtrl)
case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_STOP:
// tell service we are stopping // tell service we are stopping
llarp::log::info(logcat, "Windows service controller gave SERVICE_CONTROL_STOP"); llarp::log::info(logcat, "Windows service controller gave SERVICE_CONTROL_STOP");
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); llarp::sys::service_manager->system_changed_our_state(llarp::sys::ServiceState::Stopping);
// do the actual tear down
handle_signal(SIGINT);
return; return;
case SERVICE_CONTROL_INTERROGATE: case SERVICE_CONTROL_INTERROGATE:
// report status // report status
SetServiceStatus(SvcStatusHandle, &SvcStatus); llarp::log::debug(logcat, "Got win32 service interrogate signal");
llarp::sys::service_manager->report_changed_state();
return; return;
default: default:
@ -673,21 +615,15 @@ VOID FAR PASCAL
win32_daemon_entry(DWORD, LPTSTR* argv) win32_daemon_entry(DWORD, LPTSTR* argv)
{ {
// Register the handler function for the service // Register the handler function for the service
SvcStatusHandle = RegisterServiceCtrlHandler("lokinet", SvcCtrlHandler); auto* svc = dynamic_cast<llarp::sys::SVC_Manager*>(llarp::sys::service_manager);
svc->handle = RegisterServiceCtrlHandler("lokinet", SvcCtrlHandler);
if (!SvcStatusHandle) if (svc->handle == nullptr)
{ {
llarp::LogError("failed to register daemon control handler"); llarp::LogError("failed to register daemon control handler");
return; return;
} }
// These SERVICE_STATUS members remain as set here
SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
SvcStatus.dwServiceSpecificExitCode = 0;
// Report initial status to the SCM
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
// we hard code the args to lokinet_main. // we hard code the args to lokinet_main.
// we yoink argv[0] (lokinet.exe path) and pass in the new args. // we yoink argv[0] (lokinet.exe path) and pass in the new args.
std::array args = { std::array args = {

@ -45,6 +45,7 @@ namespace llarp
std::shared_ptr<NodeDB> nodedb = nullptr; std::shared_ptr<NodeDB> nodedb = nullptr;
std::string nodedb_dir; std::string nodedb_dir;
Context();
virtual ~Context() = default; virtual ~Context() = default;
void void

@ -49,17 +49,23 @@ target_link_libraries(lokinet-platform PUBLIC lokinet-cryptography lokinet-util
target_link_libraries(lokinet-platform PRIVATE oxenmq::oxenmq) target_link_libraries(lokinet-platform PRIVATE oxenmq::oxenmq)
if (ANDROID) if (ANDROID)
target_sources(lokinet-platform PRIVATE android/ifaddrs.c) target_sources(lokinet-platform PRIVATE android/ifaddrs.c util/nop_service_manager.cpp)
endif() endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux") if(CMAKE_SYSTEM_NAME MATCHES "Linux")
target_sources(lokinet-platform PRIVATE linux/dbus.cpp) target_sources(lokinet-platform PRIVATE linux/dbus.cpp)
if(WITH_SYSTEMD)
target_sources(lokinet-platform PRIVATE linux/sd_service_manager.cpp)
else()
target_sources(lokinet-platform PRIVATE util/nop_service_manager.cpp)
endif()
endif() endif()
if (WIN32) if (WIN32)
target_sources(lokinet-platform PRIVATE target_sources(lokinet-platform PRIVATE
net/win32.cpp net/win32.cpp
vpn/win32.cpp vpn/win32.cpp
win32/service_manager.cpp
win32/exec.cpp) win32/exec.cpp)
add_library(lokinet-win32 STATIC add_library(lokinet-win32 STATIC
win32/dll.cpp win32/dll.cpp
@ -312,6 +318,7 @@ endif()
if(APPLE) if(APPLE)
add_subdirectory(apple) add_subdirectory(apple)
target_sources(lokinet-platform PRIVATE util/nop_system_manager.cpp)
endif() endif()
file(GLOB_RECURSE docs_SRC */*.hpp *.hpp) file(GLOB_RECURSE docs_SRC */*.hpp *.hpp)

@ -12,6 +12,8 @@
#include "service/context.hpp" #include "service/context.hpp"
#include "util/logging.hpp" #include "util/logging.hpp"
#include <llarp/util/service_manager.hpp>
#include <cxxopts.hpp> #include <cxxopts.hpp>
#include <csignal> #include <csignal>
#include <stdexcept> #include <stdexcept>
@ -213,4 +215,10 @@ namespace llarp
loop.reset(); loop.reset();
} }
Context::Context()
{
// service_manager is a global and context isnt
llarp::sys::service_manager->give_context(this);
}
} // namespace llarp } // namespace llarp

@ -0,0 +1,60 @@
#include <llarp/util/service_manager.hpp>
#include <systemd/sd-daemon.h>
#include <cassert>
#include <llarp.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/logging.hpp>
namespace llarp::sys
{
class SD_Manager : public I_SystemLayerManager
{
llarp::sys::ServiceState m_State{ServiceState::Initial};
public:
/// change our state and report it to the system layer
void
we_changed_our_state(ServiceState st) override
{
assert(m_State != st);
m_State = st;
report_changed_state();
}
void
report_changed_state() override
{
if (m_State == ServiceState::Running)
{
::sd_notify(0, "READY=1");
return;
}
if (m_State == ServiceState::Stopping)
{
::sd_notify(0, "STOPPING=1");
return;
}
}
void
report_periodic_stats() override
{
if (m_Context and m_Context->router and not m_disable)
{
auto status = fmt::format("WATCHDOG=1\nSTATUS={}", m_Context->router->status_line());
::sd_notify(0, status.c_str());
}
}
void
system_changed_our_state(ServiceState) override
{
// not applicable on systemd
}
};
SD_Manager _manager{};
I_SystemLayerManager* const service_manager = &_manager;
} // namespace llarp::sys

@ -361,6 +361,9 @@ namespace llarp
virtual void virtual void
GossipRCIfNeeded(const RouterContact rc) = 0; GossipRCIfNeeded(const RouterContact rc) = 0;
virtual std::string
status_line() = 0;
/// Templated convenience function to generate a RouterHive event and /// Templated convenience function to generate a RouterHive event and
/// delegate to non-templated (and overridable) function for handling. /// delegate to non-templated (and overridable) function for handling.
template <class EventType, class... Params> template <class EventType, class... Params>

@ -393,6 +393,8 @@ namespace llarp
bool bool
Router::Configure(std::shared_ptr<Config> c, bool isSNode, std::shared_ptr<NodeDB> nodedb) Router::Configure(std::shared_ptr<Config> c, bool isSNode, std::shared_ptr<NodeDB> nodedb)
{ {
llarp::sys::service_manager->starting();
m_Config = std::move(c); m_Config = std::move(c);
auto& conf = *m_Config; auto& conf = *m_Config;
@ -870,6 +872,58 @@ namespace llarp
m_LastStatsReport = now; m_LastStatsReport = now;
} }
std::string
Router::status_line()
{
std::string status;
auto out = std::back_inserter(status);
fmt::format_to(out, "v{}", llarp::VERSION_STR);
if (IsServiceNode())
{
fmt::format_to(
out,
" snode | known/svc/clients: {}/{}/{}",
nodedb()->NumLoaded(),
NumberOfConnectedRouters(),
NumberOfConnectedClients());
fmt::format_to(
out,
" | {} active paths | block {} ",
pathContext().CurrentTransitPaths(),
(m_lokidRpcClient ? m_lokidRpcClient->BlockHeight() : 0));
auto maybe_last = _rcGossiper.LastGossipAt();
fmt::format_to(
out,
" | gossip: (next/last) {} / {}",
short_time_from_now(_rcGossiper.NextGossipAt()),
maybe_last ? short_time_from_now(*maybe_last) : "never");
}
else
{
fmt::format_to(
out,
" client | known/connected: {}/{}",
nodedb()->NumLoaded(),
NumberOfConnectedRouters());
if (auto ep = hiddenServiceContext().GetDefault())
{
fmt::format_to(
out,
" | paths/endpoints {}/{}",
pathContext().CurrentOwnedPaths(),
ep->UniqueEndpoints());
if (auto success_rate = ep->CurrentBuildStats().SuccessRatio(); success_rate < 0.5)
{
fmt::format_to(
out, " [ !!! Low Build Success Rate ({:.1f}%) !!! ]", (100.0 * success_rate));
}
};
}
return status;
}
void void
Router::Tick() Router::Tick()
{ {
@ -884,57 +938,7 @@ namespace llarp
Thaw(); Thaw();
} }
#if defined(WITH_SYSTEMD) llarp::sys::service_manager->report_periodic_stats();
{
std::string status;
auto out = std::back_inserter(status);
fmt::format_to(out, "WATCHDOG=1\nSTATUS=v{}", llarp::VERSION_STR);
if (IsServiceNode())
{
fmt::format_to(
out,
" snode | known/svc/clients: {}/{}/{}",
nodedb()->NumLoaded(),
NumberOfConnectedRouters(),
NumberOfConnectedClients());
fmt::format_to(
out,
" | {} active paths | block {} ",
pathContext().CurrentTransitPaths(),
(m_lokidRpcClient ? m_lokidRpcClient->BlockHeight() : 0));
auto maybe_last = _rcGossiper.LastGossipAt();
fmt::format_to(
out,
" | gossip: (next/last) {} / {}",
short_time_from_now(_rcGossiper.NextGossipAt()),
maybe_last ? short_time_from_now(*maybe_last) : "never");
}
else
{
fmt::format_to(
out,
" client | known/connected: {}/{}",
nodedb()->NumLoaded(),
NumberOfConnectedRouters());
if (auto ep = hiddenServiceContext().GetDefault())
{
fmt::format_to(
out,
" | paths/endpoints {}/{}",
pathContext().CurrentOwnedPaths(),
ep->UniqueEndpoints());
if (auto success_rate = ep->CurrentBuildStats().SuccessRatio(); success_rate < 0.5)
{
fmt::format_to(
out, " [ !!! Low Build Success Rate ({:.1f}%) !!! ]", (100.0 * success_rate));
}
};
}
::sd_notify(0, status.c_str());
}
#endif
m_PathBuildLimiter.Decay(now); m_PathBuildLimiter.Decay(now);
@ -1399,9 +1403,6 @@ namespace llarp
m_RoutePoker->Start(this); m_RoutePoker->Start(this);
_running.store(true); _running.store(true);
_startedAt = Now(); _startedAt = Now();
#if defined(WITH_SYSTEMD)
::sd_notify(0, "READY=1");
#endif
if (whitelistRouters) if (whitelistRouters)
{ {
// do service node testing if we are in service node whitelist mode // do service node testing if we are in service node whitelist mode
@ -1474,6 +1475,7 @@ namespace llarp
} }
}); });
} }
llarp::sys::service_manager->ready();
return _running; return _running;
} }
@ -1525,9 +1527,7 @@ namespace llarp
if (log::get_level_default() != log::Level::off) if (log::get_level_default() != log::Level::off)
log::reset_level(log::Level::info); log::reset_level(log::Level::info);
LogWarn("stopping router hard"); LogWarn("stopping router hard");
#if defined(WITH_SYSTEMD) llarp::sys::service_manager->stopping();
sd_notify(0, "STOPPING=1\nSTATUS=Shutting down HARD");
#endif
hiddenServiceContext().StopAll(); hiddenServiceContext().StopAll();
_exitContext.Stop(); _exitContext.Stop();
StopLinks(); StopLinks();
@ -1546,9 +1546,7 @@ namespace llarp
if (log::get_level_default() != log::Level::off) if (log::get_level_default() != log::Level::off)
log::reset_level(log::Level::info); log::reset_level(log::Level::info);
LogInfo("stopping router"); LogInfo("stopping router");
#if defined(WITH_SYSTEMD) llarp::sys::service_manager->stopping();
sd_notify(0, "STOPPING=1\nSTATUS=Shutting down");
#endif
hiddenServiceContext().StopAll(); hiddenServiceContext().StopAll();
_exitContext.Stop(); _exitContext.Stop();
paths.PumpUpstream(); paths.PumpUpstream();

@ -35,6 +35,7 @@
#include <llarp/util/status.hpp> #include <llarp/util/status.hpp>
#include <llarp/util/str.hpp> #include <llarp/util/str.hpp>
#include <llarp/util/time.hpp> #include <llarp/util/time.hpp>
#include <llarp/util/service_manager.hpp>
#include <functional> #include <functional>
#include <list> #include <list>
@ -315,6 +316,9 @@ namespace llarp
RCLookupHandler _rcLookupHandler; RCLookupHandler _rcLookupHandler;
RCGossiper _rcGossiper; RCGossiper _rcGossiper;
std::string
status_line() override;
using Clock_t = std::chrono::steady_clock; using Clock_t = std::chrono::steady_clock;
using TimePoint_t = Clock_t::time_point; using TimePoint_t = Clock_t::time_point;

@ -0,0 +1,7 @@
#include "service_manager.hpp"
namespace llarp::sys
{
NOP_SystemLayerHandler _manager{};
I_SystemLayerManager* const service_manager = &_manager;
} // namespace llarp::sys

@ -0,0 +1,118 @@
#pragma once
namespace llarp
{
struct Context;
}
namespace llarp::sys
{
// what state lokinet will report we are in to the system layer
enum class ServiceState
{
Initial,
Starting,
Running,
Stopping,
Stopped,
HardStop,
Failed,
};
/// interface type for interacting with the os dependant system layer
class I_SystemLayerManager
{
protected:
bool m_disable{false};
llarp::Context* m_Context{nullptr};
/// change our state and report it to the system layer
virtual void
we_changed_our_state(ServiceState st) = 0;
public:
virtual ~I_SystemLayerManager() = default;
/// disable all reporting to system layer
inline void
disable()
{
m_disable = true;
}
/// give our current lokinet context to the system layer manager
inline void
give_context(llarp::Context* ctx)
{
m_Context = ctx;
}
/// system told us to enter this state
virtual void
system_changed_our_state(ServiceState st) = 0;
/// report our current state to the system layer
virtual void
report_changed_state() = 0;
/// report our stats on each timer tick
virtual void
report_periodic_stats(){};
void
starting()
{
if (m_disable)
return;
we_changed_our_state(ServiceState::Starting);
}
void
ready()
{
if (m_disable)
return;
we_changed_our_state(ServiceState::Running);
}
void
stopping()
{
if (m_disable)
return;
we_changed_our_state(ServiceState::Stopping);
}
void
stopped()
{
if (m_disable)
return;
we_changed_our_state(ServiceState::Stopped);
}
void
failed()
{
if (m_disable)
return;
we_changed_our_state(ServiceState::Failed);
}
};
extern I_SystemLayerManager* const service_manager;
class NOP_SystemLayerHandler : public I_SystemLayerManager
{
protected:
void
we_changed_our_state(ServiceState) override
{}
public:
void
report_changed_state() override{};
void system_changed_our_state(ServiceState) override{};
};
} // namespace llarp::sys

@ -0,0 +1,85 @@
#include <windows.h>
#include <llarp.hpp>
#include "service_manager.hpp"
#include <dbghelp.h>
#include <cassert>
#include <csignal>
#include <optional>
namespace llarp::sys
{
namespace
{
std::optional<DWORD>
to_win32_state(ServiceState st)
{
switch (st)
{
case ServiceState::Starting:
return SERVICE_START_PENDING;
case ServiceState::Running:
return SERVICE_RUNNING;
case ServiceState::Stopping:
return SERVICE_STOP_PENDING;
case ServiceState::Stopped:
return SERVICE_STOPPED;
default:
return std::nullopt;
}
}
} // namespace
SVC_Manager::SVC_Manager()
{
_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
}
void
SVC_Manager::system_changed_our_state(ServiceState st)
{
if (m_disable)
return;
if (st == ServiceState::Stopping)
{
we_changed_our_state(st);
m_Context->HandleSignal(SIGINT);
}
}
void
SVC_Manager::report_changed_state()
{
if (m_disable)
return;
SetServiceStatus(handle, &_status);
}
void
SVC_Manager::we_changed_our_state(ServiceState st)
{
if (st == ServiceState::Failed)
{
_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
_status.dwServiceSpecificExitCode = 2; // TODO: propagate more info ?
report_changed_state();
}
else if (auto maybe_state = to_win32_state(st))
{
auto new_state = *maybe_state;
assert(_status.dwCurrentState != new_state);
_status.dwCurrentState = new_state;
// tell windows it takes 5s at most to start or stop
if (st == ServiceState::Starting or st == ServiceState::Stopping)
_status.dwCheckPoint++;
else
_status.dwCheckPoint = 0;
report_changed_state();
}
}
SVC_Manager _manager{};
I_SystemLayerManager* const service_manager = &_manager;
} // namespace llarp::sys

@ -0,0 +1,24 @@
#pragma once
#include <llarp/util/service_manager.hpp>
namespace llarp::sys
{
class SVC_Manager : public I_SystemLayerManager
{
SERVICE_STATUS _status;
public:
SERVICE_STATUS_HANDLE handle;
SVC_Manager();
void
system_changed_our_state(ServiceState st) override;
void
report_changed_state() override;
void
we_changed_our_state(ServiceState st) override;
};
} // namespace llarp::sys

@ -2,6 +2,7 @@
#include <catch2/catch.hpp> #include <catch2/catch.hpp>
#include <util/logging.hpp> #include <util/logging.hpp>
#include <util/service_manager.hpp>
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
@ -23,6 +24,7 @@ startWinsock()
int int
main(int argc, char* argv[]) main(int argc, char* argv[])
{ {
llarp::sys::service_manager->disable();
llarp::log::reset_level(llarp::log::Level::off); llarp::log::reset_level(llarp::log::Level::off);
#ifdef _WIN32 #ifdef _WIN32

Loading…
Cancel
Save