You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2296 lines
59 KiB
2296 lines
59 KiB
//***************************************************************************
|
|
//
|
|
// EXTCFG.CPP
|
|
//
|
|
// Module: WMI Framework Instance provider
|
|
//
|
|
// Purpose: Low-level utilities to configure NICs -- bind/unbind,
|
|
// get/set IP address lists, and get/set NLB cluster params.
|
|
//
|
|
// Copyright (c)2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
// History:
|
|
//
|
|
// 04/05/01 JosephJ Created (original version, from updatecfg.cpp under
|
|
// nlbmgr\provider).
|
|
// 07/23/01 JosephJ Moved functionality to lib.
|
|
//
|
|
//***************************************************************************
|
|
#include "private.h"
|
|
#include "extcfg.tmh"
|
|
|
|
//
|
|
// NLBUPD_MAX_NETWORK_ADDRESS_LENGTH is the max number of chars (excluding
|
|
// the terminating 0) of a string of the form "ip-addr/subnet", eg:
|
|
// "10.0.0.1/255.255.255.0"
|
|
//
|
|
#define NLBUPD_MAX_NETWORK_ADDRESS_LENGTH \
|
|
(WLBS_MAX_CL_IP_ADDR + 1 + WLBS_MAX_CL_NET_MASK)
|
|
|
|
|
|
LPWSTR *
|
|
allocate_string_array(
|
|
UINT NumStrings,
|
|
UINT StringLen // excluding ending NULL
|
|
);
|
|
|
|
WBEMSTATUS
|
|
address_string_to_ip_and_subnet(
|
|
IN LPCWSTR szAddress,
|
|
OUT LPWSTR szIp, // max WLBS_MAX_CL_IP_ADDR
|
|
OUT LPWSTR szSubnet // max WLBS_MAX_CL_NET_MASK
|
|
);
|
|
|
|
WBEMSTATUS
|
|
ip_and_subnet_to_address_string(
|
|
IN LPCWSTR szIp,
|
|
IN LPCWSTR szSubnet,
|
|
IN UINT cchAddress, // length in chars, including NULL.
|
|
OUT LPWSTR szAddress // max NLBUPD_MAX_NETWORK_ADDRESS_LENGTH
|
|
// + 1 (for NULL)
|
|
);
|
|
|
|
VOID
|
|
uint_to_szipaddr(
|
|
UINT uIpAddress, // Ip address or subnet -- no validation, network order
|
|
UINT cchLen,
|
|
WCHAR *rgAddress // Expected to be at least 17 chars long
|
|
);
|
|
|
|
const NLB_IP_ADDRESS_INFO *
|
|
find_ip_in_ipinfo(
|
|
LPCWSTR szIpToFind,
|
|
const NLB_IP_ADDRESS_INFO *pIpInfo,
|
|
UINT NumIpInfos
|
|
);
|
|
|
|
NLBERROR
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::AnalyzeUpdate(
|
|
IN OUT NLB_EXTENDED_CLUSTER_CONFIGURATION *pNewCfg,
|
|
OUT BOOL *pfConnectivityChange
|
|
)
|
|
//
|
|
// NLBERR_NO_CHANGE -- update is a no-op.
|
|
//
|
|
// Will MUNGE pNewCfg -- munge NlbParams and also
|
|
// fill out pIpAddressInfo if it's NULL.
|
|
//
|
|
{
|
|
NLBERROR nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
|
|
BOOL fConnectivityChange = FALSE;
|
|
BOOL fSettingsChanged = FALSE;
|
|
UINT NumIpAddresses = 0;
|
|
NLB_IP_ADDRESS_INFO *pNewIpInfo = NULL;
|
|
const NLB_EXTENDED_CLUSTER_CONFIGURATION *pOldCfg = this;
|
|
UINT u;
|
|
LPCWSTR szFriendlyName = m_szFriendlyName;
|
|
|
|
if (szFriendlyName == NULL)
|
|
{
|
|
szFriendlyName = L"";
|
|
}
|
|
|
|
|
|
if (pOldCfg->fBound && !pOldCfg->fValidNlbCfg)
|
|
{
|
|
//
|
|
// We're starting with a bound but invalid cluster state -- all bets are
|
|
// off.
|
|
//
|
|
fConnectivityChange = TRUE;
|
|
TRACE_CRIT("Analyze: Choosing Async because old state is invalid %ws", szFriendlyName);
|
|
}
|
|
else if (pOldCfg->fBound != pNewCfg->fBound)
|
|
{
|
|
//
|
|
// bound/unbound state is different -- we do async
|
|
//
|
|
fConnectivityChange = TRUE;
|
|
|
|
if (pNewCfg->fBound)
|
|
{
|
|
TRACE_CRIT("Analyze: Request to bind NLB to %ws", szFriendlyName);
|
|
}
|
|
else
|
|
{
|
|
TRACE_CRIT("Analyze: Request to unbind NLB from %ws", szFriendlyName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pNewCfg->fBound)
|
|
{
|
|
TRACE_CRIT("Analyze: Request to change NLB configuration on %ws", szFriendlyName);
|
|
}
|
|
else
|
|
{
|
|
TRACE_CRIT("Analyze: NLB not bound and to remain not bound on %ws", szFriendlyName);
|
|
}
|
|
}
|
|
|
|
if (pNewCfg->fBound)
|
|
{
|
|
const WLBS_REG_PARAMS *pOldParams = NULL;
|
|
|
|
if (pOldCfg->fBound)
|
|
{
|
|
pOldParams = &pOldCfg->NlbParams;
|
|
}
|
|
|
|
//
|
|
// We may have been bound before and we remain bound, let's check if we
|
|
// still need to do async, and also vaidate pNewCfg wlbs params in the
|
|
// process
|
|
//
|
|
|
|
WBEMSTATUS
|
|
TmpStatus = CfgUtilsAnalyzeNlbUpdate(
|
|
pOldParams,
|
|
&pNewCfg->NlbParams,
|
|
&fConnectivityChange
|
|
);
|
|
|
|
if (FAILED(TmpStatus))
|
|
{
|
|
TRACE_CRIT("Analyze: Error analyzing nlb params for %ws", szFriendlyName);
|
|
switch(TmpStatus)
|
|
{
|
|
|
|
case WBEM_E_INVALID_PARAMETER:
|
|
nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
|
|
break;
|
|
|
|
case WBEM_E_INITIALIZATION_FAILURE:
|
|
nerr = NLBERR_INITIALIZATION_FAILURE;
|
|
break;
|
|
|
|
default:
|
|
nerr = NLBERR_LLAPI_FAILURE;
|
|
break;
|
|
}
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// NOTE: CfgUtilsAnalyzeNlbUpdate can return WBEM_S_FALSE if
|
|
// the update is a no-op. We should be careful to preserve this
|
|
// on success.
|
|
//
|
|
if (TmpStatus == WBEM_S_FALSE)
|
|
{
|
|
//
|
|
// Let's check if a new password has been specified...
|
|
//
|
|
if (pNewCfg->NewRemoteControlPasswordSet())
|
|
{
|
|
fSettingsChanged = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fSettingsChanged = TRUE;
|
|
}
|
|
|
|
//
|
|
// Check the supplied list of IP addresses, to make sure that
|
|
// includes the dedicated IP first and the cluster vip and the
|
|
// per-port-rule vips.
|
|
//
|
|
|
|
NumIpAddresses = pNewCfg->NumIpAddresses;
|
|
|
|
if ((NumIpAddresses == 0) != (pNewCfg->pIpAddressInfo == NULL))
|
|
{
|
|
// Bogus input
|
|
TRACE_CRIT("Analze: mismatch between NumIpAddresses and pIpInfo");
|
|
goto end;
|
|
}
|
|
|
|
nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
|
|
|
|
if (NumIpAddresses == 0)
|
|
{
|
|
BOOL fRet;
|
|
NlbIpAddressList IpList;
|
|
|
|
if (pOldCfg->fBound && pOldCfg->fValidNlbCfg)
|
|
{
|
|
//
|
|
// NLB is currently bound with a valid configuration.
|
|
//
|
|
|
|
//
|
|
// If we we're told to do so, we try to preserve
|
|
// old IP addresses as far as possible. So we start with the
|
|
// old config, remove the old dedicated IP address (if present),
|
|
// and primary VIP, and add the new dedicated IP address (if
|
|
// present) and cluster vip. If subnet masks have changed for
|
|
// these we update them.
|
|
//
|
|
// All other IP addresses are left intact.
|
|
//
|
|
//
|
|
if (pNewCfg->fAddClusterIps)
|
|
{
|
|
|
|
//
|
|
// Start with the original set of ip addresses.
|
|
//
|
|
fRet = IpList.Set(
|
|
pOldCfg->NumIpAddresses,
|
|
pOldCfg->pIpAddressInfo,
|
|
0
|
|
);
|
|
|
|
if (!fRet)
|
|
{
|
|
TRACE_CRIT("!FUNC!: IpList.Set (orig ips) failed");
|
|
goto end;
|
|
}
|
|
|
|
if (_wcsicmp(pNewCfg->NlbParams.cl_ip_addr,
|
|
pOldCfg->NlbParams.cl_ip_addr) )
|
|
{
|
|
//
|
|
// If the cluster IP has changed,
|
|
// remove the old cluster IP address.
|
|
//
|
|
// 1/25/02 josephj NOTE: we only do this
|
|
// if the cluster IP has CHANGED,
|
|
// otherwise, by taking it out, we lose it's position
|
|
// in the old config, so we may end up changing it's
|
|
// position unnecessarily (added the wcsicmp
|
|
// check above today).
|
|
//
|
|
// We don't care if it fails.
|
|
//
|
|
(VOID) IpList.Modify(
|
|
pOldCfg->NlbParams.cl_ip_addr,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//
|
|
// Remove the old dedicated IP address first
|
|
// We don't care if this fails.
|
|
//
|
|
(VOID) IpList.Modify(
|
|
pOldCfg->NlbParams.ded_ip_addr,
|
|
NULL, // new ip address
|
|
NULL // new subnet mask
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
if (pNewCfg->fAddClusterIps)
|
|
{
|
|
//
|
|
// Now add the new cluster Ip address
|
|
//
|
|
fRet = IpList.Modify(
|
|
NULL,
|
|
pNewCfg->NlbParams.cl_ip_addr,
|
|
pNewCfg->NlbParams.cl_net_mask
|
|
);
|
|
|
|
if (!fRet)
|
|
{
|
|
TRACE_CRIT("!FUNC!: IpList.Modify (new cl ip) failed");
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
if (pNewCfg->fAddDedicatedIp)
|
|
{
|
|
//
|
|
// Add the new dedicated IP address --
|
|
// to ensure when we add it, it's at the head of the list.
|
|
//
|
|
|
|
//
|
|
// We won't add it if it is null, of course.
|
|
//
|
|
if (!pNewCfg->IsBlankDedicatedIp())
|
|
{
|
|
fRet = IpList.Modify(
|
|
NULL,
|
|
pNewCfg->NlbParams.ded_ip_addr,
|
|
pNewCfg->NlbParams.ded_net_mask
|
|
);
|
|
if (!fRet)
|
|
{
|
|
TRACE_CRIT("!FUNC!: IpList.Modify (new ded ip) failed");
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Finally, set these new addresses.
|
|
//
|
|
pNewCfg->SetNetworkAddressesRaw(NULL,0);
|
|
IpList.Extract(
|
|
REF pNewCfg->NumIpAddresses,
|
|
REF pNewCfg->pIpAddressInfo
|
|
);
|
|
nerr = NLBERR_OK;
|
|
|
|
} // End case that NumIpAddresses is zero.
|
|
|
|
|
|
//
|
|
// We're done munging IP addresses; Now get the latest
|
|
// ip address info and count and make sure things look ok.
|
|
//
|
|
pNewIpInfo = pNewCfg->pIpAddressInfo;
|
|
NumIpAddresses = pNewCfg->NumIpAddresses;
|
|
nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
|
|
|
|
//
|
|
// Check that dedicated ip address, if present is first.
|
|
//
|
|
if (pNewCfg->fAddDedicatedIp && !pNewCfg->IsBlankDedicatedIp())
|
|
{
|
|
|
|
if (NumIpAddresses == 0)
|
|
{
|
|
//
|
|
// We don't expect to get here because of checks above, but
|
|
// neverthless...
|
|
//
|
|
TRACE_CRIT("%!FUNC! address list unexpectedly zero");
|
|
nerr = NLBERR_INTERNAL_ERROR;
|
|
goto end;
|
|
}
|
|
|
|
if (_wcsicmp(pNewIpInfo[0].IpAddress, pNewCfg->NlbParams.ded_ip_addr))
|
|
{
|
|
TRACE_CRIT("%!FUNC! ERROR: dedicated IP address(%ws) is not first IP address(%ws)",
|
|
pNewCfg->NlbParams.ded_ip_addr, pNewIpInfo[0].IpAddress);
|
|
goto end;
|
|
}
|
|
|
|
if (_wcsicmp(pNewIpInfo[0].SubnetMask, pNewCfg->NlbParams.ded_net_mask))
|
|
{
|
|
TRACE_CRIT("%!FUNC! ERROR: dedicated net mask(%ws) does not match IP net mask(%ws)",
|
|
pNewCfg->NlbParams.ded_net_mask, pNewIpInfo[0].SubnetMask);
|
|
goto end;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Check that cluster-vip is present
|
|
//
|
|
if (fAddClusterIps)
|
|
{
|
|
for (u=0; u< NumIpAddresses; u++)
|
|
{
|
|
if (!_wcsicmp(pNewIpInfo[u].IpAddress, pNewCfg->NlbParams.cl_ip_addr))
|
|
{
|
|
//
|
|
// Found it! Check that the subnet masks match.
|
|
//
|
|
if (_wcsicmp(pNewIpInfo[u].SubnetMask, pNewCfg->NlbParams.cl_net_mask))
|
|
{
|
|
TRACE_CRIT("Cluster subnet mask doesn't match that in addr list");
|
|
goto end;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (u==NumIpAddresses)
|
|
{
|
|
TRACE_CRIT("Cluster ip address(%ws) is not in the list of addresses!", pNewCfg->NlbParams.cl_ip_addr);
|
|
goto end;
|
|
}
|
|
//
|
|
// Check that per-port-rule vips are present.
|
|
// TODO
|
|
{
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// NLB is to be unbound.
|
|
//
|
|
NumIpAddresses = pNewCfg->NumIpAddresses;
|
|
|
|
if (NumIpAddresses == 0 && pOldCfg->fBound && pOldCfg->fValidNlbCfg)
|
|
{
|
|
//
|
|
// No ip addresses specified and we're currently bound.
|
|
// If the DIP is present in the current
|
|
// list of IP addresses, we keep it even after we unbind.
|
|
//
|
|
const NLB_IP_ADDRESS_INFO *pFoundInfo = NULL;
|
|
pFoundInfo = find_ip_in_ipinfo(
|
|
pOldCfg->NlbParams.ded_ip_addr,
|
|
pOldCfg->pIpAddressInfo,
|
|
pOldCfg->NumIpAddresses
|
|
);
|
|
if (pFoundInfo != NULL)
|
|
{
|
|
//
|
|
// Found it -- let's take it.
|
|
//
|
|
BOOL fRet;
|
|
NlbIpAddressList IpList;
|
|
fRet = IpList.Set(1, pFoundInfo, 0);
|
|
if (fRet)
|
|
{
|
|
TRACE_VERB(
|
|
"%!FUNC! preserving dedicated ip address %ws on unbind",
|
|
pFoundInfo->IpAddress
|
|
);
|
|
IpList.Extract(
|
|
REF pNewCfg->NumIpAddresses,
|
|
REF pNewCfg->pIpAddressInfo
|
|
);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// We don't do any checking on the supplied
|
|
// list of IP addresses -- we assume caller knows best. Note that
|
|
// if NULL
|
|
// we switch to dhcp/autonet.
|
|
//
|
|
}
|
|
|
|
}
|
|
|
|
nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
|
|
//
|
|
// If there's any change in the list of ipaddresses or subnets, including
|
|
// a change in the order, we switch to async.
|
|
//
|
|
if (pNewCfg->NumIpAddresses != pOldCfg->NumIpAddresses)
|
|
{
|
|
TRACE_INFO("Analyze: detected change in list of IP addresses on %ws", szFriendlyName);
|
|
fConnectivityChange = TRUE;
|
|
}
|
|
else
|
|
{
|
|
NLB_IP_ADDRESS_INFO *pOldIpInfo = NULL;
|
|
|
|
//
|
|
// Check if there is a change in the list of ip addresses or
|
|
// their order of appearance.
|
|
//
|
|
NumIpAddresses = pNewCfg->NumIpAddresses;
|
|
pOldIpInfo = pOldCfg->pIpAddressInfo;
|
|
pNewIpInfo = pNewCfg->pIpAddressInfo;
|
|
for (u=0; u<NumIpAddresses; u++)
|
|
{
|
|
if ( _wcsicmp(pNewIpInfo[u].IpAddress, pOldIpInfo[u].IpAddress)
|
|
|| _wcsicmp(pNewIpInfo[u].SubnetMask, pOldIpInfo[u].SubnetMask))
|
|
{
|
|
TRACE_INFO("Analyze: detected change in list of IP addresses on %ws", szFriendlyName);
|
|
fConnectivityChange = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
nerr = NLBERR_OK;
|
|
|
|
|
|
end:
|
|
|
|
|
|
if (nerr == NLBERR_OK)
|
|
{
|
|
*pfConnectivityChange = fConnectivityChange;
|
|
|
|
if (fConnectivityChange)
|
|
{
|
|
fSettingsChanged = TRUE;
|
|
}
|
|
|
|
if (fSettingsChanged)
|
|
{
|
|
nerr = NLBERR_OK;
|
|
}
|
|
else
|
|
{
|
|
nerr = NLBERR_NO_CHANGE;
|
|
}
|
|
}
|
|
|
|
return nerr;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::Update(
|
|
IN const NLB_EXTENDED_CLUSTER_CONFIGURATION *pCfgNew
|
|
)
|
|
//
|
|
// Applies the properties in pCfgNew to this.
|
|
// Does NOT copy szNewRemoteControlPassword -- instead sets that field to NULL
|
|
//
|
|
{
|
|
WBEMSTATUS Status;
|
|
UINT NumIpAddresses = pCfgNew->NumIpAddresses;
|
|
NLB_IP_ADDRESS_INFO *pIpAddressInfo = NULL;
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION *pCfg = this;
|
|
|
|
//
|
|
// Free and realloc pCfg's ip info array if rquired.
|
|
//
|
|
if (pCfg->NumIpAddresses == NumIpAddresses)
|
|
{
|
|
//
|
|
// we can re-use the existing one
|
|
//
|
|
pIpAddressInfo = pCfg->pIpAddressInfo;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Free the old one and allocate space for the new array if required.
|
|
//
|
|
|
|
if (NumIpAddresses != 0)
|
|
{
|
|
pIpAddressInfo = new NLB_IP_ADDRESS_INFO[NumIpAddresses];
|
|
if (pIpAddressInfo == NULL)
|
|
{
|
|
TRACE_CRIT(L"Error allocating space for IP address info array");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
if (pCfg->NumIpAddresses!=0)
|
|
{
|
|
delete pCfg->pIpAddressInfo;
|
|
pCfg->pIpAddressInfo = NULL;
|
|
pCfg->NumIpAddresses = 0;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Copy over the new ip address info, if there is any.
|
|
//
|
|
if (NumIpAddresses)
|
|
{
|
|
CopyMemory(
|
|
pIpAddressInfo,
|
|
pCfgNew->pIpAddressInfo,
|
|
NumIpAddresses*sizeof(*pIpAddressInfo)
|
|
);
|
|
}
|
|
|
|
|
|
//
|
|
// Do any other error checks here.
|
|
//
|
|
|
|
//
|
|
// Struct copy the entire structure, then fix up the pointer to
|
|
// ip address info array.
|
|
//
|
|
(VOID) pCfg->SetFriendlyName(NULL);
|
|
delete m_szNewRemoteControlPassword;
|
|
*pCfg = *pCfgNew; // struct copy
|
|
pCfg->m_szFriendlyName = NULL; // TODO: clean this up.
|
|
pCfg->m_szNewRemoteControlPassword = NULL;
|
|
pCfg->pIpAddressInfo = pIpAddressInfo;
|
|
pCfg->NumIpAddresses = NumIpAddresses;
|
|
(VOID) pCfg->SetFriendlyName(pCfgNew->m_szFriendlyName);
|
|
|
|
//
|
|
// Update does NOT copy over the new remote control password or
|
|
// new hashed password -- in fact
|
|
// it ends up clearing the new password fields.
|
|
//
|
|
pCfg->ClearNewRemoteControlPassword();
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetNetworkAddresses(
|
|
IN LPCWSTR *pszNetworkAddresses,
|
|
IN UINT NumNetworkAddresses
|
|
)
|
|
/*
|
|
pszNetworkAddresses is an array of strings. These strings have the
|
|
format "addr/subnet", eg: "10.0.0.1/255.0.0.0"
|
|
*/
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
NLB_IP_ADDRESS_INFO *pIpInfo = NULL;
|
|
|
|
if (NumNetworkAddresses != 0)
|
|
{
|
|
UINT NumBad = 0;
|
|
|
|
//
|
|
// Allocate space for the new ip-address-info array
|
|
//
|
|
pIpInfo = new NLB_IP_ADDRESS_INFO[NumNetworkAddresses];
|
|
if (pIpInfo == NULL)
|
|
{
|
|
TRACE_CRIT("%!FUNC!: Alloc failure!");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
ZeroMemory(pIpInfo, NumNetworkAddresses*sizeof(*pIpInfo));
|
|
|
|
|
|
//
|
|
// Convert IP addresses to our internal form.
|
|
//
|
|
for (UINT u=0;u<NumNetworkAddresses; u++)
|
|
{
|
|
//
|
|
// We extrace each IP address and it's corresponding subnet mask
|
|
// from the "addr/subnet" format insert it into a
|
|
// NLB_IP_ADDRESS_INFO structure.
|
|
//
|
|
// SAMPLE: 10.0.0.1/255.0.0.0
|
|
//
|
|
LPCWSTR szAddr = pszNetworkAddresses[u];
|
|
UINT uIpAddress = 0;
|
|
|
|
//
|
|
// If this is not a valid address, we skip it.
|
|
//
|
|
Status = CfgUtilsValidateNetworkAddress(
|
|
szAddr,
|
|
&uIpAddress,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
TRACE_CRIT("%!FUNC!: Invalid ip or subnet: %ws", szAddr);
|
|
NumBad++;
|
|
continue;
|
|
}
|
|
|
|
ASSERT(u>=NumBad);
|
|
|
|
Status = address_string_to_ip_and_subnet(
|
|
szAddr,
|
|
pIpInfo[u-NumBad].IpAddress,
|
|
pIpInfo[u-NumBad].SubnetMask
|
|
);
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
//
|
|
// This one of the ip/subnet parms is too large.
|
|
//
|
|
TRACE_CRIT("%!FUNC!:ip or subnet part too large: %ws", szAddr);
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
NumNetworkAddresses -= NumBad;
|
|
if (NumNetworkAddresses == 0)
|
|
{
|
|
delete[] pIpInfo;
|
|
pIpInfo = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Replace the old ip-address-info with the new one
|
|
//
|
|
if (this->pIpAddressInfo != NULL)
|
|
{
|
|
delete this->pIpAddressInfo;
|
|
this->pIpAddressInfo = NULL;
|
|
}
|
|
this->pIpAddressInfo = pIpInfo;
|
|
pIpInfo = NULL;
|
|
this->NumIpAddresses = NumNetworkAddresses;
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
if (pIpInfo != NULL)
|
|
{
|
|
delete[] pIpInfo;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetNetworkAddresses(
|
|
OUT LPWSTR **ppszNetworkAddresses, // free using delete
|
|
OUT UINT *pNumNetworkAddresses
|
|
)
|
|
/*
|
|
ppszNetworkAddresses is filled out on successful return to
|
|
an array of strings. These strings have the
|
|
format "addr/subnet", eg: "10.0.0.1/255.0.0.0"
|
|
*/
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
UINT AddrCount = this->NumIpAddresses;
|
|
NLB_IP_ADDRESS_INFO *pIpInfo = this->pIpAddressInfo;
|
|
LPWSTR *pszNetworkAddresses = NULL;
|
|
|
|
|
|
if (AddrCount != 0)
|
|
{
|
|
//
|
|
// Convert IP addresses from our internal form into
|
|
// format "addr/subnet", eg: "10.0.0.1/255.0.0.0"
|
|
//
|
|
//
|
|
const UINT cchLen = WLBS_MAX_CL_IP_ADDR // for IP address
|
|
+ WLBS_MAX_CL_NET_MASK // for subnet mask
|
|
+ 1; // for separating '/'
|
|
|
|
|
|
pszNetworkAddresses = allocate_string_array(
|
|
AddrCount,
|
|
cchLen
|
|
);
|
|
if (pszNetworkAddresses == NULL)
|
|
{
|
|
TRACE_CRIT("%!FUNC!: Alloc failure!");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
|
|
for (UINT u=0;u<AddrCount; u++)
|
|
{
|
|
//
|
|
// We extrace each IP address and it's corresponding subnet mask
|
|
// insert them into a NLB_IP_ADDRESS_INFO
|
|
// structure.
|
|
//
|
|
LPCWSTR pIpSrc = pIpInfo[u].IpAddress;
|
|
LPCWSTR pSubSrc = pIpInfo[u].SubnetMask;
|
|
LPWSTR szDest = pszNetworkAddresses[u];
|
|
Status = ip_and_subnet_to_address_string(
|
|
pIpSrc,
|
|
pSubSrc,
|
|
cchLen,
|
|
szDest
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
//
|
|
// This would be an implementation error in get_multi_string_...
|
|
//
|
|
ASSERT(FALSE);
|
|
Status = WBEM_E_CRITICAL_ERROR;
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
if (pszNetworkAddresses != NULL)
|
|
{
|
|
delete pszNetworkAddresses;
|
|
pszNetworkAddresses = NULL;
|
|
}
|
|
AddrCount = 0;
|
|
}
|
|
|
|
*ppszNetworkAddresses = pszNetworkAddresses;
|
|
*pNumNetworkAddresses = AddrCount;
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetNetworkAddresPairs(
|
|
IN LPCWSTR *pszIpAddresses,
|
|
IN LPCWSTR *pszSubnetMasks,
|
|
IN UINT NumNetworkAddresses
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
goto end;
|
|
|
|
end:
|
|
return Status;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetNetworkAddressPairs(
|
|
OUT LPWSTR **ppszIpAddresses, // free using delete
|
|
OUT LPWSTR **ppszIpSubnetMasks, // free using delete
|
|
OUT UINT *pNumNetworkAddresses
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
goto end;
|
|
|
|
end:
|
|
return Status;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetPortRules(
|
|
OUT LPWSTR **ppszPortRules,
|
|
OUT UINT *pNumPortRules
|
|
)
|
|
{
|
|
WLBS_PORT_RULE *pRules = NULL;
|
|
UINT NumRules = 0;
|
|
WBEMSTATUS Status;
|
|
LPWSTR *pszPortRules = NULL;
|
|
|
|
// DebugBreak();
|
|
|
|
*ppszPortRules = NULL;
|
|
*pNumPortRules = 0;
|
|
|
|
Status = CfgUtilGetPortRules(
|
|
&NlbParams,
|
|
&pRules,
|
|
&NumRules
|
|
);
|
|
|
|
if (FAILED(Status) || NumRules == 0)
|
|
{
|
|
pRules = NULL;
|
|
goto end;
|
|
}
|
|
|
|
pszPortRules = CfgUtilsAllocateStringArray(
|
|
NumRules,
|
|
NLB_MAX_PORT_STRING_SIZE
|
|
);
|
|
|
|
if (pszPortRules == NULL)
|
|
{
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Now convert from the binary to the string format.
|
|
//
|
|
for (UINT u = 0; u< NumRules; u++)
|
|
{
|
|
BOOL fRet;
|
|
fRet = CfgUtilsGetPortRuleString(
|
|
pRules+u,
|
|
pszPortRules[u]
|
|
);
|
|
if (!fRet)
|
|
{
|
|
//
|
|
// Must be a bad binary port rule!
|
|
// For now, we just set the port rule to "".
|
|
//
|
|
*pszPortRules[u]=0;
|
|
TRACE_INFO("%!FUNC!: Invalid port rule %lu", u);
|
|
}
|
|
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
delete pRules;
|
|
|
|
*pNumPortRules = NumRules;
|
|
*ppszPortRules = pszPortRules;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetPortRules(
|
|
IN LPCWSTR *pszPortRules,
|
|
IN UINT NumPortRules
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
WLBS_PORT_RULE *pRules = NULL;
|
|
|
|
// DebugBreak();
|
|
|
|
if (NumPortRules!=0)
|
|
{
|
|
pRules = new WLBS_PORT_RULE[NumPortRules];
|
|
if (pRules == NULL)
|
|
{
|
|
TRACE_CRIT("%!FUNC!: Allocation failure!");
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialiez the binary form of the port rules.
|
|
//
|
|
for (UINT u=0; u < NumPortRules; u++)
|
|
{
|
|
LPCWSTR szRule = pszPortRules[u];
|
|
BOOL fRet;
|
|
fRet = CfgUtilsSetPortRuleString(
|
|
szRule,
|
|
pRules+u
|
|
);
|
|
if (fRet == FALSE)
|
|
{
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
Status = CfgUtilSetPortRules(
|
|
pRules,
|
|
NumPortRules,
|
|
&NlbParams
|
|
);
|
|
|
|
end:
|
|
|
|
delete[] pRules;
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetPortRulesSafeArray(
|
|
IN SAFEARRAY *pSA
|
|
)
|
|
{
|
|
return WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetPortRulesSafeArray(
|
|
OUT SAFEARRAY **ppSA
|
|
)
|
|
{
|
|
return WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetClusterNetworkAddress(
|
|
OUT LPWSTR *pszAddress
|
|
)
|
|
/*
|
|
allocate and return the cluster-ip and mask in address/subnet form.
|
|
Eg: "10.0.0.1/255.0.0.0"
|
|
*/
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
|
|
LPWSTR szAddress = NULL;
|
|
|
|
if (fValidNlbCfg)
|
|
{
|
|
szAddress = new WCHAR[NLBUPD_MAX_NETWORK_ADDRESS_LENGTH+1];
|
|
if (szAddress != NULL)
|
|
{
|
|
Status = ip_and_subnet_to_address_string(
|
|
NlbParams.cl_ip_addr,
|
|
NlbParams.cl_net_mask,
|
|
NLBUPD_MAX_NETWORK_ADDRESS_LENGTH+1,
|
|
szAddress
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
delete[] szAddress;
|
|
szAddress = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pszAddress = szAddress;
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetClusterNetworkAddress(
|
|
IN LPCWSTR szAddress
|
|
)
|
|
{
|
|
if (szAddress == NULL) szAddress = L"";
|
|
(VOID) address_string_to_ip_and_subnet(
|
|
szAddress,
|
|
NlbParams.cl_ip_addr,
|
|
NlbParams.cl_net_mask
|
|
);
|
|
}
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetClusterName(
|
|
OUT LPWSTR *pszName
|
|
)
|
|
/*
|
|
allocate and return the cluster name
|
|
*/
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
|
|
LPWSTR szName = NULL;
|
|
|
|
if (fValidNlbCfg)
|
|
{
|
|
UINT len = wcslen(NlbParams.domain_name);
|
|
szName = new WCHAR[len+1]; // +1 for ending zero
|
|
if (szName != NULL)
|
|
{
|
|
CopyMemory(szName, NlbParams.domain_name, (len+1)*sizeof(WCHAR));
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
*pszName = szName;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetClusterName(
|
|
IN LPCWSTR szName
|
|
)
|
|
{
|
|
if (szName == NULL) szName = L"";
|
|
UINT len = wcslen(szName);
|
|
if (len>WLBS_MAX_DOMAIN_NAME)
|
|
{
|
|
TRACE_CRIT("%!FUNC!: Cluster name too large");
|
|
}
|
|
CopyMemory(NlbParams.domain_name, szName, (len+1)*sizeof(WCHAR));
|
|
}
|
|
|
|
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetDedicatedNetworkAddress(
|
|
OUT LPWSTR *pszAddress
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
|
|
LPWSTR szAddress = NULL;
|
|
|
|
if (fValidNlbCfg)
|
|
{
|
|
szAddress = new WCHAR[NLBUPD_MAX_NETWORK_ADDRESS_LENGTH+1];
|
|
if (szAddress != NULL)
|
|
{
|
|
Status = ip_and_subnet_to_address_string(
|
|
NlbParams.ded_ip_addr,
|
|
NlbParams.ded_net_mask,
|
|
NLBUPD_MAX_NETWORK_ADDRESS_LENGTH+1,
|
|
szAddress
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
delete[] szAddress;
|
|
szAddress = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pszAddress = szAddress;
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetDedicatedNetworkAddress(
|
|
IN LPCWSTR szAddress
|
|
)
|
|
{
|
|
if (szAddress == NULL || *szAddress == 0)
|
|
{
|
|
ARRAYSTRCPY(NlbParams.ded_ip_addr, CVY_DEF_DED_IP_ADDR);
|
|
ARRAYSTRCPY(NlbParams.ded_net_mask, CVY_DEF_DED_NET_MASK);
|
|
}
|
|
else
|
|
{
|
|
(VOID) address_string_to_ip_and_subnet(
|
|
szAddress,
|
|
NlbParams.ded_ip_addr,
|
|
NlbParams.ded_net_mask
|
|
);
|
|
}
|
|
}
|
|
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetTrafficMode(
|
|
VOID
|
|
) const
|
|
{
|
|
TRAFFIC_MODE TrafficMode = TRAFFIC_MODE_UNICAST;
|
|
|
|
if (NlbParams.mcast_support)
|
|
{
|
|
if (NlbParams.fIGMPSupport)
|
|
{
|
|
TrafficMode = TRAFFIC_MODE_IGMPMULTICAST;
|
|
}
|
|
else
|
|
{
|
|
TrafficMode = TRAFFIC_MODE_MULTICAST;
|
|
}
|
|
}
|
|
|
|
return TrafficMode;
|
|
}
|
|
|
|
VOID
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetTrafficMode(
|
|
TRAFFIC_MODE Mode
|
|
)
|
|
{
|
|
switch(Mode)
|
|
{
|
|
case TRAFFIC_MODE_UNICAST:
|
|
NlbParams.mcast_support = 0;
|
|
NlbParams.fIGMPSupport = 0;
|
|
break;
|
|
case TRAFFIC_MODE_IGMPMULTICAST:
|
|
NlbParams.mcast_support = 1;
|
|
NlbParams.fIGMPSupport = 1;
|
|
break;
|
|
case TRAFFIC_MODE_MULTICAST:
|
|
NlbParams.mcast_support = 1;
|
|
NlbParams.fIGMPSupport = 0;
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
UINT
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetHostPriority(
|
|
VOID
|
|
)
|
|
{
|
|
return NlbParams.host_priority;
|
|
}
|
|
|
|
VOID
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetHostPriority(
|
|
UINT Priority
|
|
)
|
|
{
|
|
NlbParams.host_priority = Priority;
|
|
}
|
|
|
|
//NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE
|
|
DWORD
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetClusterModeOnStart(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// If we decide to make cluster_mode something besides true/false we
|
|
// need to make the change here too...
|
|
//
|
|
/*
|
|
ASSERT(NlbParams.cluster_mode==TRUE || NlbParams.cluster_mode==FALSE);
|
|
if (NlbParams.cluster_mode)
|
|
{
|
|
return START_MODE_STARTED;
|
|
}
|
|
else
|
|
{
|
|
return START_MODE_STOPPED;
|
|
}
|
|
*/
|
|
return NlbParams.cluster_mode;
|
|
}
|
|
|
|
|
|
VOID
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetClusterModeOnStart(
|
|
// START_MODE Mode
|
|
DWORD Mode
|
|
)
|
|
{
|
|
/*
|
|
switch(Mode)
|
|
{
|
|
case START_MODE_STARTED:
|
|
NlbParams.cluster_mode = TRUE;
|
|
break;
|
|
case START_MODE_STOPPED:
|
|
NlbParams.cluster_mode = FALSE;
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
*/
|
|
NlbParams.cluster_mode = Mode;
|
|
}
|
|
|
|
BOOL
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetPersistSuspendOnReboot(
|
|
VOID
|
|
)
|
|
{
|
|
// This is a straight lift from wmi\ClusterWrapper.cpp\GetNodeConfig()
|
|
// -KarthicN
|
|
return ((NlbParams.persisted_states & CVY_PERSIST_STATE_SUSPENDED) != 0);
|
|
}
|
|
|
|
|
|
VOID
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetPersistSuspendOnReboot(
|
|
BOOL bPersistSuspendOnReboot
|
|
)
|
|
{
|
|
// This is a straight lift from wmi\ClusterWrapper.cpp\PutNodeConfig()
|
|
// -KarthicN
|
|
if (bPersistSuspendOnReboot)
|
|
{
|
|
NlbParams.persisted_states |= CVY_PERSIST_STATE_SUSPENDED;
|
|
}
|
|
else
|
|
{
|
|
NlbParams.persisted_states &= ~CVY_PERSIST_STATE_SUSPENDED;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetRemoteControlEnabled(
|
|
VOID
|
|
) const
|
|
{
|
|
return (NlbParams.rct_enabled!=FALSE);
|
|
}
|
|
|
|
VOID
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetRemoteControlEnabled(
|
|
BOOL fEnabled
|
|
)
|
|
{
|
|
NlbParams.rct_enabled = (fEnabled!=FALSE);
|
|
}
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetNetworkAddressesSafeArray(
|
|
IN SAFEARRAY *pSA
|
|
)
|
|
{
|
|
LPWSTR *pStrings=NULL;
|
|
UINT NumStrings = 0;
|
|
WBEMSTATUS Status;
|
|
Status = CfgUtilStringsFromSafeArray(
|
|
pSA,
|
|
&pStrings, // delete when done useing pStrings
|
|
&NumStrings
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
pStrings=NULL;
|
|
goto end;
|
|
}
|
|
|
|
Status = this->SetNetworkAddresses(
|
|
(LPCWSTR*)pStrings,
|
|
NumStrings
|
|
);
|
|
|
|
if (pStrings != NULL)
|
|
{
|
|
delete pStrings;
|
|
}
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetNetworkAddressesSafeArray(
|
|
OUT SAFEARRAY **ppSA
|
|
)
|
|
{
|
|
LPWSTR *pszNetworkAddresses = NULL;
|
|
UINT NumNetworkAddresses = 0;
|
|
SAFEARRAY *pSA=NULL;
|
|
WBEMSTATUS Status;
|
|
|
|
Status = this->GetNetworkAddresses(
|
|
&pszNetworkAddresses,
|
|
&NumNetworkAddresses
|
|
);
|
|
if (FAILED(Status))
|
|
{
|
|
pszNetworkAddresses = NULL;
|
|
goto end;
|
|
}
|
|
|
|
Status = CfgUtilSafeArrayFromStrings(
|
|
(LPCWSTR*) pszNetworkAddresses,
|
|
NumNetworkAddresses, // can be zero
|
|
&pSA
|
|
);
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
pSA = NULL;
|
|
}
|
|
|
|
end:
|
|
|
|
*ppSA = pSA;
|
|
if (pszNetworkAddresses != NULL)
|
|
{
|
|
delete pszNetworkAddresses;
|
|
pszNetworkAddresses = NULL;
|
|
}
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
TRACE_CRIT("%!FUNC!: couldn't extract network addresses from Cfg");
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
LPWSTR *
|
|
allocate_string_array(
|
|
UINT NumStrings,
|
|
UINT MaxStringLen // excluding ending NULL
|
|
)
|
|
/*
|
|
Allocate a single chunk of memory using the new LPWSTR[] operator.
|
|
The first NumStrings LPWSTR values of this operator contain an array
|
|
of pointers to WCHAR strings. Each of these strings
|
|
is of size (MaxStringLen+1) WCHARS.
|
|
The rest of the memory contains the strings themselve.
|
|
|
|
Return NULL if NumStrings==0 or on allocation failure.
|
|
|
|
Each of the strings are initialized to be empty strings (first char is 0).
|
|
*/
|
|
{
|
|
return CfgUtilsAllocateStringArray(NumStrings, MaxStringLen);
|
|
}
|
|
|
|
WBEMSTATUS
|
|
address_string_to_ip_and_subnet(
|
|
IN LPCWSTR szAddress,
|
|
OUT LPWSTR szIp, // max WLBS_MAX_CL_IP_ADDR including NULL
|
|
OUT LPWSTR szSubnet // max WLBS_MAX_CL_NET_MASK including NULL
|
|
)
|
|
// Special case: if szAddress == "", we zero out both szIp and szSubnet;
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
|
|
if (*szAddress == 0) {szAddress = L"/";} // Special case mentioned above
|
|
|
|
// from the "addr/subnet" format insert it into a
|
|
// NLB_IP_ADDRESS_INFO structure.
|
|
//
|
|
// SAMPLE: 10.0.0.1/255.0.0.0
|
|
//
|
|
LPCWSTR pSlash = NULL;
|
|
LPCWSTR pSrcSub = NULL;
|
|
|
|
*szIp = 0;
|
|
*szSubnet = 0;
|
|
|
|
pSlash = wcsrchr(szAddress, (int) '/');
|
|
if (pSlash == NULL)
|
|
{
|
|
TRACE_CRIT("%!FUNC!:missing subnet portion in %ws", szAddress);
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
pSrcSub = pSlash+1;
|
|
UINT len = (UINT) (pSlash - szAddress);
|
|
UINT len1 = wcslen(pSrcSub);
|
|
if ( (len < WLBS_MAX_CL_IP_ADDR) && (len1 < WLBS_MAX_CL_NET_MASK))
|
|
{
|
|
CopyMemory(szIp, szAddress, len*sizeof(WCHAR));
|
|
szIp[len] = 0;
|
|
CopyMemory(szSubnet, pSrcSub, (len1+1)*sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// One of the ip/subnet parms is too large.
|
|
//
|
|
TRACE_CRIT("%!FUNC!:ip or subnet part too large: %ws", szAddress);
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
ip_and_subnet_to_address_string(
|
|
IN LPCWSTR szIp,
|
|
IN LPCWSTR szSubnet,
|
|
IN UINT cchAddress,
|
|
OUT LPWSTR szAddress// max WLBS_MAX_CL_IP_ADDR
|
|
// + 1(for slash) + WLBS_MAX_CL_NET_MASK + 1 (for NULL)
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
|
|
UINT len = wcslen(szIp)+wcslen(szSubnet) + 1; // +1 for separating '/'
|
|
|
|
if (len >= NLBUPD_MAX_NETWORK_ADDRESS_LENGTH)
|
|
{
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
HRESULT hr;
|
|
hr = StringCchPrintf(
|
|
szAddress,
|
|
cchAddress,
|
|
L"%ws/%ws",
|
|
szIp,
|
|
szSubnet
|
|
);
|
|
if (hr == S_OK)
|
|
{
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::GetFriendlyName(
|
|
OUT LPWSTR *pszFriendlyName // Free using delete
|
|
) const
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_NOT_FOUND;
|
|
LPWSTR szName = NULL;
|
|
|
|
*pszFriendlyName = NULL;
|
|
|
|
if (m_szFriendlyName != NULL)
|
|
{
|
|
UINT len = wcslen(m_szFriendlyName);
|
|
szName = new WCHAR[len+1]; // +1 for ending 0
|
|
if (szName == NULL)
|
|
{
|
|
Status = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
Status = WBEM_NO_ERROR;
|
|
CopyMemory(szName, m_szFriendlyName, (len+1)*sizeof(WCHAR));
|
|
}
|
|
}
|
|
|
|
*pszFriendlyName = szName;
|
|
|
|
return Status;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetFriendlyName(
|
|
IN LPCWSTR szFriendlyName // Saves a copy of szFriendlyName
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
|
|
LPWSTR szName = NULL;
|
|
|
|
if (szFriendlyName != NULL)
|
|
{
|
|
UINT len = wcslen(szFriendlyName);
|
|
szName = new WCHAR[len+1]; // +1 for ending 0
|
|
if (szName == NULL)
|
|
{
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(szName, szFriendlyName, (len+1)*sizeof(WCHAR));
|
|
}
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
if (m_szFriendlyName != NULL)
|
|
{
|
|
delete m_szFriendlyName;
|
|
m_szFriendlyName = NULL;
|
|
}
|
|
m_szFriendlyName = szName;
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::SetNewRemoteControlPassword(
|
|
IN LPCWSTR szRemoteControlPassword // Saves a copy of szRemoteControlPassword
|
|
)
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY;
|
|
LPWSTR szName = NULL;
|
|
|
|
if (szRemoteControlPassword != NULL)
|
|
{
|
|
UINT len = wcslen(szRemoteControlPassword);
|
|
szName = new WCHAR[len+1]; // +1 for ending 0
|
|
if (szName == NULL)
|
|
{
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(szName, szRemoteControlPassword, (len+1)*sizeof(WCHAR));
|
|
}
|
|
|
|
m_fSetPassword = TRUE;
|
|
}
|
|
else
|
|
{
|
|
m_fSetPassword = FALSE;
|
|
}
|
|
|
|
Status = WBEM_NO_ERROR;
|
|
|
|
if (m_szNewRemoteControlPassword != NULL)
|
|
{
|
|
delete m_szNewRemoteControlPassword;
|
|
m_szNewRemoteControlPassword = NULL;
|
|
}
|
|
m_szNewRemoteControlPassword = szName;
|
|
|
|
end:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
WBEMSTATUS
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::
|
|
ModifyNetworkAddress(
|
|
IN LPCWSTR szOldIpAddress, OPTIONAL // network order
|
|
IN LPCWSTR szNewIpAddress, OPTIONAL
|
|
IN LPCWSTR szNewSubnetMask OPTIONAL
|
|
)
|
|
//
|
|
// NULL, NULL: clear all network addresses
|
|
// NULL, szNew: add
|
|
// szOld, NULL: remove
|
|
// szOld, szNew: replace (or add, if old doesn't exist)
|
|
//
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
|
|
BOOL fRet;
|
|
NlbIpAddressList IpList;
|
|
fRet = IpList.Set(this->NumIpAddresses, this->pIpAddressInfo, 0);
|
|
if (fRet)
|
|
{
|
|
fRet = IpList.Modify(
|
|
szOldIpAddress,
|
|
szNewIpAddress,
|
|
szNewSubnetMask
|
|
);
|
|
}
|
|
if (fRet)
|
|
{
|
|
this->SetNetworkAddressesRaw(NULL,0);
|
|
IpList.Extract(REF this->NumIpAddresses, REF this->pIpAddressInfo);
|
|
Status = WBEM_NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
Status = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
BOOL
|
|
NLB_EXTENDED_CLUSTER_CONFIGURATION::
|
|
IsBlankDedicatedIp(
|
|
VOID
|
|
) const
|
|
//
|
|
// Dedicated IP is either the empty string or all zeros.
|
|
//
|
|
{
|
|
return (NlbParams.ded_ip_addr[0]==0)
|
|
|| (_wcsspnp(NlbParams.ded_ip_addr, L".0")==NULL);
|
|
}
|
|
|
|
const NLB_IP_ADDRESS_INFO *
|
|
NlbIpAddressList::Find(
|
|
LPCWSTR szIp // IF NULL, returns first address
|
|
) const
|
|
//
|
|
// Looks for the specified IP address -- returns an internal pointer
|
|
// to the found IP address info, if fount, otherwise NULL.
|
|
//
|
|
{
|
|
const NLB_IP_ADDRESS_INFO *pInfo = NULL;
|
|
|
|
if (szIp == NULL)
|
|
{
|
|
//
|
|
// return the first if there is one, else NULL.
|
|
//
|
|
if (m_uNum != 0)
|
|
{
|
|
pInfo = m_pIpInfo;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pInfo = find_ip_in_ipinfo(szIp, m_pIpInfo, m_uNum);
|
|
}
|
|
|
|
return pInfo;
|
|
}
|
|
|
|
BOOL
|
|
NlbIpAddressList::Copy(const NlbIpAddressList &refList)
|
|
{
|
|
BOOL fRet;
|
|
|
|
fRet = this->Set(refList.m_uNum, refList.m_pIpInfo, 0);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
NlbIpAddressList::Validate(void)
|
|
// checks that there are no dups and all valid ip/subnets
|
|
{
|
|
BOOL fRet = FALSE;
|
|
NLB_IP_ADDRESS_INFO *pInfo = m_pIpInfo;
|
|
UINT uNum = m_uNum;
|
|
|
|
for (UINT u = 0; u<uNum; u++)
|
|
{
|
|
UINT uIpAddress = 0;
|
|
fRet = sfn_validate_info(REF pInfo[u], REF uIpAddress);
|
|
|
|
if (!fRet) break;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
BOOL
|
|
NlbIpAddressList::Set(
|
|
UINT uNew,
|
|
const NLB_IP_ADDRESS_INFO *pNewInfo,
|
|
UINT uExtraCount
|
|
)
|
|
/*
|
|
Sets internal list to a copy of pNewInfo. Reallocates list if required.
|
|
Reserves uExtraCount empty locations (perhaps more if it kept the old
|
|
internal list)
|
|
*/
|
|
{
|
|
BOOL fRet = FALSE;
|
|
UINT uMax = uNew+uExtraCount;
|
|
NLB_IP_ADDRESS_INFO *pInfo = NULL;
|
|
|
|
// printf("-> set(%lu, %p, %lu): m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n",
|
|
// uNew, pNewInfo, uExtraCount,
|
|
// m_uNum, m_uMax, m_pIpInfo);
|
|
|
|
if (uMax > m_uMax)
|
|
{
|
|
//
|
|
// We'll re-allocate to get more space.
|
|
//
|
|
pInfo = new NLB_IP_ADDRESS_INFO[uMax];
|
|
if (pInfo == NULL)
|
|
{
|
|
TRACE_CRIT("%!FUNC! allocation failure");
|
|
goto end;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The current m_pIpInfo is large enough; we'll keep it.
|
|
//
|
|
pInfo = m_pIpInfo;
|
|
uMax = m_uMax;
|
|
}
|
|
|
|
if (uNew != 0)
|
|
{
|
|
if (pNewInfo == pInfo)
|
|
{
|
|
// Caller has passed m_pInfo as pNewInfo.
|
|
// No need to copy.
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// MoveMemory can deal with overlapping regions.
|
|
//
|
|
MoveMemory(pInfo, pNewInfo, sizeof(NLB_IP_ADDRESS_INFO)*uNew);
|
|
}
|
|
}
|
|
|
|
if (uMax > uNew)
|
|
{
|
|
//
|
|
// Zero out the empty space.
|
|
//
|
|
ZeroMemory(pInfo+uNew, sizeof(NLB_IP_ADDRESS_INFO)*(uMax-uNew));
|
|
}
|
|
m_uNum = uNew;
|
|
m_uMax = uMax;
|
|
if (m_pIpInfo != pInfo)
|
|
{
|
|
delete[] m_pIpInfo;
|
|
m_pIpInfo = pInfo;
|
|
}
|
|
fRet = TRUE;
|
|
|
|
end:
|
|
|
|
// printf("<- set: fRet=%lu, m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n",
|
|
// fRet, m_uNum, m_uMax, m_pIpInfo);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
VOID
|
|
NlbIpAddressList::Extract(UINT &uNum, NLB_IP_ADDRESS_INFO * &pNewInfo)
|
|
/*
|
|
Sets pNewInfo to the ip list (not a copy) and sets the internal list to
|
|
null. Free using delete[].
|
|
*/
|
|
{
|
|
uNum = m_uNum;
|
|
pNewInfo = m_pIpInfo;
|
|
m_uNum=0;
|
|
m_uMax=0;
|
|
m_pIpInfo = NULL;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
uint_to_szipaddr(
|
|
UINT uIpAddress, // Ip address or subnet -- no validation, network order
|
|
UINT cchLen, // length of rgAddress, incluing space for NULL
|
|
WCHAR *rgAddress // Expected to be at least 17 chars long
|
|
)
|
|
{
|
|
BYTE *pb = (BYTE*) &uIpAddress;
|
|
StringCchPrintf(rgAddress, cchLen, L"%lu.%lu.%lu.%lu", pb[0], pb[1], pb[2], pb[3]);
|
|
}
|
|
|
|
BOOL
|
|
NlbIpAddressList::Modify(
|
|
LPCWSTR szOldIp,
|
|
LPCWSTR szNewIp,
|
|
LPCWSTR szNewSubnet
|
|
)
|
|
//
|
|
// NULL, NULL, -: clear all network addresses
|
|
// NULL, szNew, -: add
|
|
// szOld, NULL, -: remove
|
|
// szOld, szNew, -: remove szOld if found; add or replace szNew.
|
|
//
|
|
{
|
|
WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
|
|
BOOL fRet = FALSE;
|
|
UINT uFoundOldOffset = 0;
|
|
BOOL fFoundOldAddress = FALSE;
|
|
|
|
// printf("-> modify: m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n",
|
|
// m_uNum, m_uMax, m_pIpInfo);
|
|
|
|
if (szOldIp==NULL && szNewIp==NULL)
|
|
{
|
|
this->Clear();
|
|
fRet = TRUE;
|
|
goto end;
|
|
}
|
|
|
|
if (szOldIp != NULL && szNewIp != NULL)
|
|
{
|
|
//
|
|
// Both szOld and szNew are specified.
|
|
// We'll first call ourselves recursively to remove szNewIp, if
|
|
// it exists. Later on below we'll replace szOldIp with szNewIp
|
|
// if szOldIp exists (i.e. at the same LOCATION of szOldIp), or
|
|
// add it to the beginning if szOldIp doesn't exist.
|
|
//
|
|
(void) this->Modify(szNewIp, NULL, NULL);
|
|
}
|
|
|
|
if (szOldIp == NULL)
|
|
{
|
|
szOldIp = szNewIp; // so we don't add dups.
|
|
}
|
|
|
|
if (szOldIp != NULL)
|
|
{
|
|
const NLB_IP_ADDRESS_INFO *pFoundInfo = NULL;
|
|
|
|
pFoundInfo = find_ip_in_ipinfo(szOldIp, m_pIpInfo, m_uNum);
|
|
if(pFoundInfo != NULL)
|
|
{
|
|
uFoundOldOffset = (ULONG) (UINT_PTR) (pFoundInfo-m_pIpInfo);
|
|
fFoundOldAddress = TRUE;
|
|
}
|
|
}
|
|
|
|
if (szNewIp == NULL)
|
|
{
|
|
//
|
|
// Remove old Ip address
|
|
//
|
|
if (!fFoundOldAddress)
|
|
{
|
|
//
|
|
// Old one not found
|
|
//
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// We bump up everything beyond this one
|
|
//
|
|
m_uNum--; // that this was at least 1 because we found the old
|
|
for (UINT u=uFoundOldOffset; u<m_uNum; u++)
|
|
{
|
|
m_pIpInfo[u] = m_pIpInfo[u+1]; // struct copy.
|
|
}
|
|
//
|
|
// Zero out the last (vacated) element.
|
|
//
|
|
ZeroMemory(&m_pIpInfo[m_uNum], sizeof(*m_pIpInfo));
|
|
}
|
|
else
|
|
{
|
|
UINT uNewIpAddress=0;
|
|
UINT uNewSubnetMask=0;
|
|
NLB_IP_ADDRESS_INFO NewIpInfo;
|
|
ZeroMemory(&NewIpInfo, sizeof(NewIpInfo));
|
|
|
|
Status = CfgUtilsValidateNetworkAddress(
|
|
szNewIp,
|
|
&uNewIpAddress,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (!FAILED(Status))
|
|
{
|
|
Status = CfgUtilsValidateNetworkAddress(
|
|
szNewSubnet,
|
|
&uNewSubnetMask,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if (FAILED(Status))
|
|
{
|
|
//
|
|
// Invalid ip address.
|
|
//
|
|
TRACE_CRIT("%!FUNC!:ip or subnet part too large: %ws/%ws",
|
|
szNewIp, szNewSubnet);
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Convert into the IP_ADDRESS_INFO format.
|
|
// Here we also convert to standard dotted notation.
|
|
//
|
|
uint_to_szipaddr(uNewIpAddress, ASIZE(NewIpInfo.IpAddress), NewIpInfo.IpAddress);
|
|
uint_to_szipaddr(uNewSubnetMask, ASIZE(NewIpInfo.SubnetMask), NewIpInfo.SubnetMask);
|
|
|
|
if (fFoundOldAddress == TRUE)
|
|
{
|
|
//
|
|
// Replace the old one.
|
|
//
|
|
m_pIpInfo[uFoundOldOffset] = NewIpInfo; // struct copy.
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Well add the new ip info to the head of the list.
|
|
//
|
|
|
|
if (m_uNum == m_uMax)
|
|
{
|
|
//
|
|
// We need to allocate more space.
|
|
// We somewhat arbitrarily reserve 2 spots
|
|
// NOTE: this will cause a change in the value of
|
|
// m_pIpInfo, m_uNum and m_uMax.
|
|
//
|
|
fRet = this->Set(m_uNum, m_pIpInfo, 2);
|
|
if (!fRet)
|
|
{
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Move existing stuff one place down, to make place for the
|
|
// new one.
|
|
//
|
|
if (m_uNum >= m_uMax)
|
|
{
|
|
// Ahem, should never get here because we just added
|
|
// two extra spaces above.
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
if (m_uNum)
|
|
{
|
|
// Note the regions overlap -- MoveMemory can handle this.
|
|
//
|
|
MoveMemory(m_pIpInfo+1, m_pIpInfo, m_uNum*sizeof(*m_pIpInfo));
|
|
}
|
|
//
|
|
// Add a new one -- we'll add it to the beginning.
|
|
//
|
|
m_pIpInfo[0] = NewIpInfo; // struct copy.
|
|
m_uNum++;
|
|
|
|
}
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
|
|
end:
|
|
|
|
// printf("<- modify: fRet=%lu, m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n",
|
|
// fRet, m_uNum, m_uMax, m_pIpInfo);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
BOOL
|
|
NlbIpAddressList::sfn_validate_info(
|
|
const NLB_IP_ADDRESS_INFO &Info,
|
|
UINT &uIpAddress
|
|
)
|
|
{
|
|
WBEMSTATUS Status;
|
|
UINT uSubnetMask = 0;
|
|
|
|
Status = CfgUtilsValidateNetworkAddress(
|
|
Info.IpAddress,
|
|
&uIpAddress,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (!FAILED(Status))
|
|
{
|
|
Status = CfgUtilsValidateNetworkAddress(
|
|
Info.SubnetMask,
|
|
&uSubnetMask,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
return (!FAILED(Status));
|
|
}
|
|
|
|
|
|
UINT *
|
|
ipaddresses_from_ipaddressinfo(
|
|
const NLB_IP_ADDRESS_INFO *pInfo,
|
|
UINT NumAddresses
|
|
)
|
|
/*
|
|
Free return value using "delete" operator.
|
|
*/
|
|
{
|
|
UINT *rgOut = NULL;
|
|
|
|
if (NumAddresses == 0) goto end;
|
|
|
|
//
|
|
// Allocate space.
|
|
//
|
|
rgOut = new UINT[NumAddresses];
|
|
|
|
if (rgOut==NULL) goto end;
|
|
|
|
//
|
|
// Validate each address, thereby getting the ip address info.
|
|
//
|
|
for (UINT *pOut = rgOut; NumAddresses--; pOut++, pInfo++)
|
|
{
|
|
WBEMSTATUS wStat;
|
|
wStat = CfgUtilsValidateNetworkAddress(
|
|
pInfo->IpAddress,
|
|
pOut,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (FAILED(wStat))
|
|
{
|
|
TRACE_CRIT("%!FUNC! -- Validate address \"%ws\" failed!\n",
|
|
pInfo->IpAddress);
|
|
delete[] rgOut;
|
|
rgOut = NULL;
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
end:
|
|
|
|
return rgOut;
|
|
}
|
|
|
|
BOOL
|
|
NlbIpAddressList::Apply(UINT NumNew, const NLB_IP_ADDRESS_INFO *pNewInfo)
|
|
/*
|
|
Set our internal list to be a permutation of the ip addresses in pInfo.
|
|
The permutation attempts to minimize the differences between the
|
|
new and the current version: basically the relative order of any adresses
|
|
that remain in new is preserved, and any new addresses are tacked on at
|
|
the end.
|
|
*/
|
|
{
|
|
BOOL fRet = FALSE;
|
|
UINT *rgOldIps = NULL;
|
|
UINT *rgNewIps = NULL;
|
|
NLB_IP_ADDRESS_INFO *rgNewInfo = NULL;
|
|
UINT NumFilled = 0;
|
|
UINT NumOld = m_uNum;
|
|
|
|
|
|
if (NumNew == 0)
|
|
{
|
|
this->Clear();
|
|
fRet = TRUE;
|
|
goto end;
|
|
}
|
|
|
|
if (NumOld!=0)
|
|
{
|
|
rgOldIps = ipaddresses_from_ipaddressinfo(
|
|
m_pIpInfo,
|
|
m_uNum
|
|
);
|
|
|
|
if (rgOldIps == NULL) goto end;
|
|
}
|
|
|
|
rgNewIps = ipaddresses_from_ipaddressinfo(
|
|
pNewInfo,
|
|
NumNew
|
|
);
|
|
|
|
if (rgNewIps==NULL) goto end;
|
|
|
|
rgNewInfo = new NLB_IP_ADDRESS_INFO[NumNew];
|
|
if (rgNewInfo == NULL)
|
|
{
|
|
TRACE_CRIT("%!FUNC! allocation failure!");
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// We try to preserve our current order of IP addresses
|
|
// as far as possible. To do this, we go through each ip address
|
|
// in our list in order -- if we find it in the new list, we
|
|
// add it to our new copy -- thereby preserving the order of all
|
|
// old IP addresses that are still present in the new list.
|
|
//
|
|
{
|
|
|
|
for (UINT uOld = 0; uOld < NumOld; uOld++)
|
|
{
|
|
UINT uOldIp = rgOldIps[uOld];
|
|
|
|
//
|
|
// See if it exists in new version -- if so add to new
|
|
//
|
|
for (UINT uNew=0; uNew<NumNew; uNew++)
|
|
{
|
|
if (uOldIp == rgNewIps[uNew])
|
|
{
|
|
// yes it's still present, keep it.
|
|
if (NumFilled<NumNew)
|
|
{
|
|
rgNewInfo[NumFilled]
|
|
= pNewInfo[uNew]; // struct copy
|
|
NumFilled++;
|
|
rgNewIps[uNew] = 0; // we use this later.
|
|
}
|
|
else
|
|
{
|
|
TRACE_CRIT("%!FUNC! Out of new addresses!");
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Now tack on any cluster IP addresses not already added on.
|
|
//
|
|
{
|
|
//
|
|
// See if it exists in cluster version -- if so add to new
|
|
//
|
|
for (UINT uNew=0; uNew<NumNew; uNew++)
|
|
{
|
|
if (rgNewIps[uNew] != 0)
|
|
{
|
|
//
|
|
// yes it's a new cluster IP -- add it...
|
|
// (remember we set rgClusterIps[uCluster] to zero
|
|
// in the previous block, if we copied it over.
|
|
//
|
|
if (NumFilled<NumNew)
|
|
{
|
|
rgNewInfo[NumFilled]
|
|
= pNewInfo[uNew]; // struct copy
|
|
NumFilled++;
|
|
}
|
|
else
|
|
{
|
|
TRACE_CRIT("%!FUNC! Out of new addresses!");
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// At this point, we should have filled up all of the allocated space.
|
|
//
|
|
if (NumFilled != NumNew)
|
|
{
|
|
TRACE_CRIT("%!FUNC! NumNewAddressesFilled != NumNewAddresses!");
|
|
fRet = FALSE;
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Now update our internal list.
|
|
//
|
|
delete[] m_pIpInfo;
|
|
m_pIpInfo = rgNewInfo;
|
|
m_uNum = m_uMax = NumNew;
|
|
rgNewInfo = NULL; // so it doesn't get deleted below.
|
|
|
|
fRet = TRUE;
|
|
|
|
end:
|
|
|
|
delete[] rgOldIps;
|
|
delete[] rgNewIps;
|
|
delete[] rgNewInfo;
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
const NLB_IP_ADDRESS_INFO *
|
|
find_ip_in_ipinfo(
|
|
LPCWSTR szIpToFind,
|
|
const NLB_IP_ADDRESS_INFO *pIpInfo,
|
|
UINT NumIpInfos
|
|
)
|
|
{
|
|
|
|
UINT uIpAddressToFind = 0;
|
|
UINT uIpAddress=0;
|
|
const NLB_IP_ADDRESS_INFO *pInfo = NULL;
|
|
WBEMSTATUS Status;
|
|
|
|
Status = CfgUtilsValidateNetworkAddress(
|
|
szIpToFind,
|
|
&uIpAddressToFind,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (Status == WBEM_NO_ERROR)
|
|
{
|
|
// Find location of old network address
|
|
for (UINT u=0; u<NumIpInfos; u++)
|
|
{
|
|
Status = CfgUtilsValidateNetworkAddress(
|
|
pIpInfo[u].IpAddress,
|
|
&uIpAddress,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (Status == WBEM_NO_ERROR)
|
|
{
|
|
if (uIpAddressToFind == uIpAddress)
|
|
{
|
|
// found it.
|
|
pInfo = &pIpInfo[u];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return pInfo;
|
|
}
|