Leaked source code of windows server 2003
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.
 
 
 
 
 
 

950 lines
26 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996.
//
// File: mach.cxx
//
// Contents:
// Machine naming helper objects
//
// History:
//--------------------------------------------------------------------------
#include "act.hxx"
#include <mach.hxx>
#include <misc.hxx>
// Singleton instance:
CMachineName gMachineName;
// Defn of global ptr external parties use:
CMachineName * gpMachineName = &gMachineName;
CIPAddrs::CIPAddrs() :
_lRefs(1), // constructed with non-zero refcount!
_pIPAddresses(NULL)
{
}
CIPAddrs::~CIPAddrs()
{
ASSERT(_lRefs == 0);
if (_pIPAddresses)
{
PrivMemFree(_pIPAddresses);
}
}
void CIPAddrs::IncRefCount()
{
InterlockedIncrement(&_lRefs);
}
void CIPAddrs::DecRefCount()
{
LONG lRefs = InterlockedDecrement(&_lRefs);
if (lRefs == 0)
{
delete this;
}
}
const DWORD MAX_IPV4_STRING_BUF = ((INET_ADDRSTRLEN+1) * sizeof(WCHAR));
const DWORD MAX_IPV6_STRING_BUF = ((INET6_ADDRSTRLEN+1) * sizeof(WCHAR));
CMachineName::CMachineName()
{
_pIPAddresses = NULL;
_pwszNetBiosName = NULL;
_pwszDNSName = NULL;
_bIPV4AddrsChanged = TRUE;
_bIPV6AddrsChanged = TRUE;
_bInitialized = FALSE;
InitAQD(&_aqdIPV4, AF_INET);
InitAQD(&_aqdIPV6, AF_INET6);
ZeroMemory(&_csMachineNameLock, sizeof(CRITICAL_SECTION));
}
void
CMachineName::InitAQD(
ADDRESS_QUERY_DATA* paqd,
int addrfamily)
{
ASSERT(paqd);
ZeroMemory(paqd, sizeof(ADDRESS_QUERY_DATA));
paqd->dwSig = ADDRQUERYDATA_SIG;
paqd->socket = INVALID_SOCKET;
paqd->addrfamily = addrfamily;
if (addrfamily == AF_INET)
{
paqd->pfnIsGlobalAddress = CMachineName::IsIPV4AddressGlobal;
paqd->dwMaxAddrStringBufSize = MAX_IPV4_STRING_BUF;
}
else if (addrfamily == AF_INET6)
{
paqd->pfnIsGlobalAddress = CMachineName::IsIPV6AddressGlobal;
paqd->dwMaxAddrStringBufSize = MAX_IPV6_STRING_BUF;
}
else
{
ASSERT(0);
}
}
CMachineName::~CMachineName()
{
// CODEWORK: This object does not cleanup its resources. This
// could be fixed, but is pointless at the present time since the
// object lives for the life of the RPCSS svchost, which lives for
// the life of the machine boot.
}
BOOL CMachineName::Initialize()
{
NTSTATUS status;
// Initialize lock
status = RtlInitializeCriticalSection(&_csMachineNameLock);
_bInitialized = NT_SUCCESS(status);
return _bInitialized;
}
void
CMachineName::IPAddrsChanged(int addrfamily)
{
ASSERT(_bInitialized);
switch (addrfamily)
{
case AF_INET:
// IPV4 addresses changed
_bIPV4AddrsChanged = TRUE;
break;
case AF_INET6:
// IPV6 addresses changed
ASSERT(gAddrRefreshMgr.IsIPV6Installed() == TRUE);
_bIPV6AddrsChanged = TRUE;
break;
default:
ASSERT(0 && "Address change signalled on unknown addr family");
return;
}
return;
}
BOOL
CMachineName::Compare( IN WCHAR * pwszName )
{
CIPAddrs* pIPAddrs = NULL;
ASSERT(_bInitialized);
if (!pwszName)
return FALSE;
// Okay to check hard-coded names first (they never change)
if (CompareHardCodedLocalHostNames(pwszName))
return TRUE;
// Get netbios name if we haven't done so already:
if (!_pwszNetBiosName)
{
SetNetBIOSName();
}
if (_pwszNetBiosName && !lstrcmpiW(pwszName, _pwszNetBiosName))
return TRUE;
// Don't go any farther unless we're actually using TCP
if (!gAddrRefreshMgr.ListenedOnTCP())
return FALSE;
// Get DNS name if we haven't done so already.
if (! _pwszDNSName)
{
SetDNSName();
}
if (_pwszDNSName && !lstrcmpiW(pwszName, _pwszDNSName))
return TRUE;
// review: there are other names we could be checking for here, see docs
// on GetComputerNameEx. Need to be wary of cluster names though.
pIPAddrs = GetIPAddrs();
if (pIPAddrs)
{
NetworkAddressVector* pNetworkAddrVector = pIPAddrs->_pIPAddresses;
for ( DWORD n = 0; n < pNetworkAddrVector->Count; n++ )
{
if (!lstrcmpiW(pwszName, pNetworkAddrVector->NetworkAddresses[n]))
{
pIPAddrs->DecRefCount();
return TRUE;
}
}
pIPAddrs->DecRefCount();
}
// We do this last because a side-effect of calling GetIPAddrs is that it will
// populate the list of IPV4 & IPV6 localhost names, if any.
if (CompareDynamicLocalHostNames(pwszName))
return TRUE;
return FALSE;
}
//
// CMachineName::GetIPAddrs()
//
// Returns a pointer to a refcounted CIPAddrs for this
// machine. If we don't yet have a non-localhost ip,
// then we keep trying to get one.
//
CIPAddrs*
CMachineName::GetIPAddrs()
{
ASSERT(_bInitialized);
CMutexLock lock(&_csMachineNameLock);
// should we call gAddrRefreshMgr.ListenedOnTCP() here
// and simply return an empty vector if so?
// If anything changed, or if we don't have any
// addresses at all, go query for the current stuff
if (_bIPV4AddrsChanged ||
_bIPV6AddrsChanged ||
!_pIPAddresses)
{
// Release old addresses, if any
if (_pIPAddresses)
{
_pIPAddresses->DecRefCount();
_pIPAddresses = NULL;
}
_pIPAddresses = QueryAddresses();
if (!_pIPAddresses)
return NULL;
}
ASSERT(_pIPAddresses);
_pIPAddresses->IncRefCount();
return _pIPAddresses;
}
WCHAR*
CMachineName::NetBiosName()
{
ASSERT(_bInitialized);
if (!_pwszNetBiosName)
{
SetNetBIOSName();
}
return _pwszNetBiosName;
}
WCHAR*
CMachineName::DNSName()
{
ASSERT(_bInitialized);
if (!_pwszDNSName)
{
SetDNSName();
}
return _pwszDNSName;
}
CIPAddrs*
CMachineName::QueryAddresses()
{
// Assumes we hold _csMachineNameLock
// If necessary free old ipv4 addresses and requery
if (_bIPV4AddrsChanged)
{
_bIPV4AddrsChanged = FALSE;
BOOL fRet = QueryAddressesSpecific(&_aqdIPV4);
if (!fRet)
{
// If something went wrong, just keep going. The only thing
// we could do here is refuse to supply bindings. If we keep
// going though, the worst thing that could occur (IMHO) is
// that the bindings might only contain a DNS name. Better
// to degrade gracefully than refuse service altogether.
}
}
// If necessary free old ipv6 addresses and requery
if (_bIPV6AddrsChanged && gAddrRefreshMgr.IsIPV6Installed())
{
_bIPV6AddrsChanged = FALSE;
BOOL fRet = QueryAddressesSpecific(&_aqdIPV6);
if (!fRet)
{
// If something went wrong, just keep going. The only thing
// we could do here is refuse to supply bindings. If we keep
// going though, the worst thing that could occur (IMHO) is
// that the bindings might only contain a DNS name. Better
// to degrade gracefully than refuse service altogether.
}
}
// We now have the current IPV4 + IPV6 addresses, now
// just merge them.
CIPAddrs* pIPAddrs = MergeAddresses();
if (!pIPAddrs)
return NULL;
return pIPAddrs;
}
CIPAddrs*
CMachineName::MergeAddresses()
{
DWORD dwCurrentAddress = 0;
DWORD dwTotalAddresses = 0;
CIPAddrs* pIPAddrs = NULL;
NetworkAddressVector* pVector = NULL;
DWORD dwTotalVectorStorageNeeded = 0;
// Assumes we hold _csMachineNameLock
// Allocate new wrapper object
pIPAddrs = new CIPAddrs();
if (!pIPAddrs)
return NULL;
// Figure out how many addresses we have
if (_aqdIPV4.pAddresses)
{
dwTotalAddresses += _aqdIPV4.pAddresses->Count;
}
if (_aqdIPV6.pAddresses)
{
dwTotalAddresses += _aqdIPV6.pAddresses->Count;
}
//
// Handle case with zero addresses
//
if (dwTotalAddresses == 0)
{
// Allocate an empty vector
pVector = (NetworkAddressVector*)PrivMemAlloc(sizeof(NetworkAddressVector));
if (pVector)
{
pVector->Count = 0;
pVector->StringBufferSpace = 0;
pVector->NetworkAddresses = NULL;
pIPAddrs->_pIPAddresses = pVector;
}
else
{
pIPAddrs->DecRefCount();
pIPAddrs = NULL;
}
return pIPAddrs;
}
//
// Calculate total memory needed for combined vector and
// allocate it
//
dwTotalVectorStorageNeeded = sizeof(NetworkAddressVector);
dwTotalVectorStorageNeeded += (sizeof(WCHAR*) * dwTotalAddresses);
if (_aqdIPV4.pAddresses)
{
dwTotalVectorStorageNeeded += _aqdIPV4.pAddresses->StringBufferSpace;
}
if (_aqdIPV6.pAddresses)
{
dwTotalVectorStorageNeeded += _aqdIPV6.pAddresses->StringBufferSpace;
}
pVector = (NetworkAddressVector*)PrivMemAlloc(dwTotalVectorStorageNeeded);
if (!pVector)
{
pIPAddrs->DecRefCount();
pIPAddrs = NULL;
return NULL;
}
//
// Init struct and set it up for copying
//
ZeroMemory(pVector, dwTotalVectorStorageNeeded);
pVector->Count = dwTotalAddresses;
if (_aqdIPV4.pAddresses)
{
pVector->StringBufferSpace = _aqdIPV4.pAddresses->StringBufferSpace;
}
if (_aqdIPV6.pAddresses)
{
pVector->StringBufferSpace += _aqdIPV6.pAddresses->StringBufferSpace;
}
pVector->NetworkAddresses = (WCHAR**)&pVector[1];
//
// Copy addresses into the vector
//
dwCurrentAddress = 0;
WCHAR* pszCurrentAddress = (WCHAR*)(&pVector->NetworkAddresses[dwTotalAddresses]);
if (_aqdIPV4.pAddresses)
{
CopySrcVectorToTargetVector (pVector,
_aqdIPV4.pAddresses,
&dwCurrentAddress,
&pszCurrentAddress);
ASSERT(dwCurrentAddress == _aqdIPV4.pAddresses->Count);
}
if (_aqdIPV6.pAddresses)
{
CopySrcVectorToTargetVector(pVector,
_aqdIPV6.pAddresses,
&dwCurrentAddress,
&pszCurrentAddress);
}
ASSERT(dwCurrentAddress == dwTotalAddresses);
ValidateVector(pVector);
//
// Success
//
pIPAddrs->_pIPAddresses = pVector;
return pIPAddrs;
}
void
CMachineName::CopySrcVectorToTargetVector (
NetworkAddressVector* pTargetVector, // The vector to copy into
NetworkAddressVector* pSourceVector, // The vector to copy from
DWORD * pdwCurrentAddress, // On input, the index in the vector to start copying into.
WCHAR** ppszCurrentAddress) // On input, the buffer position to start copying into.
{
// Do nothing in case of an empty source vector
if (pSourceVector->Count == 0)
return;
// Copy down the [in,out] parameters for shorthand purposes.
DWORD dwCurrent = *pdwCurrentAddress;
WCHAR *pszCurrent = *ppszCurrentAddress;
for (DWORD i = 0; i < pSourceVector->Count; i++)
{
// Lay the source network address into the buffer at wszCurrent.
lstrcpy(pszCurrent, pSourceVector->NetworkAddresses[i]);
// Now set the pointer in pTargetVector to point to wszCurrent...
pTargetVector->NetworkAddresses[dwCurrent] = pszCurrent;
//
// ...and advance wszCurrent to the next free spot in the buffer.
pszCurrent += (lstrlen(pszCurrent) + 1);
dwCurrent++;
}
// Update the [in,out] params.
*pdwCurrentAddress = dwCurrent;
*ppszCurrentAddress = pszCurrent;
return;
}
BOOL
CMachineName::IsIPV4AddressGlobal(LPSOCKADDR psockaddr)
{
ASSERT(psockaddr);
// undone? what do we need to check here? do we even see localhost
// addresses from a socket query? (not usually)
//in6_addr* pin6addr = &(((sockaddr_in6*)psockaddr)->sin6_addr);
return TRUE;
}
BOOL
CMachineName::IsIPV6AddressGlobal(LPSOCKADDR psockaddr)
{
ASSERT(psockaddr);
in6_addr* pin6addr = &(((sockaddr_in6*)psockaddr)->sin6_addr);
// This macro just checks for ::1%1
if (IN6_IS_ADDR_LOOPBACK(pin6addr))
{
return FALSE;
}
// Unfortunately, the IN6_IS_ADDR_LOOPBACK macro doesn't cover all
// cases. Specifically, it doesn't work for fe80::1. Here we
// have a hard-coded check for this:
if ((pin6addr->s6_words[0] == 0x80fe) &&
(pin6addr->s6_words[1] == 0x0) &&
(pin6addr->s6_words[2] == 0x0) &&
(pin6addr->s6_words[3] == 0x0) &&
(pin6addr->s6_words[4] == 0x0) &&
(pin6addr->s6_words[5] == 0x0) &&
(pin6addr->s6_words[6] == 0x0) &&
(pin6addr->s6_words[7] == 0x0100))
{
return FALSE;
}
// No link-local addresses
if (IN6_IS_ADDR_LINKLOCAL(pin6addr))
{
return FALSE;
}
// No site local addresses.
if (IN6_IS_ADDR_SITELOCAL(pin6addr))
{
return FALSE;
}
// At this point, we have concluded that the IPV6 address in question is
// a "global" scope address, and hence is okay to put in the bindings.
return TRUE;
}
void
CMachineName::SetNetBIOSName()
{
CMutexLock lock(&_csMachineNameLock);
if (!_pwszNetBiosName)
{
SetComputerNameHelper(ComputerNamePhysicalNetBIOS, &_pwszNetBiosName);
}
}
void
CMachineName::SetDNSName()
{
CMutexLock lock(&_csMachineNameLock);
if (!_pwszDNSName)
{
SetComputerNameHelper(ComputerNamePhysicalDnsFullyQualified, &_pwszDNSName);
}
}
void
CMachineName::SetComputerNameHelper(
COMPUTER_NAME_FORMAT format,
WCHAR** ppwszName
)
{
BOOL fRet = FALSE;
DWORD dwSize = 0;
ASSERT(ppwszName);
*ppwszName = NULL;
// Get needed buffer size
fRet = GetComputerNameEx(format, NULL, &dwSize);
if (!fRet)
{
// Be resilient if failures occur, sometimes network
// apis can be flaky during machine boot (for instance)
if (GetLastError() == ERROR_MORE_DATA)
{
ASSERT(dwSize > 0);
if (dwSize == 0)
return;
WCHAR* pwszName = new WCHAR[dwSize];
if (!pwszName)
return;
// Get name for real
fRet = GetComputerNameEx(format, pwszName, &dwSize);
if (fRet)
{
// success
*ppwszName = pwszName;
}
else
{
// still failed? hmm
ASSERT(0 && "Unexpected failure from GetComputerNameEx");
delete [] pwszName;
}
}
}
return;
}
BOOL
CMachineName::CompareHardCodedLocalHostNames(WCHAR* pwszName)
{
ASSERT(pwszName);
// Some localhost aliases don't show up in socket queries.
if (!lstrcmpi(L"localhost", pwszName))
return TRUE;
if (!lstrcmpi(L"127.0.0.1", pwszName))
return TRUE;
return FALSE;
}
BOOL
CMachineName::CompareDynamicLocalHostNames(WCHAR* pwszName)
{
DWORD i;
ASSERT(pwszName);
CMutexLock lock(&_csMachineNameLock);
if (_aqdIPV4.pLocalOnlyAddresses)
{
for (i = 0; i < _aqdIPV4.pLocalOnlyAddresses->Count; i++)
{
if (!lstrcmpi(_aqdIPV4.pLocalOnlyAddresses->NetworkAddresses[i],
pwszName))
{
return TRUE;
}
}
}
if (_aqdIPV6.pLocalOnlyAddresses)
{
for (i = 0; i < _aqdIPV6.pLocalOnlyAddresses->Count; i++)
{
if (!lstrcmpi(_aqdIPV6.pLocalOnlyAddresses->NetworkAddresses[i],
pwszName))
{
return TRUE;
}
}
}
return FALSE;
}
BOOL
CMachineName::QueryAddressesSpecific(ADDRESS_QUERY_DATA* paqd)
/*++
Routine Description:
Retrieves a SOCKET_ADDRESS_LIST containing addresses supported by this
machine for the specified address family (ipv4 or ipv6) and stores
it in either _pIPV4Addrs or _pIPV6Addrs.
Arguments:
paqd - structure containing data with which to query addresses on
Return Value:
TRUE -- valid results are stored in paqd
FALSE -- error occurred. One or both of paqd->pAddresses and
paqd->pLocalAddresses may be NULL.
--*/
{
int ret;
BOOL fReturn = TRUE;
DWORD dwBytesReturned;
DWORD i;
SOCKET* pSocket = NULL;
SOCKET_ADDRESS_LIST** ppSocketAddrList = NULL;
DWORD* pdwSocketAddrBufferSize = NULL;
ASSERT(paqd->dwSig == ADDRQUERYDATA_SIG);
// Allocate socket if we haven't already
if (paqd->socket == INVALID_SOCKET)
{
paqd->socket = WSASocket(paqd->addrfamily,
SOCK_STREAM,
IPPROTO_TCP,
NULL,
0,
0
);
if (paqd->socket == INVALID_SOCKET)
return NULL;
// else we got a socket for this addrfamily, which we keep forever.
}
while (TRUE)
{
ret = WSAIoctl(paqd->socket,
SIO_ADDRESS_LIST_QUERY,
NULL,
0,
(BYTE*)paqd->pSockAddrList,
paqd->dwSockAddrListBufferSize,
&dwBytesReturned,
NULL,
NULL);
paqd->dwTotalTimesQueried++;
if (ret == 0)
{
// Success
break;
}
else
{
// Failed. If need bigger buffer, allocate it
// and try again. Otherwise fail.
if (WSAGetLastError() == WSAEFAULT)
{
ASSERT(dwBytesReturned > paqd->dwSockAddrListBufferSize);
if (paqd->pSockAddrList)
{
ASSERT(paqd->dwSockAddrListBufferSize > 0);
PrivMemFree(paqd->pSockAddrList);
paqd->pSockAddrList = NULL;
paqd->dwSockAddrListBufferSize = 0;
}
else
{
ASSERT(paqd->dwSockAddrListBufferSize == 0);
}
paqd->pSockAddrList = (SOCKET_ADDRESS_LIST*)PrivMemAlloc(dwBytesReturned);
if (!(paqd->pSockAddrList))
{
fReturn = FALSE;
break;
}
paqd->dwSockAddrListBufferSize = dwBytesReturned;
}
else
{
// some other error
fReturn = FALSE;
break;
}
}
}
if (fReturn)
{
// Build local-only vector
if (!BuildVector(paqd, FALSE))
fReturn = FALSE;
// Build non-local-only vector
if (!BuildVector(paqd, TRUE))
fReturn = FALSE;
}
else
{
// if we failed above before calling BuildVector, then we need to
// free and NULL pAddresses & pLocalAddresses so that downstream
// code doesn't assume that they are pointing to valid contents.
PrivMemFree(paqd->pAddresses);
paqd->pAddresses = NULL;
paqd->dwAddrVectorSize = 0;
PrivMemFree(paqd->pLocalOnlyAddresses);
paqd->pLocalOnlyAddresses = NULL;
paqd->dwLocalAddrVectorSize = 0;
}
return fReturn;
}
BOOL
CMachineName::BuildVector(ADDRESS_QUERY_DATA* paqd, BOOL fLocalOnly)
{
int i = 0;
DWORD* pdwVectorSize = NULL;
NetworkAddressVector** ppVector = NULL;
DWORD dwTotalAddrs = 0;
BOOL fIsGlobalAddress;
ASSERT(paqd->dwSig == ADDRQUERYDATA_SIG);
//
// Sum up how many addresses of the non-local or local-only type there
// are, so we know how much memory to allocate.
//
for (i = 0; i < paqd->pSockAddrList->iAddressCount; i++)
{
fIsGlobalAddress = (!paqd->pfnIsGlobalAddress ||
paqd->pfnIsGlobalAddress(paqd->pSockAddrList->Address[i].lpSockaddr));
if ((fIsGlobalAddress && !fLocalOnly) || (!fIsGlobalAddress && fLocalOnly))
{
dwTotalAddrs++;
}
}
if (fLocalOnly)
{
pdwVectorSize = &paqd->dwLocalAddrVectorSize;
ppVector = &paqd->pLocalOnlyAddresses;
}
else
{
pdwVectorSize = &paqd->dwAddrVectorSize;
ppVector = &paqd->pAddresses;
}
//
// Build a vector of the specified addresses
//
DWORD dwBufSizeNeeded;
//
// Figure out how much space we need. See comment below (right above call
// to WSAAddressToString) regarding string buffer space required per address.
//
dwBufSizeNeeded = sizeof(NetworkAddressVector) +
(dwTotalAddrs * sizeof(WCHAR*)) +
(dwTotalAddrs * paqd->dwMaxAddrStringBufSize);
// Figure out if we can use the old vector buffer, or allocate a new one
if (*pdwVectorSize < dwBufSizeNeeded)
{
ASSERT((*pdwVectorSize > 0) ? (*ppVector != NULL) : (*ppVector == NULL));
PrivMemFree(*ppVector);
*pdwVectorSize = 0;
*ppVector = (NetworkAddressVector*)PrivMemAlloc(dwBufSizeNeeded);
if (!(*ppVector))
return FALSE;
*pdwVectorSize = dwBufSizeNeeded;
}
// Zero the buffer
ASSERT(*ppVector);
ZeroMemory(*ppVector, *pdwVectorSize);
// Fill in the vector
if (dwTotalAddrs > 0)
{
NetworkAddressVector* pVector = *ppVector;
pVector->Count = dwTotalAddrs;
pVector->StringBufferSpace = (dwTotalAddrs * paqd->dwMaxAddrStringBufSize);
pVector->NetworkAddresses = (WCHAR**)&pVector[1];
DWORD dwCurrentVectorAddress = 0;
WCHAR* pszNextAddress = (WCHAR*)&pVector->NetworkAddresses[dwTotalAddrs];
for (i = 0;
(i < paqd->pSockAddrList->iAddressCount) && (dwCurrentVectorAddress < dwTotalAddrs);
i++)
{
BOOL fUseCurrentAddress;
// Re-calculate if the current address in the sockaddrlist is going to
// be put into the vector.
fIsGlobalAddress = (!(paqd->pfnIsGlobalAddress) ||
paqd->pfnIsGlobalAddress(paqd->pSockAddrList->Address[i].lpSockaddr));
fUseCurrentAddress = (fIsGlobalAddress && !fLocalOnly) || (!fIsGlobalAddress && fLocalOnly);
if (fUseCurrentAddress)
{
int ret;
DWORD dwAddrBufLen;
dwAddrBufLen = paqd->dwMaxAddrStringBufSize;
// Note that we are being slightly sloppy here. In theory we could be
// callling WSAAddressToString with a zero-size output buffer, and WSATS
// would come back with an error and the exact required size of the buffer;
// We could then do this across all addresses going into the vector. However,
// there are some network stack bugs that don't let this work for every
// address type (ie, ipv6). Hence, we play it safe and allocate a "maximum"
// buffer space for every address.
ret = WSAAddressToString(paqd->pSockAddrList->Address[i].lpSockaddr,
paqd->pSockAddrList->Address[i].iSockaddrLength,
NULL,
pszNextAddress,
&dwAddrBufLen);
if (ret != 0)
{
// An error occurred. We don't expect "insufficient buffer" here, and other
// errors are not something we can recover from. Cleanup and return NULL.
PrivMemFree(*ppVector);
*ppVector = NULL;
*pdwVectorSize = 0;
return FALSE;
}
else
{
ASSERT(dwAddrBufLen <= paqd->dwMaxAddrStringBufSize);
ASSERT((((DWORD)lstrlenW(pszNextAddress) + 1) * sizeof(WCHAR)) <= paqd->dwMaxAddrStringBufSize);
// Write in address of just copied string
pVector->NetworkAddresses[dwCurrentVectorAddress] = pszNextAddress;
// Advance pointers to next free spot in the buffer
dwCurrentVectorAddress++;
pszNextAddress += (lstrlen(pszNextAddress) + 1);
}
}
// else skip this address
}
ASSERT(dwCurrentVectorAddress == dwTotalAddrs);
}
else
{
// Zero addresses and the vector is already "empty" (it was
// zeroed out above). So nothing to do.
}
ValidateVector(*ppVector);
return TRUE;
}
void
CMachineName::ValidateVector(NetworkAddressVector* pVector)
{
#ifdef DBG
ASSERT(pVector);
if (pVector->Count > 0)
{
ASSERT(pVector->StringBufferSpace > 0);
ASSERT(pVector->NetworkAddresses != NULL);
DWORD i;
DWORD cchTotalStringSpace = 0;
for (i = 0; i < pVector->Count; i++)
{
BYTE* pStart = (BYTE*)&pVector->NetworkAddresses[pVector->Count];
BYTE* pEnd = pStart + pVector->StringBufferSpace;
ASSERT((BYTE*)pVector->NetworkAddresses[i] >= pStart);
ASSERT((BYTE*)pVector->NetworkAddresses[i] < pEnd);
cchTotalStringSpace += (lstrlenW(pVector->NetworkAddresses[i]) + 1);
}
ASSERT((cchTotalStringSpace * sizeof(WCHAR)) <= pVector->StringBufferSpace);
}
else
{
ASSERT(pVector->StringBufferSpace == 0);
ASSERT(pVector->NetworkAddresses == NULL);
}
#endif
}