Files
SimpleRemoter/server/2015Remote/ServerServiceWrapper.cpp
2026-04-19 22:55:21 +02:00

636 lines
21 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "stdafx.h"
#include "ServerServiceWrapper.h"
#include "ServerSessionMonitor.h"
#include "CrashReport.h"
#include <stdio.h>
#include <winsvc.h>
#include "2015Remote.h"
// 静态变量
static SERVICE_STATUS g_ServiceStatus;
static SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
static HANDLE g_StopEvent = INVALID_HANDLE_VALUE;
// 前向声明
static void WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
static void WINAPI ServiceCtrlHandler(DWORD ctrlCode);
// 代理启动回调:记录启动次数
static void OnAgentStart(DWORD processId, DWORD sessionId)
{
// 递增启动次数
int startCount = THIS_CFG.GetInt(CFG_CRASH_SECTION, CFG_CRASH_STARTS, 0) + 1;
THIS_CFG.SetInt(CFG_CRASH_SECTION, CFG_CRASH_STARTS, startCount);
char buf[128];
sprintf_s(buf, sizeof(buf), "Agent started: PID=%d, Session=%d, totalStarts=%d",
(int)processId, (int)sessionId, startCount);
Mprintf(buf);
}
// 代理退出回调:累计运行时间(用于 MTBF 计算)
static void OnAgentExit(DWORD exitCode, ULONGLONG runtimeMs)
{
// 累加总运行时间
// 注意:使用字符串存储 64 位整数,避免 GetInt/SetInt 的 32 位限制
char totalStr[32];
ULONGLONG totalRuntime = 0;
std::string storedTotal = THIS_CFG.GetStr(CFG_CRASH_SECTION, CFG_CRASH_TOTAL_RUN_MS, "0");
totalRuntime = _strtoui64(storedTotal.c_str(), NULL, 10);
totalRuntime += runtimeMs;
sprintf_s(totalStr, sizeof(totalStr), "%llu", totalRuntime);
THIS_CFG.SetStr(CFG_CRASH_SECTION, CFG_CRASH_TOTAL_RUN_MS, totalStr);
// 格式化运行时间
char runtimeStr[64];
FormatRuntime(totalRuntime, runtimeStr, sizeof(runtimeStr));
// 计算 MTBF如果有崩溃记录
int crashCount = THIS_CFG.GetInt(CFG_CRASH_SECTION, CFG_CRASH_COUNT, 0);
int startCount = THIS_CFG.GetInt(CFG_CRASH_SECTION, CFG_CRASH_STARTS, 0);
char buf[256];
if (crashCount > 0) {
ULONGLONG mtbf = CalculateMTBF(totalRuntime, crashCount);
char mtbfStr[64];
FormatRuntime(mtbf, mtbfStr, sizeof(mtbfStr));
double failureRate = CalculateFailureRate(crashCount, startCount);
sprintf_s(buf, sizeof(buf),
"Agent exited: code=0x%08X, runtime=%llums, totalRuntime=%s, MTBF=%s, failureRate=%.2f%%",
exitCode, runtimeMs, runtimeStr, mtbfStr, failureRate * 100);
} else {
sprintf_s(buf, sizeof(buf),
"Agent exited: code=0x%08X, runtime=%llums, totalRuntime=%s (no crashes yet)",
exitCode, runtimeMs, runtimeStr);
}
Mprintf(buf);
}
// 崩溃统计回调:记录崩溃次数、时间和退出代码
static void OnAgentCrash(DWORD exitCode, ULONGLONG runtimeMs)
{
// 递增总崩溃次数
int totalCrashes = THIS_CFG.GetInt(CFG_CRASH_SECTION, CFG_CRASH_COUNT, 0) + 1;
THIS_CFG.SetInt(CFG_CRASH_SECTION, CFG_CRASH_COUNT, totalCrashes);
// 记录最后崩溃时间
char timeStr[32];
SYSTEMTIME st;
GetLocalTime(&st);
sprintf_s(timeStr, sizeof(timeStr), "%04d-%02d-%02d %02d:%02d:%02d",
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
THIS_CFG.SetStr(CFG_CRASH_SECTION, CFG_CRASH_LAST_TIME, timeStr);
// 记录退出代码
char exitCodeStr[64];
const char* desc = GetExitCodeDescription(exitCode);
if (desc) {
sprintf_s(exitCodeStr, sizeof(exitCodeStr), "0x%08X (%s)", exitCode, desc);
} else {
sprintf_s(exitCodeStr, sizeof(exitCodeStr), "0x%08X", exitCode);
}
THIS_CFG.SetStr(CFG_CRASH_SECTION, CFG_CRASH_LAST_CODE, exitCodeStr);
// 记录运行时间(毫秒)- 使用字符串存储 64 位值
char runtimeStr[32];
sprintf_s(runtimeStr, sizeof(runtimeStr), "%llu", runtimeMs);
THIS_CFG.SetStr(CFG_CRASH_SECTION, CFG_CRASH_LAST_RUN_MS, runtimeStr);
char buf[256];
sprintf_s(buf, sizeof(buf), "Agent crash recorded: total=%d, time=%s, exitCode=%s, runtime=%llums",
totalCrashes, timeStr, exitCodeStr, runtimeMs);
Mprintf(buf);
}
// 崩溃窗口状态变化回调:持久化崩溃窗口状态
static void OnCrashWindowChange(int crashCount, ULONGLONG firstCrashTime)
{
THIS_CFG.SetInt(CFG_CRASH_SECTION, CFG_CRASH_WIN_COUNT, crashCount);
// 使用字符串存储 64 位时间戳
char timeStr[32];
sprintf_s(timeStr, sizeof(timeStr), "%llu", firstCrashTime);
THIS_CFG.SetStr(CFG_CRASH_SECTION, CFG_CRASH_WIN_START, timeStr);
char buf[128];
sprintf_s(buf, sizeof(buf), "Crash window state saved: count=%d, startTime=%llu", crashCount, firstCrashTime);
Mprintf(buf);
}
// 崩溃保护回调:写入保护标志
// 注意:不在这里停止服务,由 MonitorLoop 检测 crashProtected 后自动退出
static void OnAgentCrashProtection(void)
{
THIS_CFG.SetInt(CFG_CRASH_SECTION, CFG_CRASH_PROTECTED, 1);
// 切换到正常模式,避免用户无法启动程序
THIS_CFG.SetInt("settings", "RunNormal", 1);
// 清除崩溃窗口状态(保护已触发,不需要再保持窗口状态)
THIS_CFG.SetInt(CFG_CRASH_SECTION, CFG_CRASH_WIN_COUNT, 0);
THIS_CFG.SetStr(CFG_CRASH_SECTION, CFG_CRASH_WIN_START, "0");
Mprintf("Crash protection triggered: switched to normal mode");
}
BOOL ServerService_CheckStatus(BOOL* registered, BOOL* running,
char* exePath, size_t exePathSize)
{
*registered = FALSE;
*running = FALSE;
if (exePath && exePathSize > 0) {
exePath[0] = '\0';
}
// 打开 SCM
SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
if (!hSCM) {
return FALSE;
}
// 打开服务
SC_HANDLE hService = OpenServiceA(
hSCM,
SERVER_SERVICE_NAME,
SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
if (!hService) {
CloseServiceHandle(hSCM);
return FALSE; // 未注册
}
*registered = TRUE;
// 获取服务状态
SERVICE_STATUS_PROCESS ssp;
DWORD bytesNeeded = 0;
memset(&ssp, 0, sizeof(ssp));
if (QueryServiceStatusEx(
hService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssp,
sizeof(SERVICE_STATUS_PROCESS),
&bytesNeeded)) {
*running = (ssp.dwCurrentState == SERVICE_RUNNING);
}
// 获取 EXE 路径
if (exePath && exePathSize > 0) {
DWORD bufSize = 0;
QueryServiceConfigA(hService, NULL, 0, &bufSize);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
LPQUERY_SERVICE_CONFIGA pConfig = (LPQUERY_SERVICE_CONFIGA)malloc(bufSize);
if (pConfig) {
if (QueryServiceConfigA(hService, pConfig, bufSize, &bufSize)) {
strncpy_s(exePath, exePathSize, pConfig->lpBinaryPathName, _TRUNCATE);
}
free(pConfig);
}
}
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return TRUE;
}
int ServerService_StartSimple(void)
{
// 打开SCM
SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
if (!hSCM) {
return (int)GetLastError();
}
// 打开服务并启动
SC_HANDLE hService = OpenServiceA(hSCM, SERVER_SERVICE_NAME, SERVICE_START);
if (!hService) {
int err = (int)GetLastError();
CloseServiceHandle(hSCM);
return err;
}
// 启动服务
BOOL ok = StartServiceA(hService, 0, NULL);
int err = ok ? ERROR_SUCCESS : (int)GetLastError();
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return err;
}
int ServerService_Run(void)
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = (LPSTR)SERVER_SERVICE_NAME;
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
Mprintf("========================================");
Mprintf("ServerService_Run() called");
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) {
DWORD err = GetLastError();
char buffer[256];
sprintf_s(buffer, sizeof(buffer), "StartServiceCtrlDispatcher failed: %d", (int)err);
Mprintf(buffer);
return (int)err;
}
return ERROR_SUCCESS;
}
int ServerService_Stop(void)
{
// 打开SCM
SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
if (!hSCM) {
return (int)GetLastError();
}
// 打开服务
SC_HANDLE hService = OpenServiceA(hSCM, SERVER_SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS);
if (!hService) {
int err = (int)GetLastError();
CloseServiceHandle(hSCM);
return err;
}
// 查询当前状态
SERVICE_STATUS status;
if (!QueryServiceStatus(hService, &status)) {
int err = (int)GetLastError();
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return err;
}
// 如果服务未运行,直接返回成功
if (status.dwCurrentState == SERVICE_STOPPED) {
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return ERROR_SUCCESS;
}
// 发送停止控制命令
if (!ControlService(hService, SERVICE_CONTROL_STOP, &status)) {
DWORD err = GetLastError();
if (err != ERROR_SERVICE_NOT_ACTIVE) {
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return (int)err;
}
}
// 等待服务停止最多30秒
int waitCount = 0;
while (status.dwCurrentState != SERVICE_STOPPED && waitCount < 30) {
Sleep(1000);
waitCount++;
if (!QueryServiceStatus(hService, &status)) {
break;
}
}
int result = (status.dwCurrentState == SERVICE_STOPPED) ? ERROR_SUCCESS : ERROR_TIMEOUT;
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
return result;
}
static void WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{
(void)argc;
(void)argv;
Mprintf("ServiceMain() called");
g_StatusHandle = RegisterServiceCtrlHandler(
SERVER_SERVICE_NAME,
ServiceCtrlHandler
);
if (g_StatusHandle == NULL) {
Mprintf("RegisterServiceCtrlHandler failed");
return;
}
ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
g_ServiceStatus.dwWaitHint = 0;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
g_StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_StopEvent == NULL) {
Mprintf("CreateEvent failed");
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
return;
}
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
Mprintf("Service is now running");
HANDLE hThread = CreateThread(NULL, 0, ServerService_WorkerThread, NULL, 0, NULL);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
SAFE_CLOSE_HANDLE(hThread);
}
SAFE_CLOSE_HANDLE(g_StopEvent);
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
Mprintf("Service stopped");
}
static void WINAPI ServiceCtrlHandler(DWORD ctrlCode)
{
switch (ctrlCode) {
case SERVICE_CONTROL_STOP:
Mprintf("SERVICE_CONTROL_STOP received");
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;
g_ServiceStatus.dwWaitHint = 0;
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
SetEvent(g_StopEvent);
break;
case SERVICE_CONTROL_INTERROGATE:
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
break;
default:
break;
}
}
// 服务工作线程
DWORD WINAPI ServerService_WorkerThread(LPVOID lpParam)
{
(void)lpParam;
int heartbeatCount = 0;
char buf[128];
Mprintf("========================================");
Mprintf("Worker thread started");
Mprintf("Service will launch Yama GUI in user sessions");
// 读取配置:运行模式 (RunNormal: 0=服务+SYSTEM, 1=普通模式, 2=服务+User)
int runNormal = THIS_CFG.GetInt("settings", "RunNormal", 0);
// 初始化会话监控器
ServerSessionMonitor monitor;
ServerSessionMonitor_Init(&monitor);
monitor.runAsUser = (runNormal == 2);
// 从配置恢复崩溃窗口状态
int savedCrashCount = THIS_CFG.GetInt(CFG_CRASH_SECTION, CFG_CRASH_WIN_COUNT, 0);
std::string savedStartStr = THIS_CFG.GetStr(CFG_CRASH_SECTION, CFG_CRASH_WIN_START, "0");
ULONGLONG savedFirstCrashTime = _strtoui64(savedStartStr.c_str(), NULL, 10);
ULONGLONG now = GetTickCount64();
if (savedCrashCount > 0 && savedFirstCrashTime > 0) {
// 检查是否仍在窗口期内
// 注意GetTickCount64() 在系统重启后会重置,所以如果 savedFirstCrashTime > now说明系统重启过
if (savedFirstCrashTime <= now && (now - savedFirstCrashTime) <= CRASH_WINDOW_MS) {
// 仍在窗口期内,恢复状态
monitor.crashCount = savedCrashCount;
monitor.firstCrashTime = savedFirstCrashTime;
sprintf_s(buf, sizeof(buf), "Crash window state restored: count=%d, elapsed=%llums",
savedCrashCount, now - savedFirstCrashTime);
Mprintf(buf);
} else {
// 窗口期已过或系统重启,清除状态
THIS_CFG.SetInt(CFG_CRASH_SECTION, CFG_CRASH_WIN_COUNT, 0);
THIS_CFG.SetStr(CFG_CRASH_SECTION, CFG_CRASH_WIN_START, "0");
Mprintf("Crash window expired or system rebooted, state cleared");
}
}
// 设置回调函数
monitor.onAgentStart = OnAgentStart;
monitor.onAgentExit = OnAgentExit;
monitor.onCrash = OnAgentCrash;
monitor.onCrashWindowChange = OnCrashWindowChange;
monitor.onCrashProtection = OnAgentCrashProtection;
if (!ServerSessionMonitor_Start(&monitor)) {
Mprintf("ERROR: Failed to start session monitor");
ServerSessionMonitor_Cleanup(&monitor);
return ERROR_SERVICE_SPECIFIC_ERROR;
}
Mprintf("Session monitor started successfully");
Mprintf("Yama GUI will be launched automatically in user sessions");
// 主循环,等待停止信号或监控器停止
// 使用 1 秒超时以快速响应监控器停止
while (WaitForSingleObject(g_StopEvent, 1000) != WAIT_OBJECT_0) {
// 检查监控器是否已停止(例如代理以 EXIT_MANUAL_STOP 退出或崩溃保护触发)
if (!monitor.running) {
Mprintf("Monitor stopped - exiting worker thread");
break;
}
heartbeatCount++;
if (heartbeatCount % 60 == 0) { // 每60秒记录一次1秒 * 60 = 60秒
sprintf_s(buf, sizeof(buf), "Service heartbeat - uptime: %d minutes", heartbeatCount / 60);
Mprintf(buf);
}
}
Mprintf("Stop signal received");
Mprintf("Stopping session monitor...");
ServerSessionMonitor_Stop(&monitor);
ServerSessionMonitor_Cleanup(&monitor);
Mprintf("Worker thread exiting");
Mprintf("========================================");
return ERROR_SUCCESS;
}
BOOL ServerService_Install(void)
{
SC_HANDLE schSCManager = OpenSCManager(
NULL,
NULL,
SC_MANAGER_ALL_ACCESS
);
if (schSCManager == NULL) {
Mprintf("ERROR: OpenSCManager failed (%d)\n", (int)GetLastError());
Mprintf("Please run as Administrator\n");
return FALSE;
}
char szPath[MAX_PATH];
if (!GetModuleFileNameA(NULL, szPath, MAX_PATH)) {
Mprintf("ERROR: GetModuleFileName failed (%d)\n", (int)GetLastError());
CloseServiceHandle(schSCManager);
return FALSE;
}
// 添加 -service 参数
char szPathWithArg[MAX_PATH + 32];
sprintf_s(szPathWithArg, sizeof(szPathWithArg), "\"%s\" -service", szPath);
Mprintf("Installing service...\n");
Mprintf("Executable path: %s\n", szPathWithArg);
SC_HANDLE schService = CreateServiceA(
schSCManager,
SERVER_SERVICE_NAME,
SERVER_SERVICE_DISPLAY,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
szPathWithArg,
NULL, NULL, NULL, NULL, NULL
);
if (schService == NULL) {
DWORD err = GetLastError();
if (err == ERROR_SERVICE_EXISTS) {
Mprintf("INFO: Service already exists\n");
schService = OpenServiceA(schSCManager, SERVER_SERVICE_NAME, SERVICE_ALL_ACCESS);
if (schService) {
Mprintf("SUCCESS: Service is already installed\n");
CloseServiceHandle(schService);
}
return TRUE;
} else if (err == ERROR_ACCESS_DENIED) {
Mprintf("ERROR: Access denied. Please run as Administrator\n");
} else {
Mprintf("ERROR: CreateService failed (%d)\n", (int)err);
}
CloseServiceHandle(schSCManager);
return FALSE;
}
Mprintf("SUCCESS: Service created successfully\n");
// 设置服务描述
SERVICE_DESCRIPTION sd;
sd.lpDescription = (LPSTR)SERVER_SERVICE_DESC;
ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sd);
// 立即启动服务
DWORD err = 0;
Mprintf("Starting service...\n");
if (StartServiceA(schService, 0, NULL)) {
Mprintf("SUCCESS: Service started successfully\n");
Sleep(2000);
SERVICE_STATUS status;
if (QueryServiceStatus(schService, &status)) {
if (status.dwCurrentState == SERVICE_RUNNING) {
Mprintf("SUCCESS: Service is running\n");
} else {
Mprintf("WARNING: Service state: %d\n", (int)status.dwCurrentState);
}
}
} else {
err = GetLastError();
if (err == ERROR_SERVICE_ALREADY_RUNNING) {
Mprintf("INFO: Service is already running\n");
err = 0;
} else {
Mprintf("WARNING: StartService failed (%d)\n", (int)err);
}
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return err == 0;
}
BOOL ServerService_Uninstall(void)
{
SC_HANDLE schSCManager = OpenSCManager(
NULL,
NULL,
SC_MANAGER_ALL_ACCESS
);
if (schSCManager == NULL) {
Mprintf("ERROR: OpenSCManager failed (%d)\n", (int)GetLastError());
return FALSE;
}
SC_HANDLE schService = OpenServiceA(
schSCManager,
SERVER_SERVICE_NAME,
SERVICE_STOP | DELETE | SERVICE_QUERY_STATUS
);
if (schService == NULL) {
Mprintf("ERROR: OpenService failed (%d)\n", (int)GetLastError());
CloseServiceHandle(schSCManager);
return FALSE;
}
// 停止服务
SERVICE_STATUS status;
Mprintf("Stopping service...\n");
if (ControlService(schService, SERVICE_CONTROL_STOP, &status)) {
Mprintf("Waiting for service to stop");
Sleep(1000);
int waitCount = 0;
while (QueryServiceStatus(schService, &status) && waitCount < 30) {
if (status.dwCurrentState == SERVICE_STOP_PENDING) {
Mprintf(".");
Sleep(1000);
waitCount++;
} else {
break;
}
}
Mprintf("\n");
} else {
DWORD err = GetLastError();
if (err != ERROR_SERVICE_NOT_ACTIVE) {
Mprintf("WARNING: Failed to stop service (%d)\n", (int)err);
}
}
BOOL r = FALSE;
// 删除服务
Mprintf("Deleting service...\n");
if (DeleteService(schService)) {
Mprintf("SUCCESS: Service uninstalled successfully\n");
r = TRUE;
} else {
Mprintf("ERROR: DeleteService failed (%d)\n", (int)GetLastError());
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return r;
}