windows-nt/Source/XPSP1/NT/net/wlbs/nlbmgr/provider/tests/nlbhost.cpp
2020-09-26 16:20:57 +08:00

2022 lines
50 KiB
C++

/*++
Copyright(c) 2001 Microsoft Corporation
Module Name:
NLB Manager
File Name:
nlbhost.cpp
Abstract:
Implementation of class NLBHost
NLBHost is responsible for connecting to an NLB host and getting/setting
its NLB-related configuration.
History:
03/31/01 JosephJ Created
--*/
#include "tprov.h"
#include "nlbhost.tmh"
//
// Static members of class NLBHost.
//
WSADATA NLBHost::s_WsaData;
LONG NLBHost::s_InstanceCount;
BOOL NLBHost::s_FatalError;
BOOL NLBHost::s_WsaInitialized;
BOOL NLBHost::s_ComInitialized;
IWbemStatusCodeTextPtr NLBHost::s_sp_werr; // Smart pointer
WBEMSTATUS
extract_GetClusterConfiguration_output_params(
IN IWbemClassObjectPtr spWbemOutput,
OUT PNLB_EXTENDED_CLUSTER_CONFIGURATION pCfg
);
WBEMSTATUS
setup_GetClusterConfiguration_input_params(
IN LPCWSTR szNic,
IN IWbemClassObjectPtr spWbemInput
);
WBEMSTATUS
setup_UpdateClusterConfiguration_input_params(
IN LPCWSTR szNic,
IN PNLB_EXTENDED_CLUSTER_CONFIGURATION pCfg,
IN IWbemClassObjectPtr spWbemInput
);
VOID
NLBHost::mfn_LogHr(
LPCWSTR pwszMessage,
HRESULT hr
)
{
if (s_sp_werr)
{
BSTR bstr1 = 0;
BSTR bstr2 = 0;
SCODE sc;
sc = s_sp_werr->GetFacilityCodeText( hr,
0,
0,
&bstr1 );
if( sc != S_OK )
{
bstr2 = L"Unknown Error";
}
sc = s_sp_werr->GetErrorCodeText( hr,
0,
0,
&bstr2 );
if( sc != S_OK )
{
bstr2 = L"Unknown Code";
}
mfn_Log(
L"%s %s: %s(hr=0x%08lx)",
pwszMessage,
(LPCWSTR) bstr1,
(LPCWSTR) bstr2,
hr
);
SysFreeString( bstr1 );
SysFreeString( bstr2 );
}
else
{
mfn_Log(
L"%s (hr=0x%08lx)",
pwszMessage,
hr
);
}
}
VOID
NLBHost::mfn_Log(
LPCWSTR pwszMessage,
...
)
{
WCHAR wszBuffer[1024];
wszBuffer[0] = 0;
va_list arglist;
va_start (arglist, pwszMessage);
int cch = vswprintf(wszBuffer, pwszMessage, arglist);
va_end (arglist);
m_pfnLogger(m_pLoggerContext, wszBuffer);
}
NLBHost::NLBHost(
const WCHAR * pBindString,
const WCHAR * pFriendlyName,
PFN_LOGGER pfnLogger,
PVOID pLoggerContext
)
/*++
Routine Description:
Constructor for NLBHost.
The constructor does not initiate any connections to the host. Connections
to the host are initiated on demand (based on method calls).
Arguments:
pBindString - String used to connect to the remote host.
pFriendlyName - Descriptive name of the host. Used for logging.
pfnLogger - Function called to log textual information.
pLoggerContext - Caller's context, passed in calls to pfnLogger
--*/
{
m_BindString = pBindString; // implicit copy
m_FriendlyName = pFriendlyName; // implicit copy
m_pfnLogger = pfnLogger;
m_pLoggerContext = pLoggerContext;
if (InterlockedIncrement(&s_InstanceCount) == 1)
{
mfn_InitializeStaticFields();
}
InitializeCriticalSection(&m_Lock);
mfn_Log(
L"NLBHost(BindString=%s, FriendlyName=%s) constructor succeeded.",
(LPCWSTR) pBindString,
(LPCWSTR) pFriendlyName
);
}
NLBHost::~NLBHost()
/*++
Routine Description:
Destructor for NLBHost.
--*/
{
mfn_Log(L"NLBHost distructor(%s).", (LPCWSTR) m_FriendlyName);
ASSERT(m_fProcessing == FALSE); // Shouldn't be doing any processing when
// calling the distructor.
if (InterlockedDecrement(&s_InstanceCount)==0)
{
mfn_DeinitializeStaticFields();
}
DeleteCriticalSection(&m_Lock);
}
UINT
NLBHost::Ping(
VOID
)
{
if (s_FatalError) return ERROR_INTERNAL_ERROR;
return mfn_ping();
}
WBEMSTATUS
NLBHost::GetHostInformation(
OUT HostInformation **ppHostInfo
)
{
WBEMSTATUS Status;
HostInformation *pHostInfo = NULL;
BOOL fConnected = FALSE;
NicInformation *pNicInfo=NULL;
if (s_FatalError)
{
Status = WBEM_E_CRITICAL_ERROR;
goto end;
}
pHostInfo = new HostInformation;
if (pHostInfo == NULL)
{
Status = WBEM_E_OUT_OF_MEMORY;
goto end;
}
//
// Connect to the host.
//
Status = mfn_connect();
if (FAILED(Status)) goto end;
fConnected = TRUE;
#if 0
//
// Now find the instance and execute the method to get the host info.
//
mfn_find_host_instance();
... stuff parameters ...
mfn_execute_method();
#endif //
pHostInfo->MachineName = L"ACME-Machine-Name";
pNicInfo = pHostInfo->nicInformation;
pNicInfo->fullNicName = L"ACME Full Nic Name";
pNicInfo->adapterGuid = L"{AD4DA14D-CAAE-42DD-97E3-5355E55247C2}";
pNicInfo->friendlyName = L"ACME Friendly Name";
pHostInfo->NumNics = 1;
end:
if (fConnected)
{
mfn_disconnect();
}
if (FAILED(Status))
{
if (pHostInfo != NULL)
{
delete pHostInfo;
}
pHostInfo = NULL;
}
*ppHostInfo = pHostInfo;
return Status;
}
//
// Configuration operations:
//
WBEMSTATUS
NLBHost::GetClusterConfiguration(
IN const WCHAR* pNicGuid,
OUT PNLB_EXTENDED_CLUSTER_CONFIGURATION pCfg
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
IWbemClassObjectPtr spWbemInputInstance = NULL; // smart pointer
BOOL fConnected = FALSE;
LPWSTR pRelPath = NULL;
IWbemClassObjectPtr spWbemOutput = NULL; // smart pointer.
ZeroMemory(pCfg, sizeof(*pCfg));
if (s_FatalError)
{
Status = WBEM_E_CRITICAL_ERROR;
goto end;
}
//
// Connect to the host.
//
Status = mfn_connect();
if (FAILED(Status)) goto end;
fConnected = TRUE;
mfn_Log(
L"NLBHost -- getting cluster configuration on NIC (%s).",
pNicGuid
);
//
// Get input instance and relpath...
//
Status = CfgUtilGetWmiInputInstanceAndRelPath(
m_sp_pws,
L"NlbsNic", // szClassName
L"AdapterGuid", // szParameterName
pNicGuid, // szPropertyValue
L"GetClusterConfiguration", // szMethodName,
spWbemInputInstance, // smart pointer
&pRelPath // free using delete
);
if (FAILED(Status))
{
mfn_Log(
L"NLBHost -- error 0x%08lx trying to find NIC instance\n",
(UINT) Status
);
goto end;
}
//
// NOTE: spWbemInputInstance could be NULL -- in fact it is
// NULL because GetClusterConfiguration doesn't require input args
//
//
// Run the Method!
//
{
HRESULT hr;
printf("Going to call GetClusterConfiguration\n");
hr = m_sp_pws->ExecMethod(
_bstr_t(pRelPath),
L"GetClusterConfiguration",
0,
NULL,
spWbemInputInstance,
&spWbemOutput,
NULL
);
printf("GetClusterConfiguration returns\n");
if( FAILED( hr) )
{
printf("IWbemServices::ExecMethod failure 0x%08lx\n", (UINT) hr);
goto end;
}
else
{
printf("GetClusterConfiguration method returns SUCCESS!\n");
}
if (spWbemOutput == NULL)
{
//
// Hmm --- no output ?!
//
printf("ExecMethod GetClusterConfiguration had no output\n");
Status = WBEM_E_NOT_FOUND;
goto end;
}
}
//
// Extract all the out parameters!
//
{
DWORD dwRet=0;
Status = CfgUtilGetWmiDWORDParam(
spWbemOutput,
L"ReturnValue",
&dwRet
);
if (FAILED(Status))
{
printf("IWbemClassObject::Get failure\n");
//
// Let's ignore for now...
//
dwRet = 0;
}
Status = extract_GetClusterConfiguration_output_params(
spWbemOutput,
pCfg
);
}
end:
if (fConnected)
{
mfn_disconnect();
}
if (pRelPath != NULL)
{
delete pRelPath;
}
spWbemInputInstance = NULL; // smart pointer.
return Status;
}
WBEMSTATUS
NLBHost::SetClusterConfiguration(
IN const WCHAR * pNicGuid,
IN const PNLB_EXTENDED_CLUSTER_CONFIGURATION pCfg,
IN UINT GenerationId,
OUT UINT * pRequestId
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
if (s_FatalError)
{
goto end;
}
mfn_Log(
L"NLBHost -- setting cluster configuration on NIC (%s).",
pNicGuid
);
*pRequestId = 123;
Status = WBEM_S_PENDING;
end:
return Status;
}
WBEMSTATUS
NLBHost::GetAsyncResult(
IN UINT RequestId,
OUT UINT * pGenerationId,
OUT UINT * pResultCode,
OUT _bstr_t * pResultText
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
if (s_FatalError)
{
goto end;
}
mfn_Log(
L"NLBHost -- checking result of Async operation %d\n",
RequestId
);
*pGenerationId = 1;
*pResultCode = 1;
*pResultText = L"Result";
Status = WBEM_NO_ERROR;
end:
return Status;
}
WBEMSTATUS
NLBHost::mfn_connect(
VOID
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
HRESULT hr;
_bstr_t serverPath;
hr = CoCreateInstance(CLSID_WbemLocator, 0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator,
(LPVOID *) &m_sp_pwl);
if (FAILED(hr))
{
mfn_LogHr(L"CoCreateInstance IWebmLocator failed", hr);
m_sp_pwl = NULL;
goto end;
}
//
serverPath = _bstr_t(L"\\\\") + m_BindString + L"\\root\\microsoftnlb";
hr = m_sp_pwl->ConnectServer(
serverPath,
NULL, // strUser,
NULL, // strPassword,
NULL,
0,
NULL,
NULL,
&m_sp_pws
);
// these have been found to be special cases where retrying may help.
if( ( hr == 0x800706bf ) || ( hr == 0x80070767 ) || ( hr == 0x80070005 ) )
{
int delay = 250; // milliseconds
int timesToRetry = 20;
for( int i = 0; i < timesToRetry; ++i )
{
Sleep(delay);
mfn_Log(L"connectserver recoverable failure, retrying.");
hr = m_sp_pwl->ConnectServer(
serverPath,
NULL, // strUser,
NULL, // strPassword,
NULL,
0,
NULL,
NULL,
&m_sp_pws );
if( !FAILED( hr) )
{
break;
}
}
}
else if ( hr == 0x80041064 )
{
// trying to connect to local machine. Cannot use credentials.
mfn_Log(L"Connecting to self. Retrying without using credentials");
hr = m_sp_pwl->ConnectServer(
serverPath,
NULL,
NULL,
0,
NULL,
0,
0,
&m_sp_pws
);
}
if (FAILED(hr))
{
mfn_LogHr(L"Error connecting to server", hr);
m_sp_pws = NULL;
goto end;
}
else
{
mfn_Log(L"Successfully connected to server %s", serverPath);
}
// Set the proxy so that impersonation of the client occurs.
//
hr = CoSetProxyBlanket(
m_sp_pws,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_NAME,
COLE_DEFAULT_PRINCIPAL, // NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
COLE_DEFAULT_AUTHINFO, // NULL,
EOAC_DEFAULT // EOAC_NONE
);
if (FAILED(hr))
{
mfn_LogHr(L"Error setting proxy blanket", hr);
goto end;
}
else
{
mfn_Log(L"Successfully set up proxy settings.");
}
Status = WBEM_NO_ERROR;
end:
if (FAILED(Status))
{
if (m_sp_pws != NULL)
{
// Smart pointer.
m_sp_pws = NULL;
}
if (m_sp_pwl != NULL)
{
// Smart pointer.
m_sp_pwl = NULL;
}
}
return Status;
}
VOID
NLBHost::mfn_disconnect(
VOID
)
{
mfn_Log(L"Disconnecting from host %s", m_BindString);
if (m_sp_pws != NULL)
{
// Smart pointer
m_sp_pws = NULL;
}
if (m_sp_pwl != NULL)
{
// Smart pointer
m_sp_pwl = NULL;
}
}
VOID
NLBHost::mfn_InitializeStaticFields(
VOID
)
{
s_FatalError = TRUE;
// Initialize com.
//
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
if ( FAILED(hr) )
{
mfn_Log(L"Failed to initialize COM library (hr=0x%08lx)", hr);
goto end;
}
s_ComInitialized = TRUE;
//
// Initialize Winsock
//
int err = WSAStartup(MAKEWORD(2,2), &s_WsaData);
mfn_Log(L"Initializing Winsock");
err = WSAStartup(MAKEWORD(2,2), &s_WsaData);
if (err) {
mfn_Log(L"PING_WSASTARTUP_FAILED %d", GetLastError());
goto end;
}
s_WsaInitialized = TRUE;
s_FatalError = FALSE;
//
// Get some WMI interface pointers...
//
SCODE sc = CoCreateInstance(
CLSID_WbemStatusCodeText,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemStatusCodeText,
(LPVOID *) &s_sp_werr
);
if( sc != S_OK )
{
s_sp_werr = NULL;
mfn_Log(L"CoCreateInstance IWbemStatusCodeText failure\n");
}
end:
if (s_FatalError)
{
mfn_DeinitializeStaticFields();
}
}
VOID
NLBHost::mfn_DeinitializeStaticFields(
VOID
)
{
if (s_sp_werr != NULL)
{
s_sp_werr = NULL; // Smart pointer
}
if (s_WsaInitialized)
{
mfn_Log(L"Deinitializing Winsock");
WSACleanup();
s_WsaInitialized = FALSE;
}
if (s_ComInitialized)
{
mfn_Log(L"Deinitializing COM");
CoUninitialize();
s_ComInitialized = FALSE;
}
}
#if 0
WBEMSTATUS
extract_extended_config_from_wmi(
IN IWbemClassObjectPtr &spWbemOutput,
OUT PNLB_EXTENDED_CLUSTER_CONFIGURATION pCfg
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
NLB_IP_ADDRESS_INFO *pIpInfo = NULL;
UINT NumIpAddresses = 0;
BOOL fNlbBound = FALSE;
WLBS_REG_PARAMS NlbParams; // The WLBS-specific configuration
BOOL fNlbParamsValid = FALSE;
UINT Generation = 1;
//
// Verify that pCfg is indeed zero-initialized.
// We are doing this because we want to make sure that the caller
// doesn't pass in a perviously initialized pCfg which may have a non-null
// ip address array.
//
{
BYTE *pb = (BYTE*) pCfg;
BYTE *pbEnd = (BYTE*) (pCfg+1);
for (; pb < pbEnd; pb++)
{
if (*pb!=0)
{
printf(L"uninitialized pCfg\n");
ASSERT(!"uninitialized pCfg");
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
}
}
//
// Get the ip address list.
//
Status = CfgUtilGetStaticIpAddresses(
m_szNicGuid,
&NumIpAddresses,
&pIpInfo
);
if (FAILED(Status))
{
printf("Error 0x%08lx getting ip address list for %ws\n",
(UINT) Status, m_szNicGuid);
mfn_Log(L"Error IP Address list on this NIC\n");
pIpInfo = NULL;
goto end;
}
//
// TEST TEST TEST
//
if (0)
{
if (NumIpAddresses>1)
{
//
// Let's munge the 2nd IP address
//
if (!_wcsicmp(pIpInfo[1].IpAddress, L"10.0.0.33"))
{
wcscpy(pIpInfo[1].IpAddress, L"10.0.0.44");
}
else
{
wcscpy(pIpInfo[1].IpAddress, L"10.0.0.33");
}
}
MyBreak(L"Break just before calling CfgUtilSetStaticIpAddresses\n");
Status = CfgUtilSetStaticIpAddresses(
m_szNicGuid,
NumIpAddresses,
pIpInfo
);
}
//
// Check if NLB is bound
//
Status = CfgUtilCheckIfNlbBound(
m_szNicGuid,
&fNlbBound
);
if (FAILED(Status))
{
printf("Error 0x%08lx determining if NLB is bound to %ws\n",
(UINT) Status, m_szNicGuid);
mfn_Log(L"Error determining if NLB is bound to this NIC\n");
goto end;
}
if (fNlbBound)
{
//
// Get the latest NLB configuration information for this NIC.
//
Status = CfgUtilGetNlbConfig(
m_szNicGuid,
&NlbParams
);
if (FAILED(Status))
{
//
// We don't consider a catastrophic failure.
//
printf("Error 0x%08lx reading NLB configuration for %ws\n",
(UINT) Status, m_szNicGuid);
mfn_Log(L"Error reading NLB configuration for this NIC\n");
Status = WBEM_NO_ERROR;
fNlbParamsValid = FALSE;
ZeroMemory(&NlbParams, sizeof(NlbParams));
}
else
{
fNlbParamsValid = TRUE;
}
}
//
// Get the current generation
//
{
BOOL fExists=FALSE;
HKEY hKey = sfn_RegOpenKey(
m_szNicGuid,
NULL // NULL == root for this guid.,
);
Generation = 1; // We assume generation is 1 on error reading gen.
if (hKey!=NULL)
{
LONG lRet;
DWORD dwType;
DWORD dwData;
dwData = sizeof(Generation);
lRet = RegQueryValueEx(
hKey, // handle to key to query
L"Generation", // address of name of value to query
NULL, // reserved
&dwType, // address of buffer for value type
(LPBYTE) &Generation, // address of data buffer
&dwData // address of data buffer size
);
if ( lRet != ERROR_SUCCESS
|| dwType != REG_DWORD
|| dwData != sizeof(Generation))
{
//
// Couldn't read the generation. Let's assume it's
// a starting value of 1.
//
printf("Error reading generation for %ws; assuming its 0\n",
m_szNicGuid);
Generation = 1;
}
}
}
//
// Success ... fill out pCfg
//
pCfg->fValidNlbCfg = fNlbParamsValid;
pCfg->Generation = Generation;
pCfg->fBound = fNlbBound;
pCfg->NumIpAddresses = NumIpAddresses;
pCfg->pIpAddressInfo = pIpInfo;
if (fNlbBound)
{
pCfg->NlbParams = NlbParams; // struct copy
}
Status = WBEM_NO_ERROR;
end:
if (FAILED(Status))
{
if (pIpInfo!=NULL)
{
delete pIpInfo;
}
pCfg->fValidNlbCfg = FALSE;
}
return Status;
return WBEM_NO_ERROR;
}
#endif // 0
WBEMSTATUS
NlbHostGetConfiguration(
IN LPCWSTR szMachine, // empty string for local
IN LPCWSTR szNicGuid,
OUT PNLB_EXTENDED_CLUSTER_CONFIGURATION pCurrentCfg
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
IWbemServicesPtr spWbemService = NULL; // Smart pointer
IWbemClassObjectPtr spWbemInput = NULL; // smart pointer
IWbemClassObjectPtr spWbemOutput = NULL; // smart pointer.
LPWSTR pRelPath = NULL;
//
// Get interface to the NLB namespace on the specified machine
//
{
#define _MaxLen 256
WCHAR NetworkResource[_MaxLen];
if (*szMachine == 0)
{
szMachine = L".";
}
_snwprintf(NetworkResource, (_MaxLen-1), L"\\\\%ws\\root\\microsoftnlb",
szMachine);
NetworkResource[_MaxLen-1]=0;
wprintf(L"Connecting to NLB on %ws ...\n", szMachine);
Status = CfgUtilConnectToServer(
NetworkResource,
NULL, // szUser
NULL, // szPassword
NULL, // szAuthority (domain)
&spWbemService
);
if (FAILED(Status))
{
wprintf(L"ERROR: COULD NOT CONNECT TO NLB ON %ws\n", szMachine);
goto end;
}
wprintf(L"Successfully connected to NLB on %ws...\n", szMachine);
}
//
// Get wmi input instance to "GetClusterConfiguration" method
//
{
Status = CfgUtilGetWmiInputInstanceAndRelPath(
spWbemService,
L"NlbsNic", // szClassName
L"AdapterGuid", // szParameterName
szNicGuid, // szPropertyValue
L"GetClusterConfiguration", // szMethodName,
spWbemInput, // smart pointer
&pRelPath // free using delete
);
if (FAILED(Status))
{
wprintf(
L"ERROR 0x%08lx trying to get instance of GetClusterConfiguration\n",
(UINT) Status
);
goto end;
}
}
//
// Setup params for the "GetClusterConfiguration" method
// NOTE: spWbemInput could be NULL.
//
Status = setup_GetClusterConfiguration_input_params(
szNicGuid,
spWbemInput
);
if (FAILED(Status))
{
goto end;
}
//
// Call the "GetClusterConfiguration" method
//
{
HRESULT hr;
wprintf(L"Going get GetClusterConfiguration...\n");
hr = spWbemService->ExecMethod(
_bstr_t(pRelPath),
L"GetClusterConfiguration",
0,
NULL,
spWbemInput,
&spWbemOutput,
NULL
);
if( FAILED( hr) )
{
wprintf(L"GetClusterConfiguration returns with failure 0x%8lx\n",
(UINT) hr);
goto end;
}
else
{
wprintf(L"GetClusterConfiguration returns successfully\n");
}
if (spWbemOutput == NULL)
{
//
// Hmm --- no output ?!
//
printf("ExecMethod GetClusterConfiguration had no output");
Status = WBEM_E_NOT_FOUND;
goto end;
}
}
//
// Extract params from the "GetClusterConfiguration" method
//
Status = extract_GetClusterConfiguration_output_params(
spWbemOutput,
pCurrentCfg
);
end:
if (pRelPath != NULL)
{
delete pRelPath;
}
spWbemService = NULL; // Smart pointer
spWbemInput = NULL; // smart pointer
spWbemOutput = NULL; // smart pointer.
return Status;
}
WBEMSTATUS
NlbHostDoUpdate(
IN LPCWSTR szMachine, // NULL or empty for local
IN LPCWSTR szNicGuid,
IN LPCWSTR szClientDescription,
IN PNLB_EXTENDED_CLUSTER_CONFIGURATION pNewState,
OUT UINT *pGeneration,
OUT WCHAR **ppLog // free using delete operator.
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
IWbemServicesPtr spWbemService = NULL; // Smart pointer
IWbemClassObjectPtr spWbemInput = NULL; // smart pointer
IWbemClassObjectPtr spWbemOutput = NULL; // smart pointer.
LPWSTR pRelPath = NULL;
*pGeneration = 0;
*ppLog = NULL;
//
// Get interface to the NLB namespace on the specified machine
//
{
#define _MaxLen 256
WCHAR NetworkResource[_MaxLen];
if (*szMachine == 0)
{
szMachine = L".";
}
_snwprintf(NetworkResource, (_MaxLen-1), L"\\\\%ws\\root\\microsoftnlb",
szMachine);
NetworkResource[_MaxLen-1]=0;
wprintf(L"Connecting to NLB on %ws ...\n", szMachine);
Status = CfgUtilConnectToServer(
NetworkResource,
NULL, // szUser
NULL, // szPassword
NULL, // szAuthority (domain)
&spWbemService
);
if (FAILED(Status))
{
wprintf(L"ERROR: COULD NOT CONNECT TO NLB ON %ws\n", szMachine);
goto end;
}
wprintf(L"Successfully connected to NLB on %ws...\n", szMachine);
}
//
// Get wmi input instance to "UpdateClusterConfiguration" method
//
{
Status = CfgUtilGetWmiInputInstanceAndRelPath(
spWbemService,
L"NlbsNic", // szClassName
L"AdapterGuid", // szParameterName
szNicGuid, // szPropertyValue
L"UpdateClusterConfiguration", // szMethodName,
spWbemInput, // smart pointer
&pRelPath // free using delete
);
if (FAILED(Status))
{
wprintf(
L"ERROR 0x%08lx trying to get instance of UpdateConfiguration\n",
(UINT) Status
);
goto end;
}
}
//
// Setup params for the "UpdateClusterConfiguration" method
// NOTE: spWbemInput could be NULL.
//
Status = setup_UpdateClusterConfiguration_input_params(
szNicGuid,
pNewState,
spWbemInput
);
if (FAILED(Status))
{
goto end;
}
//
// Call the "UpdateClusterConfiguration" method
//
{
HRESULT hr;
wprintf(L"Going get UpdateClusterConfiguration...\n");
hr = spWbemService->ExecMethod(
_bstr_t(pRelPath),
L"UpdateClusterConfiguration",
0,
NULL,
spWbemInput,
&spWbemOutput,
NULL
);
if( FAILED( hr) )
{
wprintf(L"UpdateConfiguration returns with failure 0x%8lx\n",
(UINT) hr);
goto end;
}
else
{
wprintf(L"UpdateConfiguration returns successfully\n");
}
if (spWbemOutput == NULL)
{
//
// Hmm --- no output ?!
//
printf("ExecMethod UpdateConfiguration had no output");
Status = WBEM_E_NOT_FOUND;
goto end;
}
}
//
// Extract params from the "UpdateClusterConfiguration" method
//
{
DWORD dwReturnValue = 0;
Status = CfgUtilGetWmiDWORDParam(
spWbemOutput,
L"ReturnValue", // <--------------------------------
&dwReturnValue
);
if (FAILED(Status))
{
wprintf(L"Attempt to read ReturnValue failed. Error=0x%08lx\n",
(UINT) Status);
goto end;
}
LPWSTR szLog = NULL;
Status = CfgUtilGetWmiStringParam(
spWbemOutput,
L"Log", // <-------------------------
&szLog
);
if (FAILED(Status))
{
szLog = NULL;
}
*ppLog = szLog;
DWORD dwGeneration = 0;
Status = CfgUtilGetWmiDWORDParam(
spWbemOutput,
L"NewGeneration", // <--------------------------------
&dwGeneration
);
if (FAILED(Status))
{
//
// Generation should always be specified for pending operations.
// TODO: for successful operations also?
//
if ((WBEMSTATUS)dwReturnValue == WBEM_S_PENDING)
{
wprintf(L"Attempt to read NewGeneration for pending update failed. Error=0x%08lx\n",
(UINT) Status);
Status = WBEM_E_CRITICAL_ERROR;
goto end;
}
dwGeneration = 0; // we don't care if it's not set for non-pending
}
*pGeneration = (UINT) dwGeneration;
//
// Make the return status reflect the true status of the update
// operation.
//
Status = (WBEMSTATUS) dwReturnValue;
}
end:
if (pRelPath != NULL)
{
delete pRelPath;
}
spWbemService = NULL; // Smart pointer
spWbemInput = NULL; // smart pointer
spWbemOutput = NULL; // smart pointer.
return Status;
}
WBEMSTATUS
NlbHostGetUpdateStatus(
IN LPCWSTR szMachine, // NULL or empty for local
IN LPCWSTR szNicGuid,
IN UINT Generation,
OUT WBEMSTATUS *pCompletionStatus,
OUT WCHAR **ppLog // free using delete operator.
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
IWbemServicesPtr spWbemService = NULL; // Smart pointer
IWbemClassObjectPtr spWbemInput = NULL; // smart pointer
IWbemClassObjectPtr spWbemOutput = NULL; // smart pointer.
LPWSTR pRelPath = NULL;
*ppLog = NULL;
*pCompletionStatus = WBEM_E_CRITICAL_ERROR;
//
// Get interface to the NLB namespace on the specified machine
//
{
#define _MaxLen 256
WCHAR NetworkResource[_MaxLen];
if (*szMachine == 0)
{
szMachine = L".";
}
_snwprintf(NetworkResource, (_MaxLen-1), L"\\\\%ws\\root\\microsoftnlb",
szMachine);
NetworkResource[_MaxLen-1]=0;
// wprintf(L"Connecting to NLB on %ws ...\n", szMachine);
Status = CfgUtilConnectToServer(
NetworkResource,
NULL, // szUser
NULL, // szPassword
NULL, // szAuthority (domain)
&spWbemService
);
if (FAILED(Status))
{
wprintf(L"ERROR: COULD NOT CONNECT TO NLB ON %ws\n", szMachine);
goto end;
}
// wprintf(L"Successfully connected to NLB on %ws...\n", szMachine);
}
//
// Get wmi input instance to "QueryConfigurationUpdateStatus" method
//
{
Status = CfgUtilGetWmiInputInstanceAndRelPath(
spWbemService,
L"NlbsNic", // szClassName
L"AdapterGuid", // szParameterName
szNicGuid, // szPropertyValue
L"QueryConfigurationUpdateStatus", // szMethodName,
spWbemInput, // smart pointer
&pRelPath // free using delete
);
if (FAILED(Status))
{
wprintf(
L"ERROR 0x%08lx trying to find instance to QueryUpdateStatus\n",
(UINT) Status
);
goto end;
}
}
//
// Setup params for the "QueryConfigurationUpdateStatus" method
// NOTE: spWbemInput could be NULL.
//
{
Status = CfgUtilSetWmiStringParam(
spWbemInput,
L"AdapterGuid",
szNicGuid
);
if (FAILED(Status))
{
wprintf(
L"Couldn't set Adapter GUID parameter to QueryUpdateStatus\n");
goto end;
}
Status = CfgUtilSetWmiDWORDParam(
spWbemInput,
L"Generation",
Generation
);
if (FAILED(Status))
{
wprintf(
L"Couldn't set Generation parameter to QueryUpdateStatus\n");
goto end;
}
}
//
// Call the "QueryConfigurationUpdateStatus" method
//
{
HRESULT hr;
// wprintf(L"Going call QueryConfigurationUpdateStatus...\n");
hr = spWbemService->ExecMethod(
_bstr_t(pRelPath),
L"QueryConfigurationUpdateStatus", // szMethodName,
0,
NULL,
spWbemInput,
&spWbemOutput,
NULL
);
if( FAILED( hr) )
{
wprintf(L"QueryConfigurationUpdateStatus returns with failure 0x%8lx\n",
(UINT) hr);
goto end;
}
else
{
// wprintf(L"QueryConfigurationUpdateStatus returns successfully\n");
}
if (spWbemOutput == NULL)
{
//
// Hmm --- no output ?!
//
printf("ExecMethod QueryConfigurationUpdateStatus had no output");
Status = WBEM_E_NOT_FOUND;
goto end;
}
}
//
// Extract output params --- return code and log.
//
{
DWORD dwReturnValue = 0;
Status = CfgUtilGetWmiDWORDParam(
spWbemOutput,
L"ReturnValue", // <--------------------------------
&dwReturnValue
);
if (FAILED(Status))
{
wprintf(L"Attempt to read ReturnValue failed. Error=0x%08lx\n",
(UINT) Status);
goto end;
}
*pCompletionStatus = (WBEMSTATUS) dwReturnValue;
LPWSTR szLog = NULL;
Status = CfgUtilGetWmiStringParam(
spWbemOutput,
L"Log", // <-------------------------
&szLog
);
if (FAILED(Status))
{
szLog = NULL;
}
*ppLog = szLog;
ASSERT(Status != WBEM_S_PENDING);
}
end:
if (pRelPath != NULL)
{
delete pRelPath;
}
spWbemService = NULL; // Smart pointer
spWbemInput = NULL; // smart pointer
spWbemOutput = NULL; // smart pointer.
return Status;
}
WBEMSTATUS
setup_GetClusterConfiguration_input_params(
IN LPCWSTR szNic,
IN IWbemClassObjectPtr spWbemInput
)
/*
Setup the input wmi parameters for the GetClusterConfiguration method
*/
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
Status = CfgUtilSetWmiStringParam(
spWbemInput,
L"AdapterGuid",
szNic
);
return Status;
}
WBEMSTATUS
extract_GetClusterConfiguration_output_params(
IN IWbemClassObjectPtr spWbemOutput,
OUT PNLB_EXTENDED_CLUSTER_CONFIGURATION pCfg
)
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
DWORD Generation = 0;
BOOL NlbBound = FALSE;
LPWSTR *pszNetworkAddresses= NULL;
UINT NumNetworkAddresses = 0;
BOOL ValidNlbCfg = FALSE;
LPWSTR szClusterName = NULL;
LPWSTR szClusterNetworkAddress = NULL;
LPWSTR szTrafficMode = NULL;
NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE
TrafficMode
= NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_UNICAST;
LPWSTR *pszPortRules = NULL;
UINT NumPortRules = 0;
DWORD HostPriority = 0;
LPWSTR szDedicatedNetworkAddress = NULL;
NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE
ClusterModeOnStart
= NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE_STOPPED;
BOOL RemoteControlEnabled= FALSE;
#if 0
[OUT] uint32 Generation,
[OUT] String NetworkAddresses[], // "10.1.1.1/255.0.0.0"
[OUT] Boolean NLBBound,
[OUT] String ClusterNetworkAddress, // "10.1.1.1/255.0.0.0"
[OUT] String ClusterName,
[OUT] String TrafficMode, // UNICAST MULTICAST IGMPMULTICAST
[OUT] String PortRules[],
[OUT] uint32 HostPriority,
[OUT] String DedicatedNetworkAddress, // "10.1.1.1/255.0.0.0"
[OUT] Boolean ClusterModeOnStart,
[OUT] Boolean RemoteControlEnabled
#endif // 0
Status = CfgUtilGetWmiDWORDParam(
spWbemOutput,
L"Generation", // <--------------------------------
&Generation
);
if (FAILED(Status))
{
wprintf(L"Attempt to read Generation failed. Error=0x%08lx\n",
(UINT) Status);
goto end;
}
Status = CfgUtilGetWmiStringArrayParam(
spWbemOutput,
L"NetworkAddresses", // <--------------------------------
&pszNetworkAddresses,
&NumNetworkAddresses
);
if (FAILED(Status))
{
wprintf(L"Attempt to read Network addresses failed. Error=0x%08lx\n",
(UINT) Status);
goto end;
}
Status = CfgUtilGetWmiBoolParam(
spWbemOutput,
L"NLBBound", // <--------------------------------
&NlbBound
);
if (FAILED(Status))
{
wprintf(L"Attempt to read NLBBound failed. Error=0x%08lx\n",
(UINT) Status);
goto end;
}
do // while false -- just to allow us to break out
{
ValidNlbCfg = FALSE;
if (!NlbBound)
{
wprintf(L"NLB is UNBOUND\n");
break;
}
Status = CfgUtilGetWmiStringParam(
spWbemOutput,
L"ClusterNetworkAddress", // <-------------------------
&szClusterNetworkAddress
);
if (FAILED(Status))
{
wprintf(L"Attempt to read Cluster IP failed. Error=0x%08lx\n",
(UINT) Status);
break;
}
wprintf(L"NLB is BOUND, and the cluster address is %ws\n",
szClusterNetworkAddress);
Status = CfgUtilGetWmiStringParam(
spWbemOutput,
L"ClusterName", // <-------------------------
&szClusterName
);
if (FAILED(Status))
{
wprintf(L"Attempt to read Cluster Name failed. Error=0x%08lx\n",
(UINT) Status);
break;
}
//
// Traffic mode
//
{
Status = CfgUtilGetWmiStringParam(
spWbemOutput,
L"TrafficMode", // <-------------------------
&szTrafficMode
);
if (FAILED(Status))
{
wprintf(L"Attempt to read Traffic Mode failed. Error=0x%08lx\n",
(UINT) Status);
break;
}
if (!_wcsicmp(szTrafficMode, L"UNICAST"))
{
TrafficMode =
NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_UNICAST;
}
else if (!_wcsicmp(szTrafficMode, L"MULTICAST"))
{
TrafficMode =
NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_MULTICAST;
}
else if (!_wcsicmp(szTrafficMode, L"IGMPMULTICAST"))
{
TrafficMode =
NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_IGMPMULTICAST;
}
}
// TODO: [OUT] String PortRules[],
Status = CfgUtilGetWmiDWORDParam(
spWbemOutput,
L"HostPriority", // <--------------------------------
&HostPriority
);
if (FAILED(Status))
{
wprintf(L"Attempt to read HostPriority failed. Error=0x%08lx\n",
(UINT) Status);
break;
}
Status = CfgUtilGetWmiStringParam(
spWbemOutput,
L"DedicatedNetworkAddress", // <-------------------------
&szDedicatedNetworkAddress
);
if (FAILED(Status))
{
wprintf(L"Attempt to read dedicated IP failed. Error=0x%08lx\n",
(UINT) Status);
break;
}
//
// StartMode
//
{
BOOL StartMode = FALSE;
Status = CfgUtilGetWmiBoolParam(
spWbemOutput,
L"ClusterModeOnStart", // <-------------------------
&StartMode
);
if (FAILED(Status))
{
wprintf(L"Attempt to read ClusterModeOnStart failed. Error=0x%08lx\n",
(UINT) Status);
break;
}
if (StartMode)
{
ClusterModeOnStart =
NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE_STARTED;
}
else
{
ClusterModeOnStart =
NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE_STOPPED;
}
}
Status = CfgUtilGetWmiBoolParam(
spWbemOutput,
L"RemoteControlEnabled", // <----------------------------
&RemoteControlEnabled
);
if (FAILED(Status))
{
wprintf(L"Attempt to read RemoteControlEnabled failed. Error=0x%08lx\n",
(UINT) Status);
break;
}
ValidNlbCfg = TRUE;
} while (FALSE) ;
//
// Now let's set all the the parameters in Cfg
//
{
pCfg->Generation = Generation;
pCfg->fBound = NlbBound;
Status = pCfg->SetNetworkAddresses(
(LPCWSTR*) pszNetworkAddresses,
NumNetworkAddresses
);
if (FAILED(Status))
{
wprintf(L"Attempt to set NetworkAddresses failed. Error=0x%08lx\n",
(UINT) Status);
goto end;
}
pCfg->fValidNlbCfg = ValidNlbCfg;
pCfg->SetClusterName(szClusterName);
pCfg->SetClusterNetworkAddress(szClusterNetworkAddress);
pCfg->SetTrafficMode(TrafficMode);
Status = pCfg->SetPortRules((LPCWSTR*)pszPortRules, NumPortRules);
Status = WBEM_NO_ERROR; // TODO -- change once port rules is done
if (FAILED(Status))
{
wprintf(L"Attempt to set PortRules failed. Error=0x%08lx\n",
(UINT) Status);
goto end;
}
pCfg->SetHostPriority(HostPriority);
pCfg->SetDedicatedNetworkAddress(szDedicatedNetworkAddress);
pCfg->SetClusterModeOnStart(ClusterModeOnStart);
pCfg->SetRemoteControlEnabled(RemoteControlEnabled);
}
end:
delete szClusterNetworkAddress;
delete pszNetworkAddresses;
delete szClusterName;
delete szTrafficMode;
delete pszPortRules;
delete szDedicatedNetworkAddress;
return Status;
}
WBEMSTATUS
setup_UpdateClusterConfiguration_input_params(
IN LPCWSTR szNic,
IN PNLB_EXTENDED_CLUSTER_CONFIGURATION pCfg,
IN IWbemClassObjectPtr spWbemInput
)
/*
Setup the input wmi parameters for the UpdateGetClusterConfiguration method
[IN] String ClientDescription,
[IN] String AdapterGuid,
[IN] uint32 Generation,
[IN] Boolean PartialUpdate,
[IN] String NetworkAddresses[], // "10.1.1.1/255.255.255.255"
[IN] Boolean NLBBound,
[IN] String ClusterNetworkAddress, // "10.1.1.1/255.0.0.0"
[IN] String ClusterName,
[IN] String TrafficMode, // UNICAST MULTICAST IGMPMULTICAST
[IN] String PortRules[],
[IN] uint32 HostPriority,
[IN] String DedicatedNetworkAddress, // "10.1.1.1/255.0.0.0"
[IN] Boolean ClusterModeOnStart,
[IN] Boolean RemoteControlEnabled,
[IN] String Password,
*/
{
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
Status = CfgUtilSetWmiStringParam(
spWbemInput,
L"AdapterGuid",
szNic
);
//
// Fill in NetworkAddresses[]
//
{
LPWSTR *pszAddresses = NULL;
UINT NumAddresses = 0;
Status = pCfg->GetNetworkAddresses(
&pszAddresses,
&NumAddresses
);
if (FAILED(Status))
{
printf(
"Setup update params: couldn't extract network addresses from Cfg"
" for NIC %ws\n",
szNic
);
goto end;
}
//
// Note it's ok to not specify any IP addresses -- in which case
// the default ip addresses will be set up.
//
if (pszAddresses != NULL)
{
Status = CfgUtilSetWmiStringArrayParam(
spWbemInput,
L"NetworkAddresses",
(LPCWSTR *)pszAddresses,
NumAddresses
);
delete pszAddresses;
pszAddresses = NULL;
}
}
if (!pCfg->IsNlbBound())
{
//
// NLB is not bound
//
Status = CfgUtilSetWmiBoolParam(spWbemInput, L"NLBBound", FALSE);
goto end;
}
else if (!pCfg->IsValidNlbConfig())
{
printf(
"Setup update params: NLB-specific configuration on NIC %ws is invalid\n",
szNic
);
Status = WBEM_E_INVALID_PARAMETER;
goto end;
}
Status = CfgUtilSetWmiBoolParam(spWbemInput, L"NLBBound", TRUE);
if (FAILED(Status))
{
printf("Error trying to set NLBBound parameter\n");
}
//
// NLB is bound
//
CfgUtilSetWmiBoolParam(spWbemInput, L"NLBBound", TRUE);
//
// Cluster name
//
{
LPWSTR szName = NULL;
Status = pCfg->GetClusterName(&szName);
if (FAILED(Status))
{
printf(
"Setup update params: Could not extract cluster name for NIC %ws\n",
szNic
);
goto end;
}
CfgUtilSetWmiStringParam(spWbemInput, L"ClusterName", szName);
delete (szName);
szName = NULL;
}
//
// Cluster and dedicated network addresses
//
{
LPWSTR szAddress = NULL;
Status = pCfg->GetClusterNetworkAddress(&szAddress);
if (FAILED(Status))
{
printf(
"Setup update params: Could not extract cluster address for NIC %ws\n",
szNic
);
goto end;
}
CfgUtilSetWmiStringParam(
spWbemInput,
L"ClusterNetworkAddress",
szAddress
);
delete (szAddress);
szAddress = NULL;
Status = pCfg->GetDedicatedNetworkAddress(&szAddress);
if (FAILED(Status))
{
printf(
"Setup update params: Could not extract dedicated address for NIC %ws\n",
szNic
);
goto end;
}
CfgUtilSetWmiStringParam(
spWbemInput,
L"DedicatedNetworkAddress",
szAddress
);
delete (szAddress);
szAddress = NULL;
}
//
// TrafficMode
//
{
LPCWSTR szMode = NULL;
switch(pCfg->GetTrafficMode())
{
case NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_UNICAST:
szMode = L"UNICAST";
break;
case NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_MULTICAST:
szMode = L"MULTICAST";
break;
case NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_IGMPMULTICAST:
szMode = L"IGMPMULTICAST";
break;
default:
assert(FALSE);
Status = WBEM_E_CRITICAL_ERROR;
goto end;
}
CfgUtilSetWmiStringParam(spWbemInput, L"TrafficMode", szMode);
}
CfgUtilSetWmiDWORDParam(
spWbemInput,
L"HostPriority",
pCfg->GetHostPriority()
);
if (pCfg->GetClusterModeOnStart() ==
NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE_STARTED)
{
CfgUtilSetWmiBoolParam(spWbemInput, L"ClusterModeOnStart", TRUE);
}
else
{
CfgUtilSetWmiBoolParam(spWbemInput, L"ClusterModeOnStart", FALSE);
}
CfgUtilSetWmiBoolParam(
spWbemInput,
L"RemoteControlEnabled",
pCfg->GetRemoteControlEnabled()
);
//
// TODO: get port rules
// [OUT] String PortRules[],
//
Status = WBEM_NO_ERROR;
end:
wprintf(L"<-Setup update params returns 0x%08lx\n", (UINT) Status);
return Status;
}