/*++ 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; }