You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
606 lines
16 KiB
606 lines
16 KiB
//
|
|
// Copyright (C) 1993-1997 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// MODULE: nmmgr.cpp
|
|
//
|
|
// PURPOSE: Implements the body of the service.
|
|
//
|
|
// FUNCTIONS:
|
|
// MNMServiceStart(DWORD dwArgc, LPTSTR *lpszArgv);
|
|
// MNMServiceStop( );
|
|
//
|
|
// COMMENTS: The functions implemented in nmmgr.c are
|
|
// prototyped in nmmgr.h
|
|
//
|
|
//
|
|
// AUTHOR: Claus Giloi
|
|
//
|
|
|
|
#include <precomp.h>
|
|
#include <tsecctrl.h>
|
|
|
|
#define NMSRVC_TEXT "NMSrvc"
|
|
|
|
// DEBUG only -- Define debug zone
|
|
#ifdef DEBUG
|
|
HDBGZONE ghZone = NULL;
|
|
static PTCHAR rgZones[] = {
|
|
NMSRVC_TEXT,
|
|
"Warning",
|
|
"Trace",
|
|
"Function"
|
|
};
|
|
#endif // DEBUG
|
|
|
|
extern INmSysInfo2 * g_pNmSysInfo; // Interface to SysInfo
|
|
extern BOOL InitT120Credentials(VOID);
|
|
|
|
// this event is signaled when the
|
|
// service should end
|
|
|
|
const int STOP_EVENT = 0;
|
|
HANDLE hServerStopEvent = NULL;
|
|
|
|
// this event is signaled when the
|
|
// service should be paused or continued
|
|
|
|
const int PAUSE_EVENT = 1;
|
|
HANDLE hServerPauseEvent = NULL;
|
|
|
|
const int CONTINUE_EVENT = 2;
|
|
HANDLE hServerContinueEvent = NULL;
|
|
|
|
const int numEventHandles = 3;
|
|
|
|
HANDLE hServerActiveEvent = NULL;
|
|
|
|
DWORD g_dwActiveState = STATE_INACTIVE;
|
|
|
|
|
|
//
|
|
// FUNCTION: CreateWatcherProcess
|
|
//
|
|
// PURPOSE: This launches a rundll32.exe which loads msconf.dll which will then wait for
|
|
// us to terminate and make sure that the mnmdd display driver was properly deactivated.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
BOOL CreateWatcherProcess()
|
|
{
|
|
BOOL bRet = FALSE;
|
|
HANDLE hProcess;
|
|
|
|
// open a handle to ourselves that the watcher process can inherit
|
|
hProcess = OpenProcess(SYNCHRONIZE,
|
|
TRUE,
|
|
GetCurrentProcessId());
|
|
if (hProcess)
|
|
{
|
|
TCHAR szWindir[MAX_PATH];
|
|
|
|
if (GetSystemDirectory(szWindir, sizeof(szWindir)/sizeof(szWindir[0])))
|
|
{
|
|
TCHAR szCmdLine[MAX_PATH * 2];
|
|
PROCESS_INFORMATION pi = {0};
|
|
STARTUPINFO si = {0};
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
wsprintf(szCmdLine, "\"%s\\rundll32.exe\" msconf.dll,CleanupNetMeetingDispDriver %ld", szWindir, HandleToLong(hProcess));
|
|
|
|
if (CreateProcess(NULL,
|
|
szCmdLine,
|
|
NULL,
|
|
NULL,
|
|
TRUE, // we want the watcher to inherit hProcess, so we must set bInheritHandles = TRUE
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi))
|
|
{
|
|
bRet = TRUE;
|
|
|
|
CloseHandle(pi.hThread);
|
|
CloseHandle(pi.hProcess);
|
|
}
|
|
}
|
|
|
|
CloseHandle(hProcess);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: MNMServiceStart
|
|
//
|
|
// PURPOSE: Actual code of the service
|
|
// that does the work.
|
|
//
|
|
// PARAMETERS:
|
|
// dwArgc - number of command line arguments
|
|
// lpszArgv - array of command line arguments
|
|
//
|
|
// RETURN VALUE:
|
|
// none
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
VOID MNMServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
|
|
{
|
|
HRESULT hRet;
|
|
BOOL fWaitForEvent = TRUE;
|
|
DWORD dwResult;
|
|
MSG msg;
|
|
LPCTSTR lpServiceStopEvent = TEXT("ServiceStopEvent");
|
|
LPCTSTR lpServiceBusyEvent = TEXT("ServiceBusyEvent");
|
|
const int MaxWaitTime = 5;
|
|
HANDLE hConfEvent;
|
|
DWORD dwError = NO_ERROR;
|
|
HANDLE hShuttingDown;
|
|
int i;
|
|
RegEntry Re( REMOTECONTROL_KEY, HKEY_LOCAL_MACHINE );
|
|
|
|
// Initialization
|
|
DBGINIT(&ghZone, rgZones);
|
|
InitDebugModule(NMSRVC_TEXT);
|
|
|
|
DebugEntry(MNMServiceStart);
|
|
|
|
if (!Re.GetNumber(REMOTE_REG_RUNSERVICE, DEFAULT_REMOTE_RUNSERVICE))
|
|
{
|
|
TRACE_OUT(("Try to start mnmsrvc without no registry setting"));
|
|
goto cleanup;
|
|
}
|
|
///////////////////////////////////////////////////
|
|
//
|
|
// Service initialization
|
|
//
|
|
|
|
// report the status to the service control manager.
|
|
//
|
|
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, 30000))
|
|
{
|
|
ERROR_OUT(("ReportStatusToSCMgr failed"));
|
|
dwError = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
HANDLE pEventHandles[numEventHandles];
|
|
|
|
// create the event object. The control handler function signals
|
|
// this event when it receives the "stop" control code.
|
|
//
|
|
hServerStopEvent = CreateEvent(
|
|
NULL, // no security attributes
|
|
TRUE, // manual reset event
|
|
FALSE, // not-signalled
|
|
SERVICE_STOP_EVENT); // no name
|
|
|
|
if ( hServerStopEvent == NULL)
|
|
{
|
|
ERROR_OUT(("CreateEvent failed"));
|
|
dwError = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
pEventHandles[STOP_EVENT] = hServerStopEvent;
|
|
|
|
hServerPauseEvent = CreateEvent(
|
|
NULL,
|
|
FALSE,
|
|
FALSE,
|
|
SERVICE_PAUSE_EVENT);
|
|
|
|
if (hServerPauseEvent == NULL)
|
|
{
|
|
ERROR_OUT(("CreateEvent failed"));
|
|
dwError = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
pEventHandles[PAUSE_EVENT] = hServerPauseEvent;
|
|
|
|
hServerContinueEvent = CreateEvent(
|
|
NULL,
|
|
FALSE,
|
|
FALSE,
|
|
SERVICE_CONTINUE_EVENT);
|
|
|
|
if (hServerContinueEvent == NULL)
|
|
{
|
|
ERROR_OUT(("CreateEvent failed"));
|
|
dwError = GetLastError();
|
|
goto cleanup;
|
|
}
|
|
|
|
pEventHandles[CONTINUE_EVENT] = hServerContinueEvent;
|
|
|
|
CoInitialize(NULL);
|
|
|
|
//
|
|
// End of initialization
|
|
//
|
|
////////////////////////////////////////////////////////
|
|
|
|
// report the status to the service control manager.
|
|
//
|
|
if (!ReportStatusToSCMgr(
|
|
SERVICE_RUNNING, // service state
|
|
NO_ERROR, // exit code
|
|
0)) // wait hint
|
|
{
|
|
ERROR_OUT(("ReportStatusToSCMgr failed"));
|
|
goto cleanup;
|
|
}
|
|
SetConsoleCtrlHandler(ServiceCtrlHandler, TRUE);
|
|
|
|
CreateWatcherProcess();
|
|
|
|
AddTaskbarIcon();
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// Service is now running, perform work until shutdown
|
|
//
|
|
if (IS_NT)
|
|
{
|
|
AddToMessageLog(EVENTLOG_INFORMATION_TYPE,
|
|
0,
|
|
MSG_INF_START,
|
|
NULL);
|
|
}
|
|
|
|
//
|
|
// Check if the service should start up activated
|
|
//
|
|
|
|
if ( Re.GetNumber(REMOTE_REG_ACTIVATESERVICE,
|
|
DEFAULT_REMOTE_ACTIVATESERVICE))
|
|
{
|
|
MNMServiceActivate();
|
|
}
|
|
else
|
|
{
|
|
if (!ReportStatusToSCMgr(
|
|
SERVICE_PAUSED, // service state
|
|
NO_ERROR, // exit code
|
|
0)) // wait hint
|
|
{
|
|
ERROR_OUT(("ReportStatusToSCMgr failed"));
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
while (fWaitForEvent)
|
|
{
|
|
dwResult = MsgWaitForMultipleObjects( numEventHandles,
|
|
pEventHandles,
|
|
FALSE,
|
|
INFINITE,
|
|
QS_ALLINPUT);
|
|
|
|
switch (dwResult)
|
|
{
|
|
case WAIT_OBJECT_0 + numEventHandles:
|
|
{
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (WM_QUIT != msg.message)
|
|
{
|
|
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(("received WM_QUIT"));
|
|
fWaitForEvent = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case WAIT_OBJECT_0 + PAUSE_EVENT:
|
|
{
|
|
if (STATE_ACTIVE == g_dwActiveState)
|
|
{
|
|
MNMServiceDeActivate();
|
|
}
|
|
ReportStatusToSCMgr( SERVICE_PAUSED, NO_ERROR, 0);
|
|
break;
|
|
}
|
|
case WAIT_OBJECT_0 + CONTINUE_EVENT:
|
|
{
|
|
HANDLE hInit = OpenEvent(EVENT_ALL_ACCESS, FALSE, _TEXT("CONF:Init"));
|
|
if (STATE_INACTIVE == g_dwActiveState && NULL == hInit)
|
|
{
|
|
MNMServiceActivate();
|
|
}
|
|
CloseHandle(hInit);
|
|
ReportStatusToSCMgr( SERVICE_RUNNING, NO_ERROR, 0);
|
|
break;
|
|
}
|
|
case WAIT_OBJECT_0 + STOP_EVENT:
|
|
{
|
|
RemoveTaskbarIcon();
|
|
if (STATE_ACTIVE == g_dwActiveState)
|
|
{
|
|
MNMServiceDeActivate();
|
|
}
|
|
fWaitForEvent = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if ( STATE_ACTIVE == g_dwActiveState )
|
|
{
|
|
MNMServiceDeActivate();
|
|
}
|
|
|
|
if (hServerStopEvent)
|
|
CloseHandle(hServerStopEvent);
|
|
if (hServerPauseEvent)
|
|
CloseHandle(hServerPauseEvent);
|
|
if (hServerContinueEvent)
|
|
CloseHandle(hServerContinueEvent);
|
|
|
|
TRACE_OUT(("Reporting SERVICE_STOPPED"));
|
|
ReportStatusToSCMgr( SERVICE_STOPPED, dwError, 0);
|
|
|
|
DebugExitVOID(MNMServiceStart);
|
|
|
|
CoUninitialize();
|
|
|
|
DBGDEINIT(&ghZone);
|
|
ExitDebugModule();
|
|
}
|
|
|
|
|
|
BOOL MNMServiceActivate ( VOID )
|
|
{
|
|
DebugEntry(MNMServiceActivate);
|
|
|
|
if ( STATE_INACTIVE != g_dwActiveState )
|
|
{
|
|
WARNING_OUT(("MNMServiceActivate: g_dwActiveState:%d",
|
|
g_dwActiveState));
|
|
return FALSE;
|
|
}
|
|
|
|
g_dwActiveState = STATE_BUSY;
|
|
|
|
if (!IS_NT)
|
|
{
|
|
ASSERT(NULL == hServerActiveEvent);
|
|
hServerActiveEvent = CreateEvent(NULL, FALSE, FALSE, SERVICE_ACTIVE_EVENT);
|
|
}
|
|
HRESULT hRet = InitConfMgr();
|
|
if (FAILED(hRet))
|
|
{
|
|
ERROR_OUT(("ERROR %x initializing nmmanger", hRet));
|
|
FreeConfMgr();
|
|
g_dwActiveState = STATE_INACTIVE;
|
|
if (!IS_NT)
|
|
{
|
|
CloseHandle ( hServerActiveEvent );
|
|
}
|
|
DebugExitBOOL(MNMServiceActivate,FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
if ( g_pNmSysInfo )
|
|
{
|
|
//
|
|
// Attempt to initialize T.120 security, if this fails
|
|
// bail out since we won't be able to receive any calls
|
|
//
|
|
|
|
if ( !InitT120Credentials() )
|
|
{
|
|
FreeConfMgr();
|
|
g_dwActiveState = STATE_INACTIVE;
|
|
if (!IS_NT)
|
|
{
|
|
CloseHandle ( hServerActiveEvent );
|
|
}
|
|
DebugExitBOOL(MNMServiceActivate,FALSE);
|
|
return FALSE;
|
|
}
|
|
}
|
|
g_dwActiveState = STATE_ACTIVE;
|
|
DebugExitBOOL(MNMServiceActivate,TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL MNMServiceDeActivate ( VOID )
|
|
{
|
|
DebugEntry(MNMServiceDeActivate);
|
|
|
|
if (STATE_ACTIVE != g_dwActiveState)
|
|
{
|
|
WARNING_OUT(("MNMServiceDeActivate: g_dwActiveState:%d",
|
|
g_dwActiveState));
|
|
DebugExitBOOL(MNMServiceDeActivate,FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
g_dwActiveState = STATE_BUSY;
|
|
|
|
//
|
|
// Leave Conference
|
|
//
|
|
|
|
if (NULL != g_pConference)
|
|
{
|
|
if (g_pNmSysInfo)
|
|
{
|
|
g_pNmSysInfo->ProcessSecurityData(UNLOADFTAPPLET,0,0,NULL);
|
|
}
|
|
if ( FAILED(g_pConference->Leave()))
|
|
{
|
|
ERROR_OUT(("Conference Leave failed"));;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free the conference
|
|
//
|
|
|
|
FreeConference();
|
|
|
|
//
|
|
// Free the AS interface
|
|
//
|
|
|
|
ASSERT(g_pAS);
|
|
UINT ret = g_pAS->Release();
|
|
g_pAS = NULL;
|
|
TRACE_OUT(("AS interface freed, ref %d after Release", ret));
|
|
|
|
// can we have a way not to create this event?
|
|
HANDLE hevt = ::CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
ASSERT(NULL != hevt);
|
|
const DWORD dwTimeout = 1000;
|
|
DWORD dwStartTime = ::GetTickCount();
|
|
DWORD dwCurrTimeout = dwTimeout;
|
|
DWORD dwRet;
|
|
BOOL fContinue = TRUE;
|
|
|
|
while (fContinue && WAIT_OBJECT_0 != (dwRet = ::MsgWaitForMultipleObjects(1, &hevt, FALSE, dwCurrTimeout, QS_ALLINPUT)))
|
|
{
|
|
if (WAIT_TIMEOUT != dwRet)
|
|
{
|
|
DWORD dwCurrTime = ::GetTickCount();
|
|
if (dwCurrTime < dwStartTime + dwTimeout)
|
|
{
|
|
dwCurrTimeout = dwStartTime + dwTimeout - dwCurrTime;
|
|
|
|
MSG msg;
|
|
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (WM_QUIT != msg.message)
|
|
{
|
|
::TranslateMessage(&msg);
|
|
::DispatchMessage(&msg);
|
|
}
|
|
else
|
|
{
|
|
::PostQuitMessage(0);
|
|
fContinue = FALSE;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
// timeout here
|
|
}
|
|
// exit the loop
|
|
break;
|
|
}
|
|
::CloseHandle(hevt);
|
|
|
|
// not to call FreeConfMfr imediately after FreeConference to avoid
|
|
// a bug in t120 will remove this sleep call after fix the bug in t120
|
|
FreeConfMgr();
|
|
|
|
// BUGBUG remove h323cc.dll should be done in nmcom. Once the bug in nmcom is fixed, this part will be removed.
|
|
HMODULE hmodH323CC = GetModuleHandle("h323cc.dll");
|
|
if (hmodH323CC)
|
|
{
|
|
if (FreeLibrary(hmodH323CC))
|
|
{
|
|
TRACE_OUT(("CmdInActivate -- Unloaded h323cc.dll"));
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(("CmdInActivate -- Failed to unload h323cc.dll %d", GetLastError()));
|
|
}
|
|
}
|
|
if (!IS_NT)
|
|
{
|
|
ASSERT(hServerActiveEvent);
|
|
if (hServerActiveEvent)
|
|
{
|
|
CloseHandle(hServerActiveEvent);
|
|
hServerActiveEvent = NULL;
|
|
}
|
|
}
|
|
g_dwActiveState = STATE_INACTIVE;
|
|
DebugExitBOOL(MNMServiceDeActivate,TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// FUNCTION: MNMServiceStop
|
|
//
|
|
// PURPOSE: Stops the service
|
|
//
|
|
// PARAMETERS:
|
|
// none
|
|
//
|
|
// RETURN VALUE:
|
|
// none
|
|
//
|
|
// COMMENTS:
|
|
// If a ServiceStop procedure is going to
|
|
// take longer than 3 seconds to execute,
|
|
// it should spawn a thread to execute the
|
|
// stop code, and return. Otherwise, the
|
|
// ServiceControlManager will believe that
|
|
// the service has stopped responding.
|
|
//
|
|
VOID MNMServiceStop()
|
|
{
|
|
DebugEntry(MNMServiceStop);
|
|
|
|
RemoveTaskbarIcon();
|
|
|
|
if ( hServerStopEvent )
|
|
{
|
|
TRACE_OUT(("MNMServiceStop: setting server stop event"));
|
|
SetEvent(hServerStopEvent);
|
|
}
|
|
|
|
if (IS_NT)
|
|
{
|
|
AddToMessageLog(EVENTLOG_INFORMATION_TYPE,
|
|
0,
|
|
MSG_INF_STOP,
|
|
NULL);
|
|
}
|
|
|
|
DebugExitVOID(MNMServiceStop);
|
|
}
|
|
|
|
|
|
VOID MNMServicePause()
|
|
{
|
|
DebugEntry(MNMServicePause);
|
|
|
|
if ( hServerPauseEvent )
|
|
SetEvent(hServerPauseEvent);
|
|
|
|
DebugExitVOID(MNMServicePause);
|
|
}
|
|
|
|
VOID MNMServiceContinue()
|
|
{
|
|
DebugEntry(MNMServiceContinue);
|
|
|
|
if ( hServerContinueEvent )
|
|
SetEvent(hServerContinueEvent);
|
|
|
|
DebugExitVOID(MNMServiceContinue);
|
|
}
|
|
|
|
|