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.
627 lines
16 KiB
627 lines
16 KiB
//***************************************************************************
|
|
//
|
|
// UPDATECFG.H
|
|
//
|
|
// Module: WMI Framework Instance provider
|
|
//
|
|
// Purpose: Defines class NlbConfigurationUpdate, used for
|
|
// async update of NLB properties associated with a particular NIC.
|
|
//
|
|
// Copyright (c)2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
// History:
|
|
//
|
|
// 04/05/01 JosephJ Created
|
|
//
|
|
//***************************************************************************
|
|
//
|
|
// The header of a completion header stored as a REG_BINARY value in
|
|
// the registry.
|
|
//
|
|
typedef struct {
|
|
UINT Version;
|
|
UINT Generation; // Redundant, used for internal consistancy check
|
|
UINT CompletionCode;
|
|
UINT Reserved;
|
|
} NLB_COMPLETION_RECORD, *PNLB_COMPLETION_RECORD;
|
|
|
|
#define NLB_CURRENT_COMPLETION_RECORD_VERSION 0x3d7376e2
|
|
|
|
//
|
|
// Prefix of the global event name used to control update access to the specifed
|
|
// NIC.
|
|
// Mutex1 has format: <prefix>
|
|
// Mutex2 has format: <prefix><NicGuid>
|
|
// Example mutex1 name: NLB_D6901862
|
|
// Example mutex2 name: NLB_D6901862{EBE09517-07B4-4E88-AAF1-E06F5540608B}
|
|
//
|
|
// The value "D6901862" is a random number.
|
|
//
|
|
#define NLB_CONFIGURATION_EVENT_PREFIX L"NLB_D6901862"
|
|
#define NLB_CONFIGURATION_MUTEX_PREFIX L"NLB_D6901863"
|
|
|
|
//
|
|
// Milliseconds to wait before giving up on trying to acquire the
|
|
// NLB mutex.
|
|
//
|
|
#define NLB_MUTEX_TIMEOUT 100
|
|
|
|
//
|
|
// The maximum generation difference between the oldest valid completion
|
|
// record and the current one. Records older then the oldest valid record
|
|
// are subject to pruning.
|
|
//
|
|
#define NLB_MAX_GENERATION_GAP 10
|
|
|
|
// Handle to dll - used in call to LoadString
|
|
extern HMODULE ghModule;
|
|
|
|
|
|
|
|
//
|
|
// Used for maintaining a log on the stack.
|
|
// Usage is NOT thread-safe -- each instance must be used
|
|
// by a single thread.
|
|
// 01/01/02 JosephJ Copied over from NLBMGR.EXE (nlbmgr\exe2)
|
|
//
|
|
class CLocalLogger
|
|
{
|
|
public:
|
|
|
|
CLocalLogger(VOID)
|
|
: m_pszLog (NULL), m_LogSize(0), m_CurrentOffset(0)
|
|
{
|
|
m_Empty[0] = 0; // The empty string.
|
|
}
|
|
|
|
~CLocalLogger()
|
|
{
|
|
delete[] m_pszLog;
|
|
m_pszLog=NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
Log(
|
|
IN UINT ResourceID,
|
|
...
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
ExtractLog(OUT LPCWSTR &pLog, UINT &Size)
|
|
//
|
|
// pLog -- set to pointer to internal buffer if there is stuff in the
|
|
// log, otherwise NULL.
|
|
//
|
|
// Size -- in chars; includes ending NULL
|
|
//
|
|
{
|
|
if (m_CurrentOffset != 0)
|
|
{
|
|
pLog = m_pszLog;
|
|
Size = m_CurrentOffset+1; // + 1 for ending NULL.
|
|
}
|
|
else
|
|
{
|
|
pLog = NULL;
|
|
Size = 0;
|
|
}
|
|
}
|
|
|
|
LPCWSTR
|
|
GetStringSafe(void)
|
|
{
|
|
LPCWSTR szLog = NULL;
|
|
UINT Size;
|
|
ExtractLog(REF szLog, REF Size);
|
|
if (szLog == NULL)
|
|
{
|
|
//
|
|
// Replace NULL by a pointer to an empty string.
|
|
//
|
|
szLog = m_Empty;
|
|
}
|
|
|
|
return szLog;
|
|
}
|
|
|
|
private:
|
|
|
|
WCHAR *m_pszLog;
|
|
UINT m_LogSize; // Current size of the log.
|
|
UINT m_CurrentOffset; // Characters left in the log.
|
|
WCHAR m_Empty[1]; // The empty string.
|
|
};
|
|
|
|
|
|
|
|
class NlbConfigurationUpdate
|
|
{
|
|
public:
|
|
|
|
//
|
|
// Static initialization function -- call in process-attach
|
|
//
|
|
static
|
|
VOID
|
|
StaticInitialize(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Static deinitialization function -- call in process-detach
|
|
//
|
|
static
|
|
VOID
|
|
StaticDeinitialize(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Stop accepting new queries, wait for existing (pending) queries
|
|
// to complete.
|
|
//
|
|
static
|
|
VOID
|
|
PrepareForDeinitialization(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Return true IFF there is no pending activity. If you return
|
|
// TRUE, try not to start new pending activity.
|
|
//
|
|
static
|
|
BOOL
|
|
CanUnloadNow(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Returns the current configuration on the specific NIC.
|
|
//
|
|
static
|
|
WBEMSTATUS
|
|
GetConfiguration(
|
|
IN LPCWSTR szNicGuid,
|
|
OUT PNLB_EXTENDED_CLUSTER_CONFIGURATION pCurrentCfg
|
|
);
|
|
|
|
//
|
|
// Called to initiate update to a new cluster state on that NIC. This
|
|
// could include moving from a NLB-bound state to the NLB-unbound state.
|
|
// *pGeneration is used to reference this particular update request.
|
|
//
|
|
static
|
|
WBEMSTATUS
|
|
DoUpdate(
|
|
IN LPCWSTR szNicGuid,
|
|
IN LPCWSTR szClientDescription,
|
|
IN PNLB_EXTENDED_CLUSTER_CONFIGURATION pNewState,
|
|
OUT UINT *pGeneration,
|
|
OUT WCHAR **ppLog // free using delete operator.
|
|
);
|
|
/*++
|
|
ppLog -- will point to a NULL-terminated string which contains
|
|
any messages to be displayed to the user. The string may contain
|
|
embedded (WCHAR) '\n' characters to delimit lines.
|
|
|
|
NOTE: ppLog will be filled out properly EVEN ON FAILURE. If non-null
|
|
it must be deleted by the caller.
|
|
--*/
|
|
|
|
|
|
//
|
|
// Called to get the status of an update request, identified by
|
|
// Generation.
|
|
//
|
|
static
|
|
WBEMSTATUS
|
|
GetUpdateStatus(
|
|
IN LPCWSTR szNicGuid,
|
|
IN UINT Generation,
|
|
IN BOOL fDelete, // Delete record if it exists
|
|
OUT WBEMSTATUS *pCompletionStatus,
|
|
OUT WCHAR **ppLog // free using delete operator.
|
|
);
|
|
|
|
static
|
|
DWORD
|
|
WINAPI
|
|
s_AsyncUpdateThreadProc(
|
|
LPVOID lpParameter // thread data
|
|
);
|
|
|
|
|
|
private:
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// S T A T I C S T U F F
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// A single static lock serialzes all access.
|
|
// Use sfn_Lock and sfn_Unlock.
|
|
//
|
|
static
|
|
CRITICAL_SECTION s_Crit;
|
|
|
|
static
|
|
BOOL
|
|
s_fStaticInitialized; // set to true once StaticInitialize is called.
|
|
|
|
static
|
|
BOOL
|
|
s_fInitialized; // Set to true if we're in the position to
|
|
// handle any *new* update requests or even queries.
|
|
// Will be set to false if we're in the process
|
|
// of de-initializing.
|
|
|
|
//
|
|
// Global list of current updates, one per NIC.
|
|
//
|
|
static
|
|
LIST_ENTRY
|
|
s_listCurrentUpdates;
|
|
|
|
static
|
|
VOID
|
|
sfn_Lock(
|
|
VOID
|
|
)
|
|
{
|
|
EnterCriticalSection(&s_Crit);
|
|
}
|
|
|
|
static
|
|
VOID
|
|
sfn_Unlock(
|
|
VOID
|
|
)
|
|
{
|
|
LeaveCriticalSection(&s_Crit);
|
|
}
|
|
|
|
//
|
|
// Looks up the current update for the specific NIC.
|
|
// We don't bother to reference count because this object never
|
|
// goes away once created -- it's one per unique NIC GUID for as long as
|
|
// the DLL is loaded (may want to revisit this).
|
|
//
|
|
//
|
|
static
|
|
WBEMSTATUS
|
|
sfn_LookupUpdate(
|
|
IN LPCWSTR szNic,
|
|
IN BOOL fCreate, // Create if required
|
|
OUT NlbConfigurationUpdate ** ppUpdate
|
|
);
|
|
|
|
//
|
|
// Save the specified completion status to the registry.
|
|
//
|
|
static
|
|
WBEMSTATUS
|
|
sfn_RegSetCompletion(
|
|
IN LPCWSTR szNicGuid,
|
|
IN UINT Generation,
|
|
IN WBEMSTATUS CompletionStatus
|
|
);
|
|
|
|
//
|
|
// Retrieve the specified completion status from the registry.
|
|
//
|
|
static
|
|
WBEMSTATUS
|
|
sfn_RegGetCompletion(
|
|
IN LPCWSTR szNicGuid,
|
|
IN UINT Generation,
|
|
OUT WBEMSTATUS *pCompletionStatus,
|
|
OUT WCHAR **ppLog // free using delete operator.
|
|
);
|
|
|
|
//
|
|
// Delete the specified completion status from the registry.
|
|
//
|
|
static
|
|
VOID
|
|
sfn_RegDeleteCompletion(
|
|
IN LPCWSTR szNicGuid,
|
|
IN UINT Generation
|
|
);
|
|
|
|
//
|
|
// Create the specified subkey key (for r/w access) for the specified
|
|
// the specified NIC.
|
|
//
|
|
static
|
|
HKEY
|
|
sfn_RegCreateKey(
|
|
IN LPCWSTR szNicGuid,
|
|
IN LPCWSTR szSubKey,
|
|
IN BOOL fVolatile,
|
|
OUT BOOL *fExists
|
|
);
|
|
|
|
//
|
|
// Open the specified subkey key (for r/w access) for the specified
|
|
// the specified NIC.
|
|
//
|
|
static
|
|
HKEY
|
|
sfn_RegOpenKey(
|
|
IN LPCWSTR szNicGuid,
|
|
IN LPCWSTR szSubKey
|
|
);
|
|
|
|
static
|
|
VOID
|
|
sfn_ReadLog(
|
|
IN HKEY hKeyLog,
|
|
IN UINT Generation,
|
|
OUT LPWSTR *ppLog
|
|
);
|
|
|
|
|
|
static
|
|
VOID
|
|
sfn_WriteLog(
|
|
IN HKEY hKeyLog,
|
|
IN UINT Generation,
|
|
IN LPCWSTR pLog,
|
|
IN BOOL fAppend
|
|
);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// P E R I N S T A N C E S T U F F
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Used in the global one-per-NIC list of updates maintained in
|
|
// s_listCurrentUpdates;
|
|
//
|
|
LIST_ENTRY m_linkUpdates;
|
|
|
|
#define NLB_GUID_LEN 38
|
|
#define NLB_GUID_STRING_SIZE 40 // 38 for the GUID plus trailing NULL + pad
|
|
WCHAR m_szNicGuid[NLB_GUID_STRING_SIZE]; // NIC's GUID in text form
|
|
|
|
LONG m_RefCount;
|
|
|
|
typedef enum
|
|
{
|
|
UNINITIALIZED, // IDLE -- no ongoing updates
|
|
IDLE, // IDLE -- no ongoing updates
|
|
ACTIVE // There is an ongoing update
|
|
|
|
} MyState;
|
|
|
|
MyState m_State;
|
|
|
|
//
|
|
// Following mutexes are used to ensure that only a single concurrent
|
|
// update can happen per NIC.
|
|
//
|
|
struct
|
|
{
|
|
HANDLE hMtx1; // Mutex handle; Obtained 1st
|
|
HANDLE hMtx2; // Mutex handle; Obtained 2nd, then hMtx1 is released.
|
|
HANDLE hEvt; // Unnamed evt, signaled when hMtx2 is obtained.
|
|
|
|
} m_mutex;
|
|
|
|
//
|
|
// The following fields are valid only when the state is ACTIVE
|
|
//
|
|
UINT m_Generation; // Current generation count
|
|
#define NLBUPD_MAX_CLIENT_DESCRIPTION_LENGTH 64
|
|
WCHAR m_szClientDescription[NLBUPD_MAX_CLIENT_DESCRIPTION_LENGTH+1];
|
|
DWORD m_AsyncThreadId; // Thread doing async config update operation.
|
|
HANDLE m_hAsyncThread; // ID of above thread.
|
|
HKEY m_hCompletionKey; // Key to the registry where
|
|
// completions are stored
|
|
|
|
//
|
|
// A snapshot of the cluster configuration state at the start
|
|
// of the update BUG -- can this be zeromemoried?
|
|
//
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION m_OldClusterConfig;
|
|
|
|
//
|
|
// The requested final state
|
|
//
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION m_NewClusterConfig;
|
|
|
|
|
|
//
|
|
// Completion status of the current update.
|
|
// Could be PENDING.
|
|
//
|
|
WBEMSTATUS m_CompletionStatus;
|
|
|
|
|
|
//
|
|
// END -- of fields that are valid only when the state is ACTIVE
|
|
//
|
|
|
|
|
|
//
|
|
// Constructor and destructor -- note that these are private
|
|
// In fact, the constructor is only called from sfn_LookupUpdate
|
|
// and the destructor from mfn_Dereference.
|
|
//
|
|
NlbConfigurationUpdate(VOID);
|
|
~NlbConfigurationUpdate();
|
|
|
|
//
|
|
// Try to acquire the machine-wide
|
|
// NLB configuration update event for this NIC, and create the
|
|
// appropriate keys in the registry to track this update.
|
|
// NOTE: ppLog will be filled out EVEN ON FAILURE -- it should always
|
|
// be deleted by the caller (using the delete operator) if non-NULL.
|
|
//
|
|
WBEMSTATUS
|
|
mfn_StartUpdate(
|
|
IN PNLB_EXTENDED_CLUSTER_CONFIGURATION pNewState,
|
|
IN LPCWSTR szClientDescription,
|
|
OUT BOOL *pfDoAsync,
|
|
OUT WCHAR ** ppLog
|
|
);
|
|
|
|
//
|
|
// Increment ref count. Object stays alive as long as refcount is nonzero.
|
|
//
|
|
VOID
|
|
mfn_Reference(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Decrement ref count. Object is deleted when refcount goes to zero.
|
|
//
|
|
VOID
|
|
mfn_Dereference(
|
|
VOID
|
|
);
|
|
//
|
|
// Release the machine-wide update event for this NIC, and delete any
|
|
// temporary entries in the registry that were used for this update.
|
|
// ppLog must be deleted by caller useing the delete operator.
|
|
//
|
|
VOID
|
|
mfn_StopUpdate(
|
|
OUT WCHAR ** ppLog
|
|
);
|
|
|
|
//
|
|
// Looks up the completion record identified by Generation, for
|
|
// specific NIC (identified by *this).
|
|
//
|
|
//
|
|
BOOL
|
|
mfn_LookupCompletion(
|
|
IN UINT Generation,
|
|
OUT PNLB_COMPLETION_RECORD *pCompletionRecord
|
|
);
|
|
|
|
//
|
|
// Uses various windows APIs to fill up the current extended cluster
|
|
// information for a specific nic (identified by *this).
|
|
// It fills out pNewCfg.
|
|
// The pNewCfg->field is set to TRUE IFF there were
|
|
// no errors trying to fill out the information.
|
|
//
|
|
//
|
|
WBEMSTATUS
|
|
mfn_GetCurrentClusterConfiguration(
|
|
OUT PNLB_EXTENDED_CLUSTER_CONFIGURATION pCfg
|
|
);
|
|
|
|
//
|
|
// Analyzes the nature of the update, mainly to decide whether or not
|
|
// we need to do the update asynchronously.
|
|
// This also performs parameter validation.
|
|
//
|
|
WBEMSTATUS
|
|
mfn_AnalyzeUpdate(
|
|
IN PNLB_EXTENDED_CLUSTER_CONFIGURATION pNewCfg,
|
|
IN BOOL *pDoAsync,
|
|
IN CLocalLogger &logger
|
|
);
|
|
|
|
//
|
|
// Does the update synchronously -- this is where the meat of the update
|
|
// logic exists. It can range from a NoOp, through changing the
|
|
// fields of a single port rule, through binding NLB, setting up cluster
|
|
// parameters and adding the relevant IP addresses in TCPIP.
|
|
//
|
|
VOID
|
|
mfn_ReallyDoUpdate(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
mfn_Log(
|
|
UINT Id, // Resource ID of format,
|
|
...
|
|
);
|
|
|
|
VOID
|
|
mfn_LogRawText(
|
|
LPCWSTR szText
|
|
);
|
|
|
|
//
|
|
// Stop the current cluster and take out its vips.
|
|
//
|
|
VOID
|
|
mfn_TakeOutVips(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Acquires the first global mutex, call this first.
|
|
//
|
|
WBEMSTATUS
|
|
mfn_AcquireFirstMutex(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// If (fCancel) it releases the first mutex mutex and clears up handles
|
|
// to 2nd mutex and evt.
|
|
// else it will wait until it receives signal that the 2nd mutex is
|
|
// acquired, and then clears up only the 1st mutex handle.
|
|
//
|
|
WBEMSTATUS
|
|
mfn_ReleaseFirstMutex(
|
|
BOOL fCancel
|
|
);
|
|
|
|
//
|
|
// Acquire the 2nd mutex (could be called from a different thread
|
|
// than the one that called mfn_AcquireFirstMutex.
|
|
// Also signals an internal event which mfn_ReleaseFirstMutex may
|
|
// be waiting on.
|
|
//
|
|
WBEMSTATUS
|
|
mfn_AcquireSecondMutex(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Releases the second mutex.
|
|
//
|
|
WBEMSTATUS
|
|
mfn_ReleaseSecondMutex(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Writes an NT event when the update is stopping
|
|
//
|
|
VOID
|
|
ReportStopEvent(
|
|
const WORD wEventType,
|
|
WCHAR **ppLog
|
|
);
|
|
|
|
//
|
|
// Writes an NT event when the update is starting
|
|
//
|
|
VOID
|
|
ReportStartEvent(
|
|
LPCWSTR szClientDescription
|
|
);
|
|
};
|
|
|
|
VOID
|
|
test_port_rule_string(
|
|
VOID
|
|
);
|