windows-nt/Source/XPSP1/NT/enduser/windows.com/wuau/wuaueng/cauwait.h
2020-09-26 16:20:57 +08:00

435 lines
12 KiB
C++

//=======================================================================
//
// Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
//
// File: CAUWait.h
//
// Creator: PeterWi
//
// Purpose: Event waiting management.
//
//=======================================================================
#pragma once
#include "pch.h"
//handle event number should be consecutive and
// range from AU_HANDLE_EVENT_MIN to AU_HANDLE_EVENT_MAX
typedef enum tagAUEVENT {
AU_HANDLE_EVENT_MIN = 0,
AUEVENT_STATE_CHANGED = AU_HANDLE_EVENT_MIN,
AUEVENT_SERVICE_FINISHED,
AUEVENT_NEW_ADMIN_SESSION ,
AUEVENT_WUAUCLT_FINISHED ,
AUEVENT_POLICY_CHANGE,
AUEVENT_SETTINGS_CHANGE,
AUEVENT_CATALOG_VALIDATED,
AU_HANDLE_EVENT_MAX = AUEVENT_CATALOG_VALIDATED,
AUEVENT_DUMMY,
AUEVENT_REMINDER_TIMEOUT ,
AUEVENT_DO_DIRECTIVE, //skip wait once
AUEVENT_RELAUNCH_TIMEOUT ,
AUEVENT_SCHEDULED_INSTALL,
AUEVENT_REBOOTWARNING_TIMEOUT
} AUEVENT;
extern HANDLE ghActiveAdminSession;
extern HANDLE ghPolicyChanged;
extern HANDLE ghSettingsChanged;
//=======================================================================
// CAUState
//=======================================================================
class CAUWait
{
public:
CAUWait() :m_pfSecondaryCltsIsAdmin(NULL), m_phSecondaryClts(NULL){ Reset(); }
~CAUWait()
{
Reset();
}
void Reset(void)
{
// DEBUGMSG("CAUWait Reset() called");
m_fFirstClientIsAdmin = TRUE;
m_dwSecondaryClts= 0;
m_timeoutID = AUEVENT_DUMMY;
m_fProrateTimeout = TRUE;
m_fSkipWaitOnce = FALSE;
SafeFreeNULL(m_pfSecondaryCltsIsAdmin);
SafeFreeNULL(m_phSecondaryClts);
ZeroMemory(&m_hEventHandles, sizeof(m_hEventHandles));
ZeroMemory(&m_stTimeout, sizeof(m_stTimeout));
m_Add(AUEVENT_STATE_CHANGED);
m_Add(AUEVENT_SERVICE_FINISHED);
m_Add(AUEVENT_POLICY_CHANGE);
m_Add(AUEVENT_SETTINGS_CHANGE);
}
BOOL Add(AUEVENT eventID, HANDLE hEvent = NULL, BOOL fAdmin = FALSE)
{
if (AUEVENT_DO_DIRECTIVE == eventID)
{
m_fSkipWaitOnce = TRUE;
return TRUE;
}
return m_Add(eventID, hEvent, fAdmin);
}
void Timeout(AUEVENT eventID, DWORD dwTimeout, BOOL fProrate = TRUE)
{
m_timeoutID = eventID;
GetSystemTime(&m_stTimeout);
TimeAddSeconds(m_stTimeout, dwTimeout, &m_stTimeout);
m_fProrateTimeout = fProrate;
#if 0
#ifdef DBG
TCHAR szTime[50];
if (SUCCEEDED(SystemTime2String(m_stTimeout, szTime, ARRAYSIZE(szTime))))
{
DEBUGMSG("next time out time is %S", szTime);
}
#endif
#endif
}
AUEVENT GetTimeoutEvent(void)
{
return m_timeoutID;
}
DWORD GetTimeoutValue(void)
{
SYSTEMTIME stCur;
GetSystemTime(&stCur);
return max(TimeDiff(stCur, m_stTimeout), 0);
}
BOOL Wait(HANDLE *pHandle, BOOL *pfAdmin, AUEVENT *pfEventId)
{
DWORD dwTimeout;
BOOL fRet = TRUE;
AUASSERT(pHandle != NULL);
AUASSERT(pfAdmin != NULL);
AUASSERT(NULL != pfEventId);
*pHandle = NULL;
*pfAdmin = FALSE;
*pfEventId = AUEVENT_DUMMY;
if (m_fSkipWaitOnce)
{
m_fSkipWaitOnce = FALSE;
*pfEventId = AUEVENT_DO_DIRECTIVE;
return TRUE;
}
if (AUEVENT_DUMMY == m_timeoutID)
{
dwTimeout = INFINITE;
}
else
{
SYSTEMTIME stCur;
GetSystemTime(&stCur);
dwTimeout = max(TimeDiff(stCur, m_stTimeout), 0);
dwTimeout = m_fProrateTimeout ? dwTimeToWait(dwTimeout): dwTimeout * 1000;
// DEBUGMSG("Wait() timeout value is %d msecs", dwTimeout);
}
HANDLE *phandles = NULL;
DWORD dwCount = 0;
HandleList(FALSE, &phandles, &dwCount); //get handle list
AUASSERT(dwCount > 0);
AUASSERT(NULL != phandles);
AUEVENT eventid = AUEVENT_DUMMY;
DWORD dwRet = WaitForMultipleObjects(dwCount, phandles, FALSE, dwTimeout);
if ( (WAIT_OBJECT_0 + dwCount - 1) >= dwRet )
{
*pHandle = phandles[dwRet - WAIT_OBJECT_0];
eventid = GetEventID(*pHandle);
if (AUEVENT_WUAUCLT_FINISHED == eventid)
{
*pfAdmin = fIsCltAdmin(*pHandle);
DEBUGMSG("%s wuauclt exited", *pfAdmin ? "Admin" : "Nonadmin");
}
RemoveHandle(eventid, *pHandle);
}
else if ( WAIT_TIMEOUT == dwRet )
{
eventid = m_timeoutID;
m_timeoutID = AUEVENT_DUMMY;
}
else
{
fRet = FALSE;
}
HandleList(TRUE, &phandles); //free handle list if allocated
#ifdef DBG
char buf[100];
switch (eventid)
{
case AUEVENT_STATE_CHANGED: StringCchCopyExA(buf, ARRAYSIZE(buf), "state change", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
case AUEVENT_POLICY_CHANGE: StringCchCopyExA(buf, ARRAYSIZE(buf), "policy change", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
case AUEVENT_RELAUNCH_TIMEOUT: StringCchCopyExA(buf, ARRAYSIZE(buf), "relaunch timeout", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
case AUEVENT_REMINDER_TIMEOUT: StringCchCopyExA(buf, ARRAYSIZE(buf), "reminder timeout", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
case AUEVENT_SCHEDULED_INSTALL: StringCchCopyExA(buf, ARRAYSIZE(buf), "schedule install", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
case AUEVENT_WUAUCLT_FINISHED: StringCchCopyExA(buf, ARRAYSIZE(buf), "wuauclt finished", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
case AUEVENT_SERVICE_FINISHED: StringCchCopyExA(buf, ARRAYSIZE(buf), "service finished", NULL, NULL, MISTSAFE_STRING_FLAGS);break;
case AUEVENT_NEW_ADMIN_SESSION: StringCchCopyExA(buf, ARRAYSIZE(buf), "new admin session", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
case AUEVENT_SETTINGS_CHANGE: StringCchCopyExA(buf, ARRAYSIZE(buf), "settings changed", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
case AUEVENT_DO_DIRECTIVE: StringCchCopyExA(buf, ARRAYSIZE(buf), "doing directive, skip wait once", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
case AUEVENT_CATALOG_VALIDATED: StringCchCopyExA(buf, ARRAYSIZE(buf), "catalog validation done", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
case AUEVENT_REBOOTWARNING_TIMEOUT: StringCchCopyExA(buf, ARRAYSIZE(buf), "reboot warning engine timeout", NULL, NULL, MISTSAFE_STRING_FLAGS);break;
default: StringCchCopyExA(buf, ARRAYSIZE(buf), "error", NULL, NULL, MISTSAFE_STRING_FLAGS);
}
DEBUGMSG("Wait object wake up for %s with handle %lx", buf, *pHandle);
#endif
*pfEventId = eventid;
return fRet;
}
private:
//assumption: handle is unique in the list
BOOL m_Add(AUEVENT eventID, HANDLE hEvent = NULL, BOOL fAdmin = FALSE)
{
if (eventID >= ARRAYSIZE(m_hEventHandles))
{
AUASSERT(FALSE); //should never be
return FALSE;
}
if ( NULL != hEvent )
{
if (AUEVENT_WUAUCLT_FINISHED != eventID)
{
m_hEventHandles[eventID] = hEvent;
}
else
{
if (NULL == m_hEventHandles[eventID])
{
m_hEventHandles[eventID] = hEvent;
m_fFirstClientIsAdmin = fAdmin;
}
else
{ //more than one client
HANDLE *pTmp = (HANDLE *)malloc((m_dwSecondaryClts+1)*sizeof(*pTmp));
if (NULL == pTmp)
{
return FALSE;
}
BOOL *pTmp2 = (BOOL *) malloc((m_dwSecondaryClts + 1) * sizeof(*pTmp2));
if (NULL == pTmp2)
{
free(pTmp);
return FALSE;
}
for (UINT i = 0; i < m_dwSecondaryClts; i++)
{
pTmp[i] = m_phSecondaryClts[i];
pTmp2[i] = m_pfSecondaryCltsIsAdmin[i];
}
m_dwSecondaryClts++;
pTmp[m_dwSecondaryClts-1] = hEvent;
pTmp2[m_dwSecondaryClts-1] = fAdmin;
SafeFree(m_phSecondaryClts);
SafeFree(m_pfSecondaryCltsIsAdmin);
m_phSecondaryClts = pTmp;
m_pfSecondaryCltsIsAdmin = pTmp2;
}
}
return TRUE;
}
else
{
switch (eventID)
{
case AUEVENT_STATE_CHANGED:
return m_Add(eventID, ghEngineState);
case AUEVENT_SERVICE_FINISHED:
return m_Add(eventID, ghServiceFinished);
case AUEVENT_NEW_ADMIN_SESSION:
return m_Add(eventID, ghActiveAdminSession);
case AUEVENT_POLICY_CHANGE:
return m_Add(eventID, ghPolicyChanged);
case AUEVENT_SETTINGS_CHANGE:
return m_Add(eventID, ghSettingsChanged);
case AUEVENT_CATALOG_VALIDATED:
return m_Add(eventID, ghValidateCatalog);
default:
DEBUGMSG("Unknown event id %d", eventID);
AUASSERT(FALSE); //should never be here
return FALSE;
}
}
}
private:
HANDLE m_hEventHandles[AU_HANDLE_EVENT_MAX - AU_HANDLE_EVENT_MIN + 1];
BOOL m_fFirstClientIsAdmin; // for the first clt
HANDLE *m_phSecondaryClts;
BOOL *m_pfSecondaryCltsIsAdmin;
DWORD m_dwSecondaryClts;
SYSTEMTIME m_stTimeout; //when timeout should happen
AUEVENT m_timeoutID;
BOOL m_fProrateTimeout;//whether to prorate Timeout when do actual wait
BOOL m_fSkipWaitOnce;
BOOL fIsEventInherent(DWORD dwEventId)
{
if (AUEVENT_STATE_CHANGED == dwEventId ||
AUEVENT_SERVICE_FINISHED==dwEventId ||
AUEVENT_POLICY_CHANGE == dwEventId ||
AUEVENT_SETTINGS_CHANGE == dwEventId)
{
return TRUE;
}
else
{
return FALSE;
}
}
//get or free handle list
//IN fFreeList: if TRUE, free *pHandles list got
// if FALSE, get the handle list
void HandleList(BOOL fFreeList, HANDLE **pHandles, DWORD *pdwCount = NULL) const
{
static HANDLE handles[ARRAYSIZE(m_hEventHandles)];
DWORD dwCount = 0;
if (NULL== pHandles )
{
return ;
}
if (fFreeList)
{
if (*pHandles != handles)
{
free(*pHandles);
}
return;
}
if (NULL == pdwCount)
{
return;
}
*pHandles = NULL;
*pdwCount =0;
ZeroMemory(&handles, sizeof(handles));
for (UINT i = 0; i < ARRAYSIZE(m_hEventHandles); i++)
{
if (NULL != m_hEventHandles[i])
{
handles[dwCount++] = m_hEventHandles[i];
}
}
*pHandles = handles;
if (0 != m_dwSecondaryClts)
{ //need to wait for more than one client
AUASSERT(m_phSecondaryClts != NULL);
if (NULL != (*pHandles = (HANDLE *) malloc((dwCount + m_dwSecondaryClts) * sizeof(**pHandles))))
{
for (UINT j = 0 ; j < dwCount; j++)
{
(*pHandles)[j] = handles[j];
}
for (j = 0; j< m_dwSecondaryClts; j++)
{
(*pHandles)[dwCount+j] = m_phSecondaryClts[j];
}
dwCount += m_dwSecondaryClts;
}
else
{
*pHandles = handles;
}
}
*pdwCount = dwCount;
}
//return TRUE if handle removed from internal wait list or handle does not need to be removed
//return FALSE if handle not found
BOOL RemoveHandle(IN AUEVENT eventid , IN HANDLE & handle)
{
AUASSERT(NULL != handle);
if (fIsEventInherent(eventid))
{
return TRUE;
}
//remove non inhereant events once signalled
for (UINT i = 0; i < ARRAYSIZE(m_hEventHandles); i++)
{
if (handle == m_hEventHandles[i])
{
m_hEventHandles[i] = NULL;
return TRUE;
}
}
for (i = 0; i < m_dwSecondaryClts; i++)
{
if (handle == m_phSecondaryClts[i])
{
m_phSecondaryClts[i] = m_phSecondaryClts[m_dwSecondaryClts-1];
m_pfSecondaryCltsIsAdmin[i] = m_pfSecondaryCltsIsAdmin[m_dwSecondaryClts - 1];
m_phSecondaryClts[m_dwSecondaryClts-1] = NULL;
m_pfSecondaryCltsIsAdmin[m_dwSecondaryClts - 1] = FALSE;
m_dwSecondaryClts--;
if (0 == m_dwSecondaryClts)
{
SafeFreeNULL(m_phSecondaryClts);
SafeFreeNULL(m_pfSecondaryCltsIsAdmin);
}
return TRUE;
}
}
AUASSERT(FALSE); //should never be here
return FALSE;
}
BOOL fIsCltAdmin(HANDLE & handle) const
{
AUASSERT(NULL != handle);
if (handle == m_hEventHandles[AUEVENT_WUAUCLT_FINISHED])
{
return m_fFirstClientIsAdmin;
}
for (UINT i = 0; i < m_dwSecondaryClts; i++)
{
if (handle == m_phSecondaryClts[i])
{
return m_pfSecondaryCltsIsAdmin[i];
}
}
AUASSERT(FALSE); //should never be here
return FALSE;
}
AUEVENT GetEventID(HANDLE &handle) const
{
AUASSERT(NULL!= handle);
for (UINT i = 0; i < ARRAYSIZE(m_hEventHandles); i++)
{
if (handle == m_hEventHandles[i])
{
return (AUEVENT)i;
}
}
for (i = 0; i< m_dwSecondaryClts; i++)
{
if (handle == m_phSecondaryClts[i])
{
return AUEVENT_WUAUCLT_FINISHED;
}
}
AUASSERT(FALSE); //should never be here
return AUEVENT_DUMMY;
}
};