#define INITGUID
#define __MODULE__ "sentinal"
#include "zlib.h"
#include <windows.h>
#include <windowsx.h>
#include <dplobby.h>
#include <stdlib.h>
#include <memory.h>
#include "srvdbg.h"
#include "Sentinal.h"
#include "sentmsg.h"
#include "config.h"
#include "dplaychk.h"
DEFINE_GUID(FEDSRV_GUID,
0x81662310, 0xfcb4, 0x11d0, 0xa8, 0x8a, 0x0, 0x60, 0x97, 0xb5, 0x8f, 0xbf);
#define _INTERNET_PAGING
#ifdef _INTERNET_PAGING
#include <wininet.h>
#endif typedef enum
{
karg_fTimeout,
karg_fWantInt3,
karg_dwPingInterval,
karg_szPagerNotificationURL,
karg_szMonitorServers,
} SENTINAL_ARGS;
ConfigManager* g_pCfgMgr;
const char g_szSvcName[] = "Sentinal";
SERVICE_STATUS_HANDLE g_ssh = NULL;
HINSTANCE g_hInst = NULL;
void StartServerTerminateThread();
DWORD WINAPI ServerTerminateThread(DWORD dwUnused);
void SetSvcStatus(DWORD state, DWORD exitcode);
DWORD SendAPage(char* sz, ...);
#ifdef _INTERNET_PAGING
HINTERNET g_hinetSession;
typedef HINTERNET (WINAPI* PFNINTERNETOPENURL)(HINTERNET, LPCSTR, LPCSTR, DWORD, DWORD, DWORD);
typedef BOOL (WINAPI* PFNINTERNETGETLASTRESPONSEINFO)(LPDWORD, LPSTR, LPDWORD);
typedef BOOL (WINAPI* PFNINTERNETCLOSEHANDLE)(HINTERNET);
typedef HINTERNET (WINAPI* PFNINTERNETOPEN)(LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD);
PFNINTERNETOPENURL pfnInternetOpenUrl;
PFNINTERNETGETLASTRESPONSEINFO pfnInternetGetLastResponseInfo;
PFNINTERNETCLOSEHANDLE pfnInternetCloseHandle;
PFNINTERNETOPEN pfnInternetOpen;
#endif HINSTANCE g_hMessage;
char g_szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
char g_szServerStatus[16];
HANDLE g_hEventShutdown;
DWORD PingThreadProc(LPVOID lpv)
{
HANDLE hEventShutdown = (HANDLE)lpv;
DWORD dwPingInterval = 15000;
char szServers[MAX_PATH + 1];
char *psz = NULL;
int nServers = 0;
g_pCfgMgr->GetConfigDWORD(kCompId_Sentinal, karg_dwPingInterval, (DWORD*)&dwPingInterval);
g_pCfgMgr->GetConfigString(kCompId_Sentinal, karg_szMonitorServers, szServers, sizeof(szServers)-1);
for (psz = szServers; *psz; psz++)
if (*psz==';' || *psz==',')
{
*psz = '\0';
nServers++;
}
*(psz+1) = '\0';
if (nServers > 16)
nServers = 16;
memset(g_szServerStatus, 'U', sizeof(g_szServerStatus));
HRESULT hr = CoInitialize(NULL);
BOOL bFirstTime = TRUE;
while (WAIT_TIMEOUT == WaitForSingleObject(hEventShutdown, bFirstTime ? 10000 : dwPingInterval))
{
bFirstTime = FALSE;
int nServer = 0;
for(psz = szServers; *psz && nServer<nServers; psz += strlen(psz)+1, nServer++)
{
CDplayServerChecker dsc;
dsc.SetServer(psz);
BOOL rc = dsc.ServerConnectionAlive();
if (!rc)
{
if (g_szServerStatus[nServer]=='U')
{
g_szServerStatus[nServer] = 'D';
SRVDBG_ReportEvent(SRVDBG_ERROR_TYPE, SENTINAL_MONITORED_SERVER_DOWN, psz, dsc.m_szMsg);
#ifdef _INTERNET_PAGING
SendAPage("Monitored Server Failure", psz, dsc.m_szMsg);
#endif _INTERNET_PAGING
}
}
else
g_szServerStatus[nServer] = 'U';
}
}
return(0);
}
#ifdef _INTERNET_PAGING
DWORD SendAPage(char* sz, ...) {
LPTSTR rgszStrings[5];
va_list vl;
va_start(vl, sz);
rgszStrings[0] = sz;
rgszStrings[1] = va_arg(vl, LPTSTR);
rgszStrings[2] = va_arg(vl, LPTSTR);
rgszStrings[3] = va_arg(vl, LPTSTR);
rgszStrings[4] = va_arg(vl, LPTSTR);
va_end(vl);
char szPagerNotificationURL[MAX_PATH + 1];
g_pCfgMgr->GetConfigString(kCompId_Sentinal, karg_szPagerNotificationURL, szPagerNotificationURL, sizeof(szPagerNotificationURL)-1);
char* szFormat = szPagerNotificationURL;
{
if (pfnInternetOpenUrl && pfnInternetGetLastResponseInfo && pfnInternetCloseHandle)
{
char rgchBuf[1024];
DWORD cbBuf = sizeof(rgchBuf);
DWORD cch = FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY, szFormat, 0, 0, rgchBuf, sizeof(rgchBuf) - 1, rgszStrings);
HINTERNET hinetHTTPSession = (*pfnInternetOpenUrl)(g_hinetSession, rgchBuf, NULL, 0, INTERNET_FLAG_RELOAD, 0);
if (NULL == hinetHTTPSession)
{
char szMsg[256];
wsprintf(szMsg, "%08x (%d)", GetLastError(), GetLastError());
SRVDBG_ReportEvent(SRVDBG_ERROR_TYPE, SENTINAL_INTERNETOPENURL, szMsg);
return 1;
}
DWORD dwErr;
BOOL rc = (*pfnInternetGetLastResponseInfo)(&dwErr, rgchBuf, &cbBuf);
if (!rc)
{
char szMsg[256];
wsprintf(szMsg, "%08x (%d)", GetLastError(), GetLastError());
SRVDBG_ReportEvent(SRVDBG_ERROR_TYPE, SENTINAL_INTERNETGETLASTRESPONSEINFO, szMsg);
}
(*pfnInternetCloseHandle)(hinetHTTPSession);
}
}
return(0);
}
#endif void LoadSettings()
{
g_pCfgMgr = new ConfigManager;
ZAssert(g_pCfgMgr); ZAssert(g_pCfgMgr->Init());
static const ConfigInfo rgCfg[] =
{
{ "fTimeout", kConfigType_DWORD, sizeof(DWORD), TRUE, 0 },
{ "fWantInt3", kConfigType_DWORD, sizeof(DWORD), TRUE, 0 },
{ "dwPingInterval", kConfigType_DWORD, sizeof(DWORD), FALSE, 0 },
{ "szPagerNotificationURL", kConfigType_SZ, MAX_PATH + 1, TRUE, (DWORD) "" },
{ "szMonitorServers", kConfigType_SZ, MAX_PATH + 1, TRUE, (DWORD) "" },
};
g_pCfgMgr->LoadConfig(kCompId_Sentinal, rgCfg, sizeof(rgCfg) / sizeof(rgCfg[0]));
}
HRESULT pascal Sentinal_Init()
{
int iCon = 0;
HRESULT hr = S_OK;
SRVDBG_Init("Sentinal", NULL);
SRVDBG_Info("Initialize");
LoadSettings();
hr = CoInitialize(NULL);
DWORD cbBuf = sizeof(g_szComputerName);
GetComputerName(g_szComputerName, &cbBuf);
#ifdef _INTERNET_PAGING
char szPagerNotificationURL[MAX_PATH + 1];
g_pCfgMgr->GetConfigString(kCompId_Sentinal, karg_szPagerNotificationURL, szPagerNotificationURL, sizeof(szPagerNotificationURL)-1);
if (szPagerNotificationURL[0])
{
HINSTANCE hinstWininet = LoadLibrary("wininet.dll");
pfnInternetOpen = (PFNINTERNETOPEN)GetProcAddress(hinstWininet, "InternetOpenA");
pfnInternetGetLastResponseInfo = (PFNINTERNETGETLASTRESPONSEINFO)GetProcAddress(hinstWininet, "InternetGetLastResponseInfoA");
pfnInternetOpenUrl = (PFNINTERNETOPENURL)GetProcAddress(hinstWininet, "InternetOpenUrlA");
pfnInternetCloseHandle = (PFNINTERNETCLOSEHANDLE)GetProcAddress(hinstWininet, "InternetCloseHandle");
if (pfnInternetOpen)
{
g_hinetSession = (*pfnInternetOpen)((char*)g_szSvcName, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (NULL == g_hinetSession)
{
SRVDBG_Info("InternetOpen");
}
}
}
#endif HANDLE hEventShutdown = CreateEvent(NULL, FALSE, FALSE, NULL); DWORD idPingThread = 0;
HANDLE hThreadPing = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PingThreadProc, hEventShutdown, 0, &idPingThread);
hr = (hThreadPing && hEventShutdown) ? S_OK : E_FAIL;
return hr;
}
HRESULT pascal Sentinal_Terminate(void)
{
SRVDBG_Info("Terminate");
SRVDBG_Terminate();
return(S_OK);
}
void SetSvcStatus(
DWORD state,
DWORD exitcode
)
{
if (g_ssh)
{
SERVICE_STATUS ss;
static DWORD s_cp = 1;
ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ss.dwCurrentState = state;
ss.dwControlsAccepted = SERVICE_ACCEPT_STOP; ss.dwWin32ExitCode = exitcode;
ss.dwServiceSpecificExitCode = 0;
switch (state)
{
case SERVICE_RUNNING:
case SERVICE_STOPPED:
case SERVICE_PAUSED:
ss.dwCheckPoint = s_cp++;
ss.dwWaitHint = 1000;
break;
case SERVICE_START_PENDING:
ss.dwCheckPoint = s_cp++;
ss.dwWaitHint = 30000; break;
case SERVICE_STOP_PENDING:
ss.dwCheckPoint = s_cp++;
ss.dwWaitHint = 30000; break;
default:
ss.dwCheckPoint = 0;
ss.dwWaitHint = 0;
break;
}
SetServiceStatus(g_ssh,&ss);
}
}
void StartServerTerminateThread()
{
DWORD dwId;
HANDLE hthrPending = CreateThread(NULL, 8192, (LPTHREAD_START_ROUTINE) ServerTerminateThread, 0, 0, &dwId);
CloseHandle(hthrPending);
}
DWORD WINAPI ServerTerminateThread(DWORD dwUnused)
{
Sentinal_Terminate();
SetSvcStatus(SERVICE_STOPPED,0);
return 0;
}
void WINAPI ServiceControl(DWORD dwCode)
{
switch (dwCode)
{
case SERVICE_CONTROL_STOP:
SetSvcStatus(SERVICE_STOP_PENDING,0);
StartServerTerminateThread();
break;
case SERVICE_CONTROL_PAUSE:
break;
case SERVICE_CONTROL_CONTINUE:
break;
case SERVICE_CONTROL_SHUTDOWN:
break;
case SERVICE_CONTROL_INTERROGATE:
break;
}
}
void WINAPI ServiceMain(
DWORD dwArgc,
LPSTR *lpszArgv)
{
HRESULT f;
g_ssh = RegisterServiceCtrlHandler(g_szSvcName,ServiceControl);
if (!g_ssh)
{
SetSvcStatus(SERVICE_STOPPED,GetLastError());
return;
}
SetSvcStatus(SERVICE_START_PENDING,NO_ERROR);
f = Sentinal_Init();
if (f==S_OK)
SetSvcStatus(SERVICE_RUNNING,NO_ERROR);
else
SetSvcStatus(SERVICE_STOPPED,GetLastError());
}
BOOL InstallService()
{
SC_HANDLE schMgr;
SC_HANDLE schSvc;
char szPath[512];
schMgr = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (!schMgr)
{
printf("Unable to open SCManager. Service not installed.\n");
return FALSE;
}
GetModuleFileName(NULL,szPath,sizeof(szPath));
schSvc = CreateService(schMgr,
g_szSvcName,
"MS Sentinal Server Monitor",
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
szPath,
NULL,
NULL,
NULL,
NULL,
NULL);
if (!schSvc)
{
printf("Unable to create service [0x%08x]. Service not installed.\n", GetLastError());
CloseServiceHandle(schMgr);
return FALSE;
}
CloseServiceHandle(schSvc);
CloseServiceHandle(schMgr);
printf("%s service installed.\n",g_szSvcName);
return TRUE;
}
BOOL RemoveService(void)
{
SC_HANDLE schMgr;
SC_HANDLE schSvc;
SERVICE_STATUS ss;
schMgr = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (!schMgr)
{
printf("Unable to open SCManager. Service not removed.\n");
return FALSE;
}
schSvc = OpenService(schMgr,g_szSvcName,SERVICE_ALL_ACCESS);
if (!schSvc)
{
printf("Unable to open %s service. Service not removed.\n",g_szSvcName);
CloseServiceHandle(schMgr);
return FALSE;
}
QueryServiceStatus(schSvc,&ss);
if (ss.dwCurrentState!=SERVICE_STOPPED)
{
printf("Unable to remove %s service while it is running.\n",g_szSvcName);
CloseServiceHandle(schSvc);
CloseServiceHandle(schMgr);
return FALSE;
}
if (DeleteService(schSvc))
printf("%s service removed.\n",g_szSvcName);
else
printf("Unable to delete % service.\n",g_szSvcName);
CloseServiceHandle(schSvc);
CloseServiceHandle(schMgr);
return TRUE;
}
VOID RunAsExecutable()
{
HRESULT f;
printf("Microsoft (R) Sentinal Server Monitoring Service\n");
printf("Copyright (C) Microsoft Corp 1998. All rights reserved.\n\n");
printf("Running as an executable.\n");
printf("Initializing...");
f = Sentinal_Init();
if (f==S_OK)
{
HANDLE hConsole;
DWORD cbr;
char c;
printf("\rType 'Q' to exit.\n");
hConsole = GetStdHandle(STD_INPUT_HANDLE);
SetConsoleMode(hConsole,0);
while (ReadConsole(hConsole,&c,1,&cbr,NULL) && (int)CharUpper((LPSTR)c)!='Q')
;
Sentinal_Terminate();
}
else
{
printf("\rInitialization failed. (%d)\n",f);
}
}
int __cdecl main(int argc, char *argv[])
{
SERVICE_TABLE_ENTRY rgSTE[] =
{
{ (char *)g_szSvcName, (LPSERVICE_MAIN_FUNCTION)ServiceMain },
{ NULL, NULL }
};
bool fShowUsage = false;
g_hInst = GetModuleHandle(NULL);
if (argc>1)
{
if (*argv[1]=='-' || *argv[1]=='/')
{
if (!lstrcmpi("install",argv[1]+1))
InstallService();
else if (!lstrcmpi("remove",argv[1]+1))
RemoveService();
else if (!lstrcmpi("debug",argv[1]+1))
RunAsExecutable();
else
fShowUsage = true;
}
else
fShowUsage = true;
if (fShowUsage)
{
printf("Microsoft (R) Sentinal Server Monitoring Service\n");
printf("Copyright (C) Microsoft Corp 1998. All rights reserved.\n\n");
printf("usage: %s -install install the service\n",argv[0]);
printf(" %s -remove remove the service\n",argv[0]);
printf(" %s -debug run the service as an EXE\n",argv[0]);
printf("\nTo start this service when installed: net start %s\n",g_szSvcName);
}
}
else {
#ifdef WIN95
RunAsExecutable();
#else
if (!StartServiceCtrlDispatcher(rgSTE))
SRVDBG_Error("StartServiceCtrlDispatcher failed.");
#endif
}
return 0;
}