2025-04-27 07:49:33 -04:00

458 lines
9.1 KiB
C++

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
wpipm.cxx
Abstract:
Contains the WPIPM class that handles communication with
the admin service. WPIPM responds to pings, and tells
the process when to shut down.
Author:
Michael Courage (MCourage) 22-Feb-1999
Revision History:
--*/
#include <precomp.hxx>
#include "ipm.hxx"
#include "wpipm.hxx"
#include "ipm_io_c.hxx"
#ifdef TEST
#include "RWP_Func.hxx"
#endif
/**
*
* Routine Description:
*
* Initializes WPIPM.
*
* Arguments:
*
* pWpContext - pointer to the wp context (so we can tell it to shutdown)
*
* Return Value:
*
* HRESULT
*/
HRESULT
WP_IPM::Initialize(
WP_CONTEXT * pWpContext
)
{
HRESULT hr = S_OK;
IO_FACTORY_C * pFactory;
STRU strPipeName;
MESSAGE_PIPE * pPipe = NULL;
m_pWpContext = pWpContext;
m_pMessageGlobal = NULL;
m_pPipe = NULL;
m_hTerminateEvent = NULL;
//
// create MESSAGE_GLOBAL
//
pFactory = new IO_FACTORY_C();
if (pFactory) {
m_pMessageGlobal = new MESSAGE_GLOBAL(pFactory);
if (m_pMessageGlobal) {
hr = m_pMessageGlobal->InitializeMessageGlobal();
} else {
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
} else {
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
//
// create connect event
//
if (SUCCEEDED(hr)) {
m_hConnectEvent = CreateEvent(
NULL, // default security
TRUE, // manual reset
FALSE, // initial state
NULL // unnamed event
);
if (m_hConnectEvent) {
hr = m_pMessageGlobal->CreateMessagePipe(
this,
&pPipe
);
} else {
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
//
// create the MESSAGE_PIPE and termination event
//
if (SUCCEEDED(hr)) {
m_hTerminateEvent = CreateEvent(
NULL, // default security
TRUE, // manual reset
FALSE, // initial state
NULL // unnamed
);
if (m_hTerminateEvent) {
hr = m_pMessageGlobal->CreateMessagePipe(
this,
&pPipe
);
} else {
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
//
// connect the MESSAGE_PIPE
//
if (SUCCEEDED(hr)) {
hr = strPipeName.Copy(IPM_NAMED_PIPE_NAME);
if (SUCCEEDED(hr)) {
hr = m_pMessageGlobal->ConnectMessagePipe(
strPipeName,
pWpContext->m_pConfigInfo->QueryNamedPipeId(),
pPipe
);
}
}
if (SUCCEEDED(hr)) {
m_pPipe = pPipe;
} else {
// pipe takes care of itself
Terminate();
}
return hr;
}
/**
*
* Routine Description:
*
* Terminates WPIPM.
*
* If the message pipe is open this function will disconnect it
* and wait for the pipe's disconnection callback.
*
* Arguments:
*
* None.
*
* Return Value:
*
* HRESULT
*/
HRESULT
WP_IPM::Terminate(
VOID
)
{
HRESULT hr = S_OK;
HRESULT hrGlobalTerminate;
DWORD dwWaitResult;
if (m_pMessageGlobal) {
if (m_pPipe) {
hr = m_pMessageGlobal->DisconnectMessagePipe(m_pPipe);
m_pPipe = NULL;
// pipe deletes itself
if (SUCCEEDED(hr)) {
dwWaitResult = WaitForSingleObject(
m_hTerminateEvent,
INFINITE
);
}
}
hrGlobalTerminate = m_pMessageGlobal->TerminateMessageGlobal();
if (SUCCEEDED(hr)) {
hr = hrGlobalTerminate;
}
m_pMessageGlobal = NULL;
}
m_pWpContext = NULL;
if (m_hTerminateEvent) {
CloseHandle(m_hTerminateEvent);
m_hTerminateEvent = NULL;
}
if (m_hConnectEvent) {
CloseHandle(m_hConnectEvent);
m_hConnectEvent = NULL;
}
return hr;
}
/**
*
*
* Routine Description:
*
* This is a callback from the message pipe that means
* the pipe has received a message.
*
* We decode the message and respond appropriately.
*
* Arguments:
*
* pPipeMessage - the message that we received
*
* Return Value:
*
* HRESULT
*
*/
HRESULT
WP_IPM::AcceptMessage(
IN const MESSAGE * pPipeMessage
)
{
HRESULT hr;
switch (pPipeMessage->GetOpcode()) {
case IPM_OP_PING:
hr = HandlePing();
break;
case IPM_OP_SHUTDOWN:
hr = HandleShutdown();
break;
default:
DBG_ASSERT(FALSE);
hr = E_FAIL;
break;
}
return hr;
}
/**
*
* Routine Description:
*
* This is a callback from the message pipe that means
* the pipe has been connected and is ready for use.
*
* Arguments:
*
* None.
*
* Return Value:
*
* HRESULT
*/
HRESULT
WP_IPM::PipeConnected(
VOID
)
{
DBG_ASSERT(m_hConnectEvent);
DBG_REQUIRE( SetEvent(m_hConnectEvent) );
return S_OK;
}
/**
*
* Routine Description:
*
* This is a callback from the message pipe that means
* the pipe has been disconnected and you won't be receiving
* any more messages.
*
* Tells WPIPM::Terminate that it's ok to exit now.
*
* Arguments:
*
* hr - the error code associated with the pipe disconnection
*
* Return Value:
*
* HRESULT
*/
HRESULT
WP_IPM::PipeDisconnected(
IN HRESULT hr
)
{
//
// CODEWORK: should we do something with the parameter?
//
if (FAILED(hr))
{
WpTrace(WPIPM, (DBG_CONTEXT, "PipeDisconnected with hr ( %d).\n", hr));
}
//
// If the pipe disappears out from under us, assume the WAS has
// gone bad, and initiate clean shutdown of this worker process.
//
#ifdef TEST
//
// All sorts of miscreat shutdown behaviors (for testing)
//
if (RWP_BEHAVIOR_EXHIBITED = RWP_Shutdown_Behavior(&hr))
return (hr);
#endif
m_pWpContext->IndicateShutdown(SHUTDOWN_REASON_ADMIN);
if (SetEvent(m_hTerminateEvent)) {
return S_OK;
} else {
return HRESULT_FROM_WIN32(GetLastError());
}
}
/**
*
* Routine Description:
*
* Handles the ping message. Sends the ping response message.
*
* Arguments:
*
* None.
*
* Return Value:
*
* HRESULT
*/
HRESULT
WP_IPM::HandlePing(
VOID
)
{
HRESULT hr;
#ifdef TEST
//
// All sorts of miscreat ping response behaviors (for testing)
//
if (RWP_BEHAVIOR_EXHIBITED = RWP_Ping_Behavior(&hr, m_pPipe))
return (hr);
#endif
WpTrace(WPIPM, (DBG_CONTEXT, "Handle Ping\n\n"));
hr = m_pPipe->WriteMessage(
IPM_OP_PING_REPLY, // ping reply opcode
0, // no data to send
NULL // pointer to no data
);
return hr;
}
/**
*
* Routine Description:
*
*
* Handles the shutdown message. Shuts down the process
*
* Arguments:
*
* None.
*
* Return Value:
*
* HRESULT
*/
HRESULT
WP_IPM::HandleShutdown(
VOID
)
{
HRESULT hr = S_OK;
//
// BUGBUG: Surely this is not the right way out!
//
// ExitProcess(NO_ERROR);
#ifdef TEST
//
// All sorts of miscreat shutdown behaviors (for testing)
//
if (RWP_BEHAVIOR_EXHIBITED = RWP_Shutdown_Behavior(&hr))
return (hr);
#endif
WpTrace(WPIPM, (DBG_CONTEXT, "Handle ******************** Shutdown\n\n"));
m_pWpContext->IndicateShutdown(SHUTDOWN_REASON_ADMIN);
return hr;
}
/**
*
* Routine Description:
*
* Sends the message to indicate the worker process has reach certain state.
* Main use is in shutdown. See IPM_WP_SHUTDOWN_MSG for reasons.
*
* Arguments:
*
* None.
*
* Return Value:
*
* HRESULT
*/
HRESULT
WP_IPM::SendMsgToAdminProcess(
IPM_WP_SHUTDOWN_MSG reason
)
{
HRESULT hr;
//
// wait for connect
//
WaitForSingleObject(m_hConnectEvent, INFINITE);
//
// really send the message
//
hr = m_pPipe->WriteMessage(
IPM_OP_WORKER_REQUESTS_SHUTDOWN, // sends message indicate shutdown
sizeof(reason), // no data to send
(BYTE *)&reason // pointer to no data
);
return hr;
}
//
// end of wpipm.cxx
//