in minifi_main/MiNiFiWindowsService.cpp [51:247]
void RunAsServiceIfNeeded() {
static const int WAIT_TIME_EXE_TERMINATION = 5000;
static const int WAIT_TIME_EXE_RESTART = 60000;
static SERVICE_STATUS s_serviceStatus;
static SERVICE_STATUS_HANDLE s_statusHandle;
static HANDLE s_hProcess;
static HANDLE s_hEvent;
static char serviceNameMutable[] = SERVICE_NAME;
static auto Log = []() {
static std::shared_ptr<minifi::core::logging::Logger> s_logger = minifi::core::logging::LoggerConfiguration::getConfiguration().getLogger("service");
return s_logger;
};
SERVICE_TABLE_ENTRY serviceTable[] = {
{
serviceNameMutable,
[](DWORD argc, LPTSTR *argv) {
setSyslogLogger();
Log()->log_trace("ServiceCtrlDispatcher");
s_hEvent = CreateEvent(0, TRUE, FALSE, SERVICE_TERMINATION_EVENT_NAME);
if (!s_hEvent) {
Log()->log_error("!CreateEvent lastError {:#x}", GetLastError());
return;
}
s_statusHandle = RegisterServiceCtrlHandler(
SERVICE_NAME,
[](DWORD ctrlCode) {
Log()->log_trace("ServiceCtrlHandler ctrlCode {}", ctrlCode);
if (SERVICE_CONTROL_STOP == ctrlCode) {
Log()->log_trace("ServiceCtrlHandler ctrlCode = SERVICE_CONTROL_STOP");
// Set service status SERVICE_STOP_PENDING.
s_serviceStatus.dwControlsAccepted = 0;
s_serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
s_serviceStatus.dwWin32ExitCode = 0;
if (!SetServiceStatus(s_statusHandle, &s_serviceStatus)) {
Log()->log_error("!SetServiceStatus SERVICE_STOP_PENDING lastError {:#x}", GetLastError());
}
bool exeTerminated = false;
SetEvent(s_hEvent);
Log()->log_info("Wait for exe termination");
switch (auto res = WaitForSingleObject(s_hProcess, WAIT_TIME_EXE_TERMINATION)) {
case WAIT_OBJECT_0:
Log()->log_info("Exe terminated");
exeTerminated = true;
break;
case WAIT_TIMEOUT:
Log()->log_error("WaitForSingleObject timeout {}", WAIT_TIME_EXE_TERMINATION);
break;
default:
Log()->log_error("!WaitForSingleObject return {}", res);
}
if (!exeTerminated) {
Log()->log_info("TerminateProcess");
if (TerminateProcess(s_hProcess, 0)) {
s_serviceStatus.dwControlsAccepted = 0;
s_serviceStatus.dwCurrentState = SERVICE_STOPPED;
s_serviceStatus.dwWin32ExitCode = 0;
if (!SetServiceStatus(s_statusHandle, &s_serviceStatus)) {
Log()->log_error("!SetServiceStatus SERVICE_STOPPED lastError {:#x}", GetLastError());
}
} else {
Log()->log_error("!TerminateProcess lastError {:#x}", GetLastError());
}
}
}
}
);
if (!s_statusHandle) {
Log()->log_error("!RegisterServiceCtrlHandler lastError {:#x}", GetLastError());
return;
}
// Set service status SERVICE_START_PENDING.
ZeroMemory(&s_serviceStatus, sizeof(s_serviceStatus));
s_serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
s_serviceStatus.dwControlsAccepted = 0;
s_serviceStatus.dwCurrentState = SERVICE_START_PENDING;
s_serviceStatus.dwWin32ExitCode = 0;
s_serviceStatus.dwServiceSpecificExitCode = 0;
if (!SetServiceStatus(s_statusHandle, &s_serviceStatus)) {
Log()->log_error("!SetServiceStatus SERVICE_START_PENDING lastError {:#x}", GetLastError());
return;
}
// Set service status SERVICE_RUNNING.
s_serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
s_serviceStatus.dwCurrentState = SERVICE_RUNNING;
s_serviceStatus.dwWin32ExitCode = 0;
if (!SetServiceStatus(s_statusHandle, &s_serviceStatus)) {
Log()->log_error("!SetServiceStatus SERVICE_RUNNING lastError {:#x}", GetLastError());
// Set service status SERVICE_START_PENDING.
s_serviceStatus.dwControlsAccepted = 0;
s_serviceStatus.dwCurrentState = SERVICE_STOPPED;
s_serviceStatus.dwWin32ExitCode = GetLastError();
if (!SetServiceStatus(s_statusHandle, &s_serviceStatus)) {
Log()->log_error("!SetServiceStatus SERVICE_STOPPED lastError {:#x}", GetLastError());
}
return;
}
char filePath[MAX_PATH];
if (!GetModuleFileName(0, filePath, _countof(filePath))) {
Log()->log_error("!GetModuleFileName lastError {:#x}", GetLastError());
return;
}
do {
Log()->log_debug("Start exe path {}", filePath);
STARTUPINFO startupInfo{};
startupInfo.cb = sizeof(startupInfo);
PROCESS_INFORMATION processInformation{};
if (!CreateProcess(filePath, 0, 0, 0, 0, FALSE, 0, 0, &startupInfo, &processInformation)) {
Log()->log_error("!CreateProcess lastError {:#x}", GetLastError());
return;
}
s_hProcess = processInformation.hProcess;
Log()->log_info("{} started", filePath);
auto res = WaitForSingleObject(processInformation.hProcess, INFINITE);
CloseHandle(processInformation.hProcess);
CloseHandle(processInformation.hThread);
if (WAIT_FAILED == res) {
Log()->log_error("!WaitForSingleObject hProcess lastError {:#x}", GetLastError());
} else if (WAIT_OBJECT_0 != res) {
Log()->log_error("!WaitForSingleObject hProcess return {}", res);
}
Log()->log_info("Sleep {} sec before restarting exe", WAIT_TIME_EXE_RESTART/1000);
res = WaitForSingleObject(s_hEvent, WAIT_TIME_EXE_RESTART);
if (WAIT_OBJECT_0 == res) {
Log()->log_info("Service was stopped, exe won't be restarted");
break;
}
if (WAIT_FAILED == res) {
Log()->log_error("!WaitForSingleObject s_hEvent lastError {:#x}", GetLastError());
} if (WAIT_TIMEOUT != res) {
Log()->log_error("!WaitForSingleObject s_hEvent return {}", res);
}
} while (true);
s_serviceStatus.dwControlsAccepted = 0;
s_serviceStatus.dwCurrentState = SERVICE_STOPPED;
s_serviceStatus.dwWin32ExitCode = 0;
if (!SetServiceStatus(s_statusHandle, &s_serviceStatus)) {
Log()->log_error("!SetServiceStatus SERVICE_STOPPED lastError {:#x}", GetLastError());
}
}
},
{0, 0}
};
if (!StartServiceCtrlDispatcher(serviceTable)) {
if (ERROR_FAILED_SERVICE_CONTROLLER_CONNECT == GetLastError()) {
// Run this exe as console.
return;
}
Log()->log_error("!StartServiceCtrlDispatcher lastError {:#x}", GetLastError());
ExitProcess(1);
}
Log()->log_info("Service exit");
ExitProcess(0);
}