123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645 |
- //-------------------------------------------------------------------------
- // sentinal\sentinal.cpp
- //
- // Sentinal server monitoring service
- //
- // Owner: Mark Snyder (MarkSn)
- //
- // Copyright (C) 1998 Mark E. Snyder, Microsoft Corp.
- //-------------------------------------------------------------------------
- #define INITGUID
- #define __MODULE__ "sentinal"
- #include "zlib.h"
- #include <windows.h>
- #include <windowsx.h>
- #include <dplobby.h>
- #include <stdlib.h>
- //#include <commctrl.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 //_INTERNET_PAGING
- // !!! The following enum must match the indices of the items in rgCfg in
- // !!! LoadSettings() !!!
- typedef enum
- {
- karg_fTimeout,
- karg_fWantInt3,
- karg_dwPingInterval,
- karg_szPagerNotificationURL,
- karg_szMonitorServers,
- } SENTINAL_ARGS;
- // instance of class that handles registry config parms
- 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);
- // prototypes
- PFNINTERNETOPENURL pfnInternetOpenUrl;
- PFNINTERNETGETLASTRESPONSEINFO pfnInternetGetLastResponseInfo;
- PFNINTERNETCLOSEHANDLE pfnInternetCloseHandle;
- PFNINTERNETOPEN pfnInternetOpen;
- #endif //_INTERNET_PAGING
- 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));
-
- // Initialize COM library
- 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++)
- {
- // *** HERE IS WHERE YOU CHECK IF THE SERVER IS STILL UP ***
- CDplayServerChecker dsc;
- dsc.SetServer(psz);
- BOOL rc = dsc.ServerConnectionAlive();
- if (!rc)
- {
- if (g_szServerStatus[nServer]=='U')
- {
- g_szServerStatus[nServer] = 'D';
- // send an NT event
- SRVDBG_ReportEvent(SRVDBG_ERROR_TYPE, SENTINAL_MONITORED_SERVER_DOWN, psz, dsc.m_szMsg);
- #ifdef _INTERNET_PAGING
- // send a pager message
- 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, ...) //const 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;
- //for (char* szFormat = szPagerNotificationURL; *szFormat; szFormat += lstrlen(szFormat) + 1)
- {
- 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);
-
- // open a session
- 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 //_INTERNET_PAGING
- /*-------------------------------------------------------------------------
- * LoadSettings
- *-------------------------------------------------------------------------
- * Purpose:
- * Load static server settings
- */
- void LoadSettings()
- {
- g_pCfgMgr = new ConfigManager;
- ZAssert(g_pCfgMgr); // all new's assumed to succeed...
- ZAssert(g_pCfgMgr->Init());
- static const ConfigInfo rgCfg[] =
- {
- // Name Type Max Length Required? Default, if not there
- { "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) "" },
- // !!!! If you add or delete items here, you MUST update the enum SENTINAL_ARGS in CONFIG.H to match
- // !!!! the appropriate index in this array !!!
- };
- g_pCfgMgr->LoadConfig(kCompId_Sentinal, rgCfg, sizeof(rgCfg) / sizeof(rgCfg[0]));
- }
- /*-------------------------------------------------------------------------
- * Sentinal_Init
- *-------------------------------------------------------------------------
- * Purpose:
- * Performs startup tasks and initialization for this service.
- *
- * Side Effects:
- * Lots
- */
- HRESULT pascal Sentinal_Init()
- {
- int iCon = 0;
- HRESULT hr = S_OK;
- SRVDBG_Init("Sentinal", NULL);
- SRVDBG_Info("Initialize");
- LoadSettings();
- // Initialize COM library
- hr = CoInitialize(NULL);
- DWORD cbBuf = sizeof(g_szComputerName);
- GetComputerName(g_szComputerName, &cbBuf);
- #ifdef _INTERNET_PAGING
- // are we going to be doing 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 //_INTERNET_PAGING
- HANDLE hEventShutdown = CreateEvent(NULL, // no security
- FALSE, // auto reset
- FALSE, // initial event reset
- NULL); // no name
- DWORD idPingThread = 0;
- HANDLE hThreadPing = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PingThreadProc, hEventShutdown, 0, &idPingThread);
-
- hr = (hThreadPing && hEventShutdown) ? S_OK : E_FAIL;
- //ZSucceeded(hr);
- return hr;
- }
- /*-------------------------------------------------------------------------
- * ShutDown
- *-------------------------------------------------------------------------
- * Purpose:
- * Cleanup before exiting
- *
- * Side Effects:
- * Everything that was allocated is deallocated and no longer valid
- */
- HRESULT pascal Sentinal_Terminate(void)
- {
- SRVDBG_Info("Terminate");
- SRVDBG_Terminate();
- return(S_OK);
- }
- ////////////////////////////////////////////////////////////////////////
- // SetServiceStatus - more useful version of this function than the NT
- // one.
- //
- //
- 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; // todo: pause
- 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; // we take about 30 seconds to start
- break;
- case SERVICE_STOP_PENDING:
- ss.dwCheckPoint = s_cp++;
- ss.dwWaitHint = 30000; // we take about 30 seconds to shutdown
- 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;
- }
- ////////////////////////////////////////////////////////////////////////
- // ServiceControl
- //
- // Service control handler which is registered with NT (using
- // RegisterServiceCtrlHandler) as the callback for the service events.
- // Right now the service does not support PAUSE/CONTINUE functionality,
- // but this could be added here if required.
- //
- //
- void WINAPI ServiceControl(DWORD dwCode)
- {
- switch (dwCode)
- {
- case SERVICE_CONTROL_STOP:
- // If it can take us a long time to stop our service as we wait for operations to complete,
- // the SCM doesn't like the ServiceControl() function to take a long time, so we spin up another
- // thread to terminate us.
- SetSvcStatus(SERVICE_STOP_PENDING,0);
- StartServerTerminateThread();
- break;
- case SERVICE_CONTROL_PAUSE:
- break;
- case SERVICE_CONTROL_CONTINUE:
- break;
- case SERVICE_CONTROL_SHUTDOWN:
- // System is shutting down. Memory and resources should *not*
- // be freed in this case due to limited time available for
- // shutdown. Instead, only urgent non-volatile (i.e. disk)
- // structures should be flushed.
- break;
- case SERVICE_CONTROL_INTERROGATE:
- break;
- }
- }
- ////////////////////////////////////////////////////////////////////////
- // ServiceMain
- //
- // Pointer to this function is in the SERVICE_TABLE_ENTRY of the
- // array passed to StartServiceCtrlDispatcher.
- 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());
- }
-
- ////////////////////////////////////////////////////////////////////////
- // InstallService - installs this service into the NT service manager
- //
- //
- 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;
- }
- ////////////////////////////////////////////////////////////////////////
- // RemoveService - uninstalls this service from the NT service manager
- //
- //
- 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;
- }
- ////////////////////////////////////////////////////////////////////////
- // RunAsExecutable - for debugging, this service can be run from the
- // command-line.
- //
- //
- 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);
- }
- }
- ////////////////////////////////////////////////////////////////////////
- // main
- //
- // This is the entry point to the process, whether run as a service, or
- // as an executable. Since the NT service manager does not send us
- // command line flags, the default case is to run as a service.
- // Additional supported mutually-exclusive functions are installation
- // (with the -install command line switch) de-installation (with the
- // -remove switch) and running as a non-service executable (with the
- // -debug switch).
- //
- // This function parses the command line arguments and invokes the
- // selected mode of operation. When running as an executable, blocking
- // keyboard input is used to prevent the program from exiting prematurely.
- //
- 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 //start as service
- {
- #ifdef WIN95
- RunAsExecutable();
- #else
- if (!StartServiceCtrlDispatcher(rgSTE))
- SRVDBG_Error("StartServiceCtrlDispatcher failed.");
- #endif
- }
- return 0;
- }
|