/****************************************************************** Copyright (c) 1999 Microsoft Corporation NlbsNic.CPP -- WMI provider class implementation Generated by Microsoft WMI Code Generation Engine TO DO: - See individual function headers - When linking, make sure you link to framedyd.lib & msvcrtd.lib (debug) or framedyn.lib & msvcrt.lib (retail). Description: ******************************************************************/ // History: // -------- // // Revised by : mhakim // Date : 02-12-01 // Reason : Added password support. // // Revised by : mhakim // Date : 02-16-01 // Reason : Added friendly name support. // // Reason : filling out version info. This was being not // done previously in GetObject. #include // This must be the first include. #include "NlbsNic.h" #include "NICCard.h" #include "MNicInfo.h" #include "MIPAddressAdmin.h" #include "MNLBProviderSetting.h" #include "Common.h" #include "MUsingCom.h" #include "WTokens.h" #include "MNLBMachine.h" #include // For Sleep #include // For Sleep #include //#include #include "wlbsconfig.h" #include "myntrtl.h" #include "wlbsparm.h" #include "cfgutils.h" #include "updatecfg.h" #include "nlbsnic.tmh" using namespace std; MUsingCom com; BOOL g_UpdateConfigurationEnabled = FALSE; WBEMSTATUS ProvGetClusterConfiguration( CInstance *pInParams, CInstance *pOutParams ); WBEMSTATUS ProvUpdateClusterConfiguration( CInstance *pInParams, CInstance *pOutParams ); WBEMSTATUS ProvQueryConfigurationUpdateStatus( CInstance *pInParams, CInstance *pOutParams ); WCHAR* CNlbsNic::version = L"03-09-2001"; // TO DO: Replace "NameSpace" with the appropriate namespace for your // provider instance. For instance: "root\\default or "root\\cimv2". // DONE : mhakim //=================================================================== CNlbsNic MyNlbsNicSet (PROVIDER_NAME_NLBSNIC, L"root\\microsoftnlb") ; // Property names //=============== const static WCHAR* pAdapterGuid = L"AdapterGuid" ; const static WCHAR* pDependent = L"Dependent" ; const static WCHAR* pFriendlyName = L"FriendlyName" ; const static WCHAR* pFullName = L"FullName" ; const static WCHAR* pVersion = L"Version" ; /***************************************************************************** * * FUNCTION : CNlbsNic::CNlbsNic * * DESCRIPTION : Constructor * * INPUTS : none * * RETURNS : nothing * * COMMENTS : Calls the Provider constructor. * *****************************************************************************/ CNlbsNic::CNlbsNic (LPCWSTR lpwszName, LPCWSTR lpwszNameSpace ) : Provider(lpwszName, lpwszNameSpace) { // // Enable WMI event tracing // WPP_INIT_TRACING(L"Microsoft\\NLB\\TPROV"); if (g_UpdateConfigurationEnabled) { // // Initialize update config // NlbConfigurationUpdate::Initialize(); } } /***************************************************************************** * * FUNCTION : CNlbsNic::~CNlbsNic * * DESCRIPTION : Destructor * * INPUTS : none * * RETURNS : nothing * * COMMENTS : * *****************************************************************************/ CNlbsNic::~CNlbsNic () { if (g_UpdateConfigurationEnabled) { // // Deinitialize update config code // NlbConfigurationUpdate::Deinitialize(); } // // Disable WMI event tracing // WPP_CLEANUP(); } /***************************************************************************** * * FUNCTION : CNlbsNic::EnumerateInstances * * DESCRIPTION : Returns all the instances of this class. * * INPUTS : A pointer to the MethodContext for communication with WinMgmt. * A long that contains the flags described in * IWbemServices::CreateInstanceEnumAsync. Note that the following * flags are handled by (and filtered out by) WinMgmt: * WBEM_FLAG_DEEP * WBEM_FLAG_SHALLOW * WBEM_FLAG_RETURN_IMMEDIATELY * WBEM_FLAG_FORWARD_ONLY * WBEM_FLAG_BIDIRECTIONAL * * RETURNS : WBEM_S_NO_ERROR if successful * * COMMENTS : TO DO: All instances on the machine should be returned here and * all properties that this class knows how to populate must * be filled in. If there are no instances, return * WBEM_S_NO_ERROR. It is not an error to have no instances. * If you are implementing a 'method only' provider, you * should remove this method. * DONE: mhakim * *****************************************************************************/ HRESULT CNlbsNic::EnumerateInstances ( MethodContext* pMethodContext, long lFlags ) { HRESULT hRes = WBEM_S_NO_ERROR; // get information about all nics on the machine. // NICCard::NICCard_Error errN; vector< NICCard::Info > nicList; errN = NICCard::getNics( &nicList ); if( errN != NICCard::NICCard_SUCCESS ) { return WBEM_E_NOT_FOUND; } // populate all instances. // for( int i = 0; i < nicList.size(); ++i ) { CInstance* pInstance = CreateNewInstance(pMethodContext); pInstance->SetCHString(pAdapterGuid, nicList[i].guid.c_str() ); pInstance->SetCHString(pFriendlyName, nicList[i].friendlyName.c_str() ); pInstance->SetCHString(pFullName, nicList[i].fullName.c_str() ); pInstance->SetCHString(pVersion, version ); hRes = pInstance->Commit(); pInstance->Release(); } hRes = WBEM_S_NO_ERROR; return hRes ; } /***************************************************************************** * * FUNCTION : CNlbsNic::GetObject * * DESCRIPTION : Find a single instance based on the key properties for the * class. * * INPUTS : A pointer to a CInstance object containing the key properties. * A long that contains the flags described in * IWbemServices::GetObjectAsync. * * RETURNS : WBEM_S_NO_ERROR if the instance can be found * WBEM_E_NOT_FOUND if the instance described by the key properties * could not be found * WBEM_E_FAILED if the instance could be found but another error * occurred. * * COMMENTS : If you are implementing a 'method only' provider, you should * remove this method. * *****************************************************************************/ HRESULT CNlbsNic::GetObject ( CInstance* pInstance, long lFlags ) { HRESULT hr = WBEM_E_NOT_FOUND; CHString sTemp; pInstance->GetCHString( L"FullName", sTemp ); wstring fullName = sTemp; NICCard::NICCard_Error errN; vector< NICCard::Info > nicList; errN = NICCard::getNics( &nicList ); if( errN != NICCard::NICCard_SUCCESS ) { return WBEM_E_NOT_FOUND; } // populate all instances. // hr = WBEM_E_NOT_FOUND; for( int i = 0; i < nicList.size(); ++i ) { if( nicList[i].fullName == fullName ) { // found specific instance. // pInstance->SetCHString(pAdapterGuid, nicList[i].guid.c_str() ); pInstance->SetCHString(pFriendlyName, nicList[i].friendlyName.c_str() ); pInstance->SetCHString(pFullName, nicList[i].fullName.c_str() ); pInstance->SetCHString(pVersion, version ); hr = WBEM_S_NO_ERROR; break; } } return hr; } /***************************************************************************** * * FUNCTION : CNlbsNic::ExecQuery * * DESCRIPTION : You are passed a method context to use in the creation of * instances that satisfy the query, and a CFrameworkQuery * which describes the query. Create and populate all * instances which satisfy the query. You may return more * instances or more properties than are requested and WinMgmt * will post filter out any that do not apply. * * INPUTS : A pointer to the MethodContext for communication with WinMgmt. * A query object describing the query to satisfy. * A long that contains the flags described in * IWbemServices::CreateInstanceEnumAsync. Note that the following * flags are handled by (and filtered out by) WinMgmt: * WBEM_FLAG_FORWARD_ONLY * WBEM_FLAG_BIDIRECTIONAL * WBEM_FLAG_ENSURE_LOCATABLE * * RETURNS : WBEM_E_PROVIDER_NOT_CAPABLE if queries not supported for * this class or if the query is too complex for this class * to interpret. The framework will call the EnumerateInstances * function instead and let Winmgmt post filter. * WBEM_E_FAILED if the query failed * WBEM_S_NO_ERROR if query was successful * * COMMENTS : TO DO: Most providers will not need to implement this method. If you don't, WinMgmt * will call your enumerate function to get all the instances and perform the * filtering for you. Unless you expect SIGNIFICANT savings from implementing * queries, you should remove this method. You should also remove this method * if you are implementing a 'method only' provider. * *****************************************************************************/ HRESULT CNlbsNic::ExecQuery (MethodContext *pMethodContext, CFrameworkQuery& Query, long lFlags) { return (WBEM_E_PROVIDER_NOT_CAPABLE); } /***************************************************************************** * * FUNCTION : CNlbsNic::PutInstance * * DESCRIPTION : PutInstance should be used in provider classes that can * write instance information back to the hardware or * software. For example: Win32_Environment will allow a * PutInstance to create or update an environment variable. * However, a class like MotherboardDevice will not allow * editing of the number of slots, since it is difficult for * a provider to affect that number. * * INPUTS : A pointer to a CInstance object containing the key properties. * A long that contains the flags described in * IWbemServices::PutInstanceAsync. * * RETURNS : WBEM_E_PROVIDER_NOT_CAPABLE if PutInstance is not available * WBEM_E_FAILED if there is an error delivering the instance * WBEM_E_INVALID_PARAMETER if any of the instance properties * are incorrect. * WBEM_S_NO_ERROR if instance is properly delivered * * COMMENTS : TO DO: If you don't intend to support writing to your provider, * or are creating a 'method only' provider, remove this * method. * *****************************************************************************/ HRESULT CNlbsNic::PutInstance ( const CInstance &Instance, long lFlags) { // Use the CInstance Get functions (for example, call // GetCHString(L"Name", sTemp)) against Instance to see the key values // the client requested. return (WBEM_E_PROVIDER_NOT_CAPABLE); } /***************************************************************************** * * FUNCTION : CNlbsNic::DeleteInstance * * DESCRIPTION : DeleteInstance, like PutInstance, actually writes information * to the software or hardware. For most hardware devices, * DeleteInstance should not be implemented, but for software * configuration, DeleteInstance implementation is plausible. * * INPUTS : A pointer to a CInstance object containing the key properties. * A long that contains the flags described in * IWbemServices::DeleteInstanceAsync. * * RETURNS : WBEM_E_PROVIDER_NOT_CAPABLE if DeleteInstance is not available. * WBEM_E_FAILED if there is an error deleting the instance. * WBEM_E_INVALID_PARAMETER if any of the instance properties * are incorrect. * WBEM_S_NO_ERROR if instance is properly deleted. * * COMMENTS : TO DO: If you don't intend to support deleting instances or are * creating a 'method only' provider, remove this method. * *****************************************************************************/ HRESULT CNlbsNic::DeleteInstance ( const CInstance &Instance, long lFlags ) { // Use the CInstance Get functions (for example, call // GetCHString(L"Name", sTemp)) against Instance to see the key values // the client requested. return (WBEM_E_PROVIDER_NOT_CAPABLE); } /***************************************************************************** * * FUNCTION : CNlbsNic::ExecMethod * * DESCRIPTION : Override this function to provide support for methods. * A method is an entry point for the user of your provider * to request your class perform some function above and * beyond a change of state. (A change of state should be * handled by PutInstance() ) * * INPUTS : A pointer to a CInstance containing the instance the method was executed against. * A string containing the method name * A pointer to the CInstance which contains the IN parameters. * A pointer to the CInstance to contain the OUT parameters. * A set of specialized method flags * * RETURNS : WBEM_E_PROVIDER_NOT_CAPABLE if not implemented for this class * WBEM_S_NO_ERROR if method executes successfully * WBEM_E_FAILED if error occurs executing method * * COMMENTS : TO DO: If you don't intend to support Methods, remove this method. * *****************************************************************************/ HRESULT CNlbsNic::ExecMethod ( const CInstance& Instance, const BSTR bstrMethodName, CInstance *pInParams, CInstance *pOutParams, long lFlags) { // For non-static methods, use the CInstance Get functions (for example, // call GetCHString(L"Name", sTemp)) against Instance to see the key // values the client requested. HRESULT hresult = WBEM_E_PROVIDER_NOT_CAPABLE; CHString sTemp; wstring fullName; wstring clusterIPAddress; wstring clusterNetworkMask; wstring clusterName; wstring password; _variant_t hostPriority; wstring dedicatedIPAddress; wstring dedicatedNetworkMask; bool retBool; Instance.GetCHString( L"FullName", sTemp ); fullName = sTemp; NICCard nic( NICCard::fullName, fullName ); NICCard::NICCard_Error err; DWORD retValue= 100; if (_wcsicmp(bstrMethodName, L"IsBound") == 0) { // check if bound or not. err = nic.isBoundTo( L"ms_wlbs"); if( err == NICCard::BOUND ) { retValue = 1; } else if( err == NICCard::UNBOUND ) { retValue = 0; } else if( err == NICCard::NO_SUCH_NIC ) { retValue = 20; } else if( err == NICCard::NO_SUCH_COMPONENT ) { retValue = 30; } else { retValue = 40; } hresult = WBEM_S_NO_ERROR; pOutParams->SetDWORD(L"ReturnValue", retValue); return hresult; } else if (_wcsicmp(bstrMethodName, L"Bind") == 0) { // bind nlbs to the nic. err = nic.bind( L"ms_wlbs" ); if( err == NICCard::NICCard_SUCCESS ) { retValue = 0; } else if( err == NICCard::NO_SUCH_NIC ) { retValue = 20; } else if( err == NICCard::NO_SUCH_COMPONENT ) { retValue = 30; } else { retValue = 40; } hresult = WBEM_S_NO_ERROR; pOutParams->SetDWORD(L"ReturnValue", retValue); return hresult; } else if (_wcsicmp(bstrMethodName, L"Unbind") == 0) { // unbind nlbs from nic err = nic.unbind( L"ms_wlbs" ); if( err == NICCard::NICCard_SUCCESS ) { retValue = 0; } else if( err == NICCard::NO_SUCH_NIC ) { retValue = 20; } else if( err == NICCard::NO_SUCH_COMPONENT ) { retValue = 30; } else { retValue = 40; } hresult = WBEM_S_NO_ERROR; pOutParams->SetDWORD(L"ReturnValue", retValue); return hresult; } else if (_wcsicmp(bstrMethodName, L"BindAndConfigure") == 0) { // here we need to be passed everything // required to configure cluster completely // on this machine. // bind nlbs to the nic. err = nic.bind( L"ms_wlbs" ); if( err == NICCard::NICCard_SUCCESS ) { MNLBProviderSetting nlbs( fullName.c_str() ); // remove all old port rules. // removing LB port rules vector portLB; nlbs.getPortRulesLoadBalanced( &portLB ); for( int i = 0; i < portLB.size(); ++i ) { nlbs.removePortRuleLoadBalanced( portLB[i] ); } // removing D port rules vector portD; nlbs.getPortRulesDisabled( &portD ); for( int i = 0; i < portD.size(); ++i ) { nlbs.removePortRuleDisabled( portD[i] ); } // removing Failover port rules vector portF; nlbs.getPortRulesFailover( &portF ); for( int i = 0; i < portF.size(); ++i ) { nlbs.removePortRuleFailover( portF[i] ); } // // get port rules to configure. // SAFEARRAY* portRulesArray; SAFEARRAYBOUND sb; sb.lLbound = 0; sb.cElements = 100; portRulesArray = SafeArrayCreate( VT_BSTR, 1, &sb ); pInParams->GetStringArray( L"PortRules", portRulesArray ); vector<_bstr_t> portRulesVector; GetVectorFromSafeArray( portRulesArray, portRulesVector ); ClusterData clusterData; FillInPortRules( &clusterData, L"rashuma", portRulesVector ); // add all new port rules. // equal load balanced. map< long, PortDataELB>::iterator topELB; for( topELB = clusterData.portELB.begin(); topELB != clusterData.portELB.end(); ++topELB ) { nlbs.addPortRuleLoadBalanced( (*topELB).second ); } // unequal load balanced map< long, PortDataULB>::iterator topULB; for( topULB = clusterData.portULB.begin(); topULB != clusterData.portULB.end(); ++topULB ) { MNLBPortRuleLoadBalanced portRuleULB = (*topULB).second; portRuleULB._load = (*topULB).second.machineMapToLoadWeight[L"rashuma"]; nlbs.addPortRuleLoadBalanced( portRuleULB ); } // disabled map< long, PortDataD>::iterator topD; for( topD = clusterData.portD.begin(); topD != clusterData.portD.end(); ++topD ) { nlbs.addPortRuleDisabled( (*topD).second ); } // failover map< long, PortDataF>::iterator topF; for( topF = clusterData.portF.begin(); topF != clusterData.portF.end(); ++topF ) { MNLBPortRuleFailover portRuleF = (*topF).second; portRuleF._priority = (*topF).second.machineMapToPriority[ L"rashuma" ]; nlbs.addPortRuleFailover( portRuleF ); } // // set host properties. // HostProperties hp; // host priority pInParams->GetVariant( L"HostPriority", hostPriority ); hp.hID = hostPriority; // dip pInParams->GetCHString( L"DedicatedIPAddress", sTemp ); dedicatedIPAddress = sTemp; hp.hIP = dedicatedIPAddress.c_str(); // dsn pInParams->GetCHString( L"DedicatedNetworkMask", sTemp ); dedicatedNetworkMask = sTemp; hp.hSubnetMask = dedicatedNetworkMask.c_str(); // initial state ? pInParams->Getbool( L"ClusterModeOnStart", hp.initialClusterStateActive ); unsigned long retVal; nlbs.setHostProperties( hp, &retVal ); // // set cluster properties. // ClusterProperties cp; RetreiveAndSetClusterProperties(pInParams, nlbs, cp, fullName ); // // if initial state active start cluster // else stop cluster. // MNLBMachine nlbMachine( cp.cIP ); if( hp.initialClusterStateActive == true ) { nlbMachine.start( Common::THIS_HOST, &retVal ); } else { nlbMachine.stop( Common::THIS_HOST, &retVal ); } retValue = 0; } else if( err == NICCard::NO_SUCH_NIC ) { retValue = 20; } else if( err == NICCard::NO_SUCH_COMPONENT ) { retValue = 30; } else { retValue = 40; } hresult = WBEM_S_NO_ERROR; pOutParams->SetDWORD(L"ReturnValue", retValue); return hresult; } else if (_wcsicmp(bstrMethodName, L"ModifyClusterProperties") == 0) { // check if nic is bound to adapter or not. err = nic.isBoundTo( L"ms_wlbs" ); if( err == NICCard::BOUND ) { MNLBProviderSetting nlbs( fullName.c_str() ); // // set cluster properties. // ClusterProperties cp; RetreiveAndSetClusterProperties(pInParams, nlbs, cp, fullName); } else if( err == NICCard::UNBOUND ) { retValue = 10; } else if( err == NICCard::NO_SUCH_NIC ) { retValue = 20; } else if( err == NICCard::NO_SUCH_COMPONENT ) { retValue = 30; } else { retValue = 40; } hresult = WBEM_S_NO_ERROR; pOutParams->SetDWORD(L"ReturnValue", retValue); return hresult; } else if (_wcsicmp(bstrMethodName, L"GetClusterConfiguration") == 0) { hresult = ProvGetClusterConfiguration( pInParams, pOutParams ); return hresult; } else if (_wcsicmp(bstrMethodName, L"UpdateClusterConfiguration") == 0) { hresult = ProvUpdateClusterConfiguration( pInParams, pOutParams ); return hresult; } else if (_wcsicmp(bstrMethodName, L"QueryConfigurationUpdateStatus") == 0) { hresult = ProvQueryConfigurationUpdateStatus( pInParams, pOutParams ); return hresult; } else { // unknown call, we do not support this. hresult = WBEM_E_PROVIDER_NOT_CAPABLE; pOutParams->SetDWORD(L"ReturnValue", retValue); return hresult; } } void CNlbsNic::RetreiveAndSetClusterProperties(CInstance *pInParams, MNLBProviderSetting &nlbs, ClusterProperties& cp, const wstring& fullName ) { CHString sTemp; wstring clusterIPAddress; wstring clusterNetworkMask; wstring clusterName; wstring password; // cip pInParams->GetCHString( L"ClusterIPAddress", sTemp ); clusterIPAddress = sTemp; cp.cIP = clusterIPAddress.c_str(); // csn pInParams->GetCHString( L"ClusterNetworkMask", sTemp ); clusterNetworkMask = sTemp; cp.cSubnetMask = clusterNetworkMask.c_str(); // full internet name pInParams->GetCHString( L"ClusterName", sTemp ); clusterName = sTemp; cp.cFullInternetName = clusterName.c_str(); // igmp support? pInParams->Getbool( L"IGMPSupport", cp.igmpSupportEnabled ); // multicast enabled? pInParams->Getbool( L"MulticastSupportEnabled", cp.multicastSupportEnabled ); // remote control enabled? pInParams->Getbool( L"RemoteControlEnabled", cp.remoteControlEnabled ); // password pInParams->GetCHString( L"Password", sTemp ); password = sTemp; cp.password = password.c_str(); unsigned long retVal; try { nlbs.setClusterProperties( cp, &retVal ); } catch( _com_error e ) { } // set password. try { if( cp.remoteControlEnabled == true ) { nlbs.setPassword( cp.password, &retVal ); } } catch( _com_error e ) { } // // add cluster ip // MIPAddressAdmin ipAdmin( fullName.c_str() ); long SleepDuration = 0; while ((ipAdmin.addIPAddress(cp.cIP, cp.cSubnetMask) != MIPAddressAdmin::MIPAddressAdmin_SUCCESS) &&(SleepDuration < PROTOCOL_BIND_DELAY)) { SleepDuration += PROTOCOL_BIND_WAIT_INCREMENT; Sleep(PROTOCOL_BIND_WAIT_INCREMENT); } } void CNlbsNic::GetVectorFromSafeArray( SAFEARRAY*& stringArray, vector<_bstr_t>& strings ) { LONG count = stringArray->rgsabound[0].cElements; BSTR* pbstr; HRESULT hr; if( SUCCEEDED( SafeArrayAccessData( stringArray, ( void **) &pbstr))) { for( LONG x = 0; x < count; x++ ) { strings.push_back( pbstr[x] ); } hr = SafeArrayUnaccessData( stringArray ); } } void CNlbsNic::FillInPortRules( ClusterData* p_clusterData, const _bstr_t& myMachine, const vector<_bstr_t>& portRules ) { wchar_t portBuf[1000]; wstring temp; WTokens tok; vector tokens; for( int i = 0; i < portRules.size(); ++i ) { wcscpy( portBuf, portRules[i] ); tok.init( portBuf, L"\t"); tokens = tok.tokenize(); if( tokens[3] == L"Multiple" ) { if( tokens[5] == L"Equal" ) { p_clusterData->portELB[ _wtoi( tokens[0].c_str()) ]._startPort = _wtoi( tokens[0].c_str() ); p_clusterData->portELB[ _wtoi( tokens[0].c_str()) ]._endPort = _wtoi( tokens[1].c_str() ); if( tokens[2] == L"Both" ) { p_clusterData->portELB[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::both; } else if( tokens[2] == L"TCP" ) { p_clusterData->portELB[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::tcp; } else { p_clusterData->portELB[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::udp; } if( tokens[6] == L"Single" ) { p_clusterData->portELB[ _wtoi( tokens[0].c_str()) ]._affinity = MNLBPortRule::single; } else if( tokens[6] == L"None" ) { p_clusterData->portELB[ _wtoi( tokens[0].c_str()) ]._affinity = MNLBPortRule::none; } else { p_clusterData->portELB[ _wtoi( tokens[0].c_str()) ]._affinity = MNLBPortRule::classC; } p_clusterData->portELB[ _wtoi( tokens[0].c_str()) ]._isEqualLoadBalanced = true; } else { p_clusterData->portULB[ _wtoi( tokens[0].c_str()) ]._startPort = _wtoi( tokens[0].c_str() ); p_clusterData->portULB[ _wtoi( tokens[0].c_str()) ]._endPort = _wtoi( tokens[1].c_str() ); if( tokens[2] == L"Both" ) { p_clusterData->portULB[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::both; } else if( tokens[2] == L"TCP" ) { p_clusterData->portULB[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::tcp; } else { p_clusterData->portULB[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::udp; } if( tokens[6] == L"Single" ) { p_clusterData->portULB[ _wtoi( tokens[0].c_str()) ]._affinity = MNLBPortRule::single; } else if( tokens[6] == L"None" ) { p_clusterData->portULB[ _wtoi( tokens[0].c_str()) ]._affinity = MNLBPortRule::none; } else { p_clusterData->portULB[ _wtoi( tokens[0].c_str()) ]._affinity = MNLBPortRule::classC; } p_clusterData->portULB[ _wtoi( tokens[0].c_str()) ]._isEqualLoadBalanced = false; p_clusterData->portULB[ _wtoi( tokens[0].c_str()) ].machineMapToLoadWeight[myMachine] = _wtoi( tokens[5].c_str() ); } } else if ( tokens[3] == L"Single" ) { p_clusterData->portF[ _wtoi( tokens[0].c_str()) ]._startPort = _wtoi( tokens[0].c_str() ); p_clusterData->portF[ _wtoi( tokens[0].c_str()) ]._endPort = _wtoi( tokens[1].c_str() ); if( tokens[2] == L"Both" ) { p_clusterData->portF[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::both; } else if( tokens[2] == L"TCP" ) { p_clusterData->portF[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::tcp; } else { p_clusterData->portF[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::udp; } p_clusterData->portF[ _wtoi( tokens[0].c_str()) ].machineMapToPriority[myMachine] = _wtoi( tokens[4].c_str() ); } else { p_clusterData->portD[ _wtoi( tokens[0].c_str()) ]._startPort = _wtoi( tokens[0].c_str() ); p_clusterData->portD[ _wtoi( tokens[0].c_str()) ]._endPort = _wtoi( tokens[1].c_str() ); if( tokens[2] == L"Both" ) { p_clusterData->portD[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::both; } else if( tokens[2] == L"TCP" ) { p_clusterData->portD[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::tcp; } else { p_clusterData->portD[ _wtoi( tokens[0].c_str()) ]._trafficToHandle = MNLBPortRule::udp; } } } } WBEMSTATUS ProvGetClusterConfiguration( CInstance *pInParams, CInstance *pOutParams ) /*++ WMI provider wrapper around NlbConfigurationUpdate::GetConfiguration --*/ { if (!g_UpdateConfigurationEnabled) return WBEM_E_PROVIDER_NOT_CAPABLE; LPCWSTR pAdapterGuid = NULL; WBEMSTATUS Status = WBEM_E_PROVIDER_NOT_CAPABLE; CHString sTemp; bool fRet; NLB_EXTENDED_CLUSTER_CONFIGURATION Cfg; SAFEARRAY *pSA = NULL; /* [IN] String AdapterGuid, [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 */ fRet = pInParams->GetCHString( L"AdapterGuid", sTemp ); if (!fRet) { TRACE_CRIT("->%!FUNC!: Missing adapter guid!"); Status = WBEM_E_INVALID_PARAMETER; goto end; } // // Note: (LPCWSTR) sTemp returns an internal pointer to sTemp's char // buffer -- see operator LPCWSTR() of WString docs. // pAdapterGuid = (LPCWSTR) sTemp; if (pAdapterGuid == NULL || *pAdapterGuid == 0) { TRACE_CRIT("->%!FUNC!: Null of empty adapter guid!"); Status = WBEM_E_INVALID_PARAMETER; goto end; } else { TRACE_VERB(L"->%!FUNC!(Nic=%ws)", pAdapterGuid); } Status = NlbConfigurationUpdate::GetConfiguration( pAdapterGuid, &Cfg ); if (FAILED(Status)) { goto end; } pOutParams->SetDWORD(L"ReturnValue", (DWORD) WBEM_NO_ERROR); pOutParams->SetDWORD(L"Generation", Cfg.GetGeneration()); // // Fill in NetworkAddresses[] // { Status = Cfg.GetNetworkAddressesSafeArray( &pSA ); if (FAILED(Status)) { TRACE_CRIT( "%!FUNC!: couldn't extract network addresses from Cfg" " for NIC %ws", pAdapterGuid ); goto end; } if (pSA!=NULL) { pOutParams->SetStringArray( L"NetworkAddresses", *pSA // pass by reference ); SafeArrayDestroy(pSA); pSA = NULL; } } if (!Cfg.IsNlbBound()) { // // NLB is bound // pOutParams->Setbool(L"NLBBound", FALSE); Status = WBEM_NO_ERROR; goto end; } // // NLB is bound // pOutParams->Setbool(L"NLBBound", TRUE); if (!Cfg.IsValidNlbConfig()) { TRACE_CRIT( "%!FUNC!: NLB-specific configuration on NIC %ws is invalid", pAdapterGuid ); goto end; } // // Cluster name // { LPWSTR szName = NULL; Status = Cfg.GetClusterName(&szName); if (FAILED(Status)) { TRACE_CRIT( "%!FUNC!: Could not extract cluster name for NIC %ws", pAdapterGuid ); goto end; } pOutParams->SetCHString(L"ClusterName", szName); delete (szName); szName = NULL; } // // Cluster and dedicated network addresses // { LPWSTR szAddress = NULL; Status = Cfg.GetClusterNetworkAddress(&szAddress); if (FAILED(Status)) { TRACE_CRIT( "%!FUNC!: Could not extract cluster address for NIC %ws", pAdapterGuid ); goto end; } pOutParams->SetCHString(L"ClusterNetworkAddress", szAddress); delete (szAddress); szAddress = NULL; Status = Cfg.GetDedicatedNetworkAddress(&szAddress); if (FAILED(Status)) { TRACE_CRIT( "%!FUNC!: Could not extract dedicated address for NIC %ws", pAdapterGuid ); goto end; } pOutParams->SetCHString(L"DedicatedNetworkAddress", szAddress); delete (szAddress); szAddress = NULL; } // // TrafficMode // { LPCWSTR szMode = NULL; switch(Cfg.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; } pOutParams->SetCHString(L"TrafficMode", szMode); } pOutParams->SetDWORD(L"HostPriority", Cfg.GetHostPriority()); if (Cfg.GetClusterModeOnStart() == NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE_STARTED) { pOutParams->Setbool(L"ClusterModeOnStart", TRUE); } else { pOutParams->Setbool(L"ClusterModeOnStart", FALSE); } pOutParams->Setbool(L"RemoteControlEnabled", Cfg.GetRemoteControlEnabled()); // // TODO: get port rules // [OUT] String PortRules[], // Status = WBEM_NO_ERROR; end: if (pSA!=NULL) { SafeArrayDestroy(pSA); pSA = NULL; } TRACE_VERB(L"<-%!FUNC! returns 0x%08lx", (UINT) Status); return Status; } WBEMSTATUS ProvUpdateClusterConfiguration( CInstance *pInParams, CInstance *pOutParams ) /*++ WMI provider wrapper NlbConfigurationUpdate::UpdateConfiguration with some additional wrinkles: we selectively update the current version. --*/ { if (!g_UpdateConfigurationEnabled) return WBEM_E_PROVIDER_NOT_CAPABLE; LPCWSTR pAdapterGuid = NULL; LPCWSTR pClientDescription = L"Unspecified WMI Client"; // TODO: localize WBEMSTATUS Status = WBEM_E_PROVIDER_NOT_CAPABLE; CHString sClientDescription; CHString sAdapterGuid; CHString sTemp; bool fRet; NLB_EXTENDED_CLUSTER_CONFIGURATION Cfg; SAFEARRAY *pSA = NULL; /* [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, [OUT] uint32 NewGeneration, [OUT] String Log */ fRet = pInParams->GetCHString( L"ClientDescription", sClientDescription); if (fRet) { // Note: (LPCWSTR) sTemp returns an internal pointer to sTemp's char pClientDescription = (LPCWSTR) sClientDescription; } fRet = pInParams->GetCHString( L"AdapterGuid", sAdapterGuid); if (!fRet) { TRACE_CRIT("->%!FUNC!: Missing adapter guid!"); Status = WBEM_E_INVALID_PARAMETER; goto end; } // // Note: (LPCWSTR) sTemp returns an internal pointer to sTemp's char // buffer -- see operator LPCWSTR() of WString docs. // pAdapterGuid = (LPCWSTR) sAdapterGuid; if (pAdapterGuid == NULL || *pAdapterGuid == 0) { TRACE_CRIT("->%!FUNC!: Null of empty adapter guid!"); Status = WBEM_E_INVALID_PARAMETER; goto end; } else { TRACE_VERB(L"->%!FUNC!(Nic=%ws)", pAdapterGuid); } // // Get the current configuration // Status = NlbConfigurationUpdate::GetConfiguration( pAdapterGuid, &Cfg ); if (FAILED(Status)) { goto end; } // // Modify the snapshot of the current configuration with whatever // cluster configuration information is specified in the input // parameters // { DWORD InGeneration = 0; bool NlbBound = FALSE; bool bResult = FALSE; bool bPartialUpdate = FALSE; // // Determine if this is a partial or full update. // If partial update, we allow a subset of cluster configuration // parameters to be specified, but allow only a restricted set // of update operations. // // Disallowed partial update operations: // - Transitions between bound and !bound // - Currently bound but nlb parameters are invalid // // Some allowed partial updates: // - Modifying IP address lists // - Modifying cluster / dedicated addresses/subnets // - Modifying existing portrules // - Adding/deleting port rules // bResult = pInParams->GetDWORD( L"Generation", // <-------------------------------- InGeneration ); if (!bResult) { // // We allow generation to be unspecified. // InGeneration = 0; } else { // // If generation is specified, // we verify that the current generation matches the // specified generation. // TODO: this really must be done in the context of // mfn_Start update -- after we've acquired the global lock! // if (InGeneration != Cfg.GetGeneration()) { TRACE_CRIT("Partial update: input generation(%lu) != current generation(%lu)", InGeneration, Cfg.GetGeneration()); Status = WBEM_E_HANDLE_OUT_OF_DATE; goto end; } } bResult = pInParams->Getbool( L"NLBBound", // <-------------------------------- NlbBound ); if (!bResult) { NlbBound = Cfg.IsNlbBound(); TRACE_CRIT(L"Could not read NLBBound -- assuming current state %d.", NlbBound); } bResult = pInParams->GetStringArray( L"NetworkAddresses", // <-------------------------------- pSA ); if (!bResult) { // // We set pCfg to zero addresses, which causes update to // use it's own defaults... // TRACE_CRIT(L"Could not read Network addresses -- using defaults"); Status = Cfg.SetNetworkAddresses(NULL, 0); pSA = NULL; } else { if (pSA != NULL) { Status = Cfg.SetNetworkAddressesSafeArray(pSA); SafeArrayDestroy(pSA); pSA = NULL; } } if (!NlbBound) { // NLB is not to be bound -- no need to read the input params. Cfg.fBound = FALSE; Cfg.fValidNlbCfg = FALSE; } else { BOOL fNewConfig = FALSE; if (!Cfg.fBound || Cfg.fValidNlbCfg == FALSE) { // // If we were previously unbound or we were bound but with // a bad configuration, we need to setup our // new cfg with good defaults // CfgUtilInitializeParams(&Cfg.NlbParams); Cfg.fBound = TRUE; Cfg.fValidNlbCfg = TRUE; fNewConfig = TRUE; } bResult = pInParams->GetCHString( L"ClusterNetworkAddress", // <-------------------- sTemp ); if (!bResult) { if (fNewConfig) { // // Cluster address MUST be specified for new config. // TRACE_CRIT(L"ERROR: Could not read Cluster IP for new config."); Status = WBEM_E_INVALID_PARAMETER; goto end; } TRACE_CRIT(L"Could not read Cluster IP. Keeping existing."); } else { LPCWSTR szClusterNetworkAddress = NULL; szClusterNetworkAddress = (LPCWSTR) sTemp; // no copies here. Cfg.SetClusterNetworkAddress(szClusterNetworkAddress); szClusterNetworkAddress = NULL; } bResult = pInParams->GetCHString( L"ClusterName", // <------------------------- sTemp ); if (!bResult) { TRACE_CRIT(L"Could not read Cluster Name. Keeping existing"); } else { LPCWSTR szClusterName = NULL; szClusterName = (LPCWSTR) sTemp; // no copies here. Cfg.SetClusterName(szClusterName); szClusterName = NULL; } // // Traffic mode // { bResult = pInParams->GetCHString( L"TrafficMode", // <------------------------- sTemp ); if (!bResult) { TRACE_CRIT(L"Could not read TrafficMode. Keeping existing"); } else { LPCWSTR szTrafficMode = NULL; NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE TrafficMode = NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE_UNICAST; szTrafficMode = (LPCWSTR) sTemp; // no copies here. 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; } else { TRACE_CRIT("Invalid TrafficMode: %ws", szTrafficMode); Status = WBEM_E_INVALID_PARAMETER; goto end; } Cfg.SetTrafficMode(TrafficMode); szTrafficMode = NULL; } } // // TODO: process port rules. // [OUT] String PortRules[] // DWORD HostPriority = 0; bResult = pInParams->GetDWORD( L"HostPriority", // <--------------------------- HostPriority ); if (!bResult) { TRACE_CRIT(L"Could not read HostPriority. Keeping existing"); } else { Cfg.SetHostPriority(HostPriority); } bResult = pInParams->GetCHString( L"DedicatedNetworkAddress", // <----------------- sTemp ); if (!bResult) { TRACE_CRIT(L"Could not dedicated IP. Keeping existing"); } else { LPCWSTR szAddress = NULL; szAddress = (LPCWSTR) sTemp; // no copies here. Cfg.SetDedicatedNetworkAddress(szAddress); // // For now, we'll always try to add the dedicated IP address // to the NIC. // Cfg.fAddDedicatedIp = TRUE; szAddress = NULL; } // // StartMode // { bool StartMode = FALSE; bResult = pInParams->Getbool( L"ClusterModeOnStart", // <----------------- StartMode ); if (!bResult) { TRACE_CRIT(L"Could not read StartMode. Keeping existing"); } else { NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE ClusterModeOnStart; if (StartMode) { ClusterModeOnStart = NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE_STARTED; } else { ClusterModeOnStart = NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE_STOPPED; } Cfg.SetClusterModeOnStart(ClusterModeOnStart); } } // // Remote control enabled // { bool bRemoteControlEnabled; bResult = pInParams->Getbool( L"RemoteControlEnabled", // <--------------- bRemoteControlEnabled ); if (!bResult) { TRACE_CRIT(L"Could not read RemoteControlEnabled. Keeping existing"); } else { Cfg.SetRemoteControlEnabled(bRemoteControlEnabled!=FALSE); } } // // TODO: if PartialUpdate is specified, we need to // make sure that fValidNlbCfg is already set. // Cfg.fValidNlbCfg = TRUE; } while (FALSE) ; } // // Call NlbConfigurationUpdate::DuUpdate to do the actual work. // UINT NewGeneration = 0; LPWSTR pLog = NULL; Status = NlbConfigurationUpdate::DoUpdate( pAdapterGuid, pClientDescription, &Cfg, &NewGeneration, &pLog ); // // Fill out the out parameters: status new generation and log // pOutParams->SetDWORD(L"ReturnValue", (DWORD) Status); pOutParams->SetDWORD(L"NewGeneration", (DWORD) NewGeneration); if (pLog != NULL) { pOutParams->SetCHString(L"Log", pLog); delete pLog; pLog = NULL; } // // If we've actually called DoUpdate, // we always return WBEM_NO_ERROR. The return value has the // real result. // Status = WBEM_NO_ERROR; end: if (pSA!=NULL) { SafeArrayDestroy(pSA); pSA = NULL; } TRACE_VERB(L"<-%!FUNC! returns 0x%08lx", (UINT) Status); return Status; } WBEMSTATUS ProvQueryConfigurationUpdateStatus( CInstance *pInParams, CInstance *pOutParams ) /*++ WMI provider wrapper around NlbConfigurationUpdate::GetUpdateStatus --*/ { if (!g_UpdateConfigurationEnabled) return WBEM_E_PROVIDER_NOT_CAPABLE; LPCWSTR pAdapterGuid = NULL; WBEMSTATUS Status = WBEM_E_PROVIDER_NOT_CAPABLE; CHString sTemp; bool fRet; DWORD Generation = 0; /* [IN] String AdapterGuid, [IN] uint32 Generation, [OUT] String Log */ fRet = pInParams->GetCHString( L"AdapterGuid", sTemp); if (!fRet) { TRACE_CRIT("->%!FUNC!: Missing adapter guid!"); Status = WBEM_E_INVALID_PARAMETER; goto end; } // // Note: (LPCWSTR) sTemp returns an internal pointer to sTemp's char // buffer -- see operator LPCWSTR() of WString docs. // pAdapterGuid = (LPCWSTR) sTemp; if (pAdapterGuid == NULL || *pAdapterGuid == 0) { TRACE_CRIT("->%!FUNC!: Null of empty adapter guid!"); Status = WBEM_E_INVALID_PARAMETER; goto end; } else { TRACE_VERB(L"->%!FUNC!(Nic=%ws)", pAdapterGuid); } fRet = pInParams->GetDWORD( L"Generation", // <-------------------------------- Generation ); if (!fRet) { TRACE_CRIT("%!FUNC!: Missing generation!"); Status = WBEM_E_INVALID_PARAMETER; goto end; } // // Call NlbConfigurationUpdate::GetUpdateResult to do the actual work. // LPWSTR pLog = NULL; WBEMSTATUS CompletionStatus = WBEM_NO_ERROR; Status = NlbConfigurationUpdate::GetUpdateStatus( pAdapterGuid, Generation, FALSE, // FALSE == Don't delete completion record &CompletionStatus, &pLog ); if (!FAILED(Status)) { // // Fill out the out parameters: status new generation and log // pOutParams->SetDWORD(L"ReturnValue", (DWORD) CompletionStatus); if (pLog != NULL) { pOutParams->SetCHString(L"Log", pLog); delete pLog; pLog = NULL; } } end: TRACE_VERB(L"<-%!FUNC! returns 0x%08lx", (UINT) Status); return Status; }