472 lines
11 KiB
C++
472 lines
11 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
CMachineName::CMachineName()
|
||
|
{
|
||
|
_socket = INVALID_SOCKET;
|
||
|
_pAddrQueryBuf = NULL;
|
||
|
_dwAddrQueryBufSize = 0;
|
||
|
_bIPAddrsChanged = FALSE;
|
||
|
_dwcResets = 0;
|
||
|
_wszMachineName[0] = 0;
|
||
|
_bInitialized = FALSE;
|
||
|
_pwszDNSName = 0;
|
||
|
_pIPAddresses = 0;
|
||
|
_pAliases = NULL;
|
||
|
|
||
|
NTSTATUS status;
|
||
|
|
||
|
// Initialize lock
|
||
|
status = RtlInitializeCriticalSection(&_csMachineNameLock);
|
||
|
_bInitialized = NT_SUCCESS(status);
|
||
|
}
|
||
|
|
||
|
DWORD CMachineName::Initialize()
|
||
|
{
|
||
|
NTSTATUS status = NO_ERROR;
|
||
|
|
||
|
ASSERT(gpClientLock->HeldExclusive());
|
||
|
|
||
|
// Get computer name if we haven't done so already:
|
||
|
if (!_wszMachineName[0])
|
||
|
{
|
||
|
SetName();
|
||
|
}
|
||
|
|
||
|
// Get DNS name if we haven't done so already. Note that we
|
||
|
// currently have no way of knowing when the DNS name changes
|
||
|
// (unlike IP address changes), so it is left alone once set.
|
||
|
if (!_pwszDNSName)
|
||
|
{
|
||
|
SetDNSName();
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
CMachineName::Compare( IN WCHAR * pwszName )
|
||
|
{
|
||
|
CIPAddrs* pIPAddrs = NULL;
|
||
|
|
||
|
ASSERT(_bInitialized);
|
||
|
|
||
|
if ( lstrcmpiW( pwszName, _wszMachineName ) == 0 )
|
||
|
return TRUE;
|
||
|
|
||
|
if ( lstrcmpiW( pwszName, L"localhost" ) == 0 )
|
||
|
return TRUE;
|
||
|
|
||
|
if ( lstrcmpiW( pwszName, L"127.0.0.1" ) == 0 )
|
||
|
return TRUE;
|
||
|
|
||
|
if (! _pwszDNSName )
|
||
|
SetDNSName();
|
||
|
|
||
|
if ( _pwszDNSName && lstrcmpiW( pwszName, _pwszDNSName ) == 0 )
|
||
|
return TRUE;
|
||
|
|
||
|
pIPAddrs = GetIPAddrs();
|
||
|
if (pIPAddrs)
|
||
|
{
|
||
|
NetworkAddressVector* pNetworkAddrVector = pIPAddrs->_pIPAddresses;
|
||
|
for ( DWORD n = 0; n < pNetworkAddrVector->Count; n++ )
|
||
|
{
|
||
|
if ( lstrcmpiW( pwszName, pNetworkAddrVector->NetworkAddresses[n] ) == 0 )
|
||
|
{
|
||
|
pIPAddrs->DecRefCount();
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
pIPAddrs->DecRefCount();
|
||
|
}
|
||
|
|
||
|
if (_pAliases)
|
||
|
{
|
||
|
for (DWORD n=0; _pAliases[n]; n++)
|
||
|
{
|
||
|
if ( lstrcmpiW( pwszName, _pAliases[n] ) == 0 )
|
||
|
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);
|
||
|
|
||
|
// _bIPAddrsChanged will TRUE if we were notified of
|
||
|
// an address change
|
||
|
if (_bIPAddrsChanged || !_pIPAddresses)
|
||
|
{
|
||
|
CIPAddrs* pIPAddrs = NULL;
|
||
|
NetworkAddressVector* pNewAddrVector = NULL;
|
||
|
|
||
|
// Create a new wrapper object
|
||
|
pIPAddrs = new CIPAddrs; // refcount starts as 1
|
||
|
if (!pIPAddrs)
|
||
|
return NULL;
|
||
|
|
||
|
// Build a new IP address vector:
|
||
|
pNewAddrVector = COMMON_IP_BuildAddressVector();
|
||
|
if (!pNewAddrVector)
|
||
|
{
|
||
|
pIPAddrs->DecRefCount();
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Store the new vector in the wrapper object:
|
||
|
pIPAddrs->_pIPAddresses = pNewAddrVector;
|
||
|
|
||
|
_dwcResets++; // debug counter
|
||
|
|
||
|
// Clear dirty flag
|
||
|
_bIPAddrsChanged = FALSE;
|
||
|
|
||
|
// Release old copy
|
||
|
if (_pIPAddresses)
|
||
|
_pIPAddresses->DecRefCount();
|
||
|
|
||
|
// Update our cached copy
|
||
|
_pIPAddresses = pIPAddrs;
|
||
|
|
||
|
// Bump refcount and return
|
||
|
_pIPAddresses->IncRefCount();
|
||
|
return _pIPAddresses;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Don't need to recalculate our ip's. Just refcount the cached object and
|
||
|
// return it.
|
||
|
ASSERT(_pIPAddresses);
|
||
|
_pIPAddresses->IncRefCount();
|
||
|
return _pIPAddresses;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CMachineName::SetName()
|
||
|
{
|
||
|
DWORD Size;
|
||
|
|
||
|
Size = sizeof(_wszMachineName);
|
||
|
|
||
|
(void) GetComputerNameW( _wszMachineName, &Size );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CMachineName::SetDNSName()
|
||
|
{
|
||
|
char hostname[IPMaximumPrettyName];
|
||
|
HOSTENT * HostEnt = 0;
|
||
|
DWORD Length;
|
||
|
int Status;
|
||
|
|
||
|
if (gethostname(hostname, IPMaximumPrettyName) != 0)
|
||
|
return;
|
||
|
|
||
|
HostEnt = gethostbyname(hostname);
|
||
|
if ( ! HostEnt )
|
||
|
return;
|
||
|
|
||
|
Length = lstrlenA( HostEnt->h_name ) + 1;
|
||
|
_pwszDNSName = (WCHAR *) PrivMemAlloc( Length * sizeof(WCHAR) );
|
||
|
|
||
|
if ( ! _pwszDNSName )
|
||
|
return;
|
||
|
|
||
|
Status = MultiByteToWideChar(
|
||
|
CP_ACP,
|
||
|
0,
|
||
|
HostEnt->h_name,
|
||
|
Length,
|
||
|
_pwszDNSName,
|
||
|
Length );
|
||
|
|
||
|
if ( ! Status )
|
||
|
{
|
||
|
PrivMemFree( _pwszDNSName );
|
||
|
_pwszDNSName = 0;
|
||
|
}
|
||
|
|
||
|
SetHostAliases(HostEnt);
|
||
|
}
|
||
|
|
||
|
void CMachineName::SetHostAliases(HOSTENT *pHostEnt)
|
||
|
{
|
||
|
if (!pHostEnt->h_aliases)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// sum up the number of bytes needed for allocation
|
||
|
//
|
||
|
|
||
|
ULONG cAliases = 0;
|
||
|
ULONG cbAliases = 0;
|
||
|
while (pHostEnt->h_aliases[cAliases])
|
||
|
{
|
||
|
cbAliases += sizeof(WCHAR) * (lstrlenA(pHostEnt->h_aliases[cAliases]) + 1);
|
||
|
cAliases++;
|
||
|
}
|
||
|
|
||
|
if (cAliases == 0)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// allocate one chunk of memory
|
||
|
//
|
||
|
|
||
|
_pAliases = (WCHAR **) PrivMemAlloc(((cAliases+1) * sizeof(WCHAR*)) + cbAliases);
|
||
|
|
||
|
if (!_pAliases)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
WCHAR *pStrings = (WCHAR *) ( _pAliases + cAliases + 1 );
|
||
|
|
||
|
ULONG i;
|
||
|
|
||
|
//
|
||
|
// copy the strings
|
||
|
//
|
||
|
|
||
|
for (i=0; i<cAliases; i++)
|
||
|
{
|
||
|
MultiByteToWideChar(
|
||
|
CP_ACP,
|
||
|
0,
|
||
|
pHostEnt->h_aliases[i],
|
||
|
-1,
|
||
|
pStrings,
|
||
|
IPMaximumPrettyName
|
||
|
);
|
||
|
_pAliases[i] = pStrings;
|
||
|
|
||
|
pStrings += (wcslen(pStrings) + 1);
|
||
|
}
|
||
|
|
||
|
// null terminator
|
||
|
_pAliases[cAliases] = NULL;
|
||
|
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
NetworkAddressVector*
|
||
|
CMachineName::COMMON_IP_BuildAddressVector()
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Builds a vector of IP addresses supported by this machine.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
non-NULL -- a valid NetworkAddressVector
|
||
|
NULL - error occurred
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
int ret;
|
||
|
DWORD dwBytesReturned;
|
||
|
int i;
|
||
|
DWORD dwVectMemNeeded = 0;
|
||
|
LPSOCKET_ADDRESS_LIST pSocketAddrList = NULL;
|
||
|
NetworkAddressVector* pVector = NULL;
|
||
|
char* pszIPAddress;
|
||
|
|
||
|
// Allocate socket if we haven't already
|
||
|
if (_socket == INVALID_SOCKET)
|
||
|
{
|
||
|
_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||
|
if (_socket == INVALID_SOCKET)
|
||
|
return NULL;
|
||
|
|
||
|
// else we got a socket, which we keep forever.
|
||
|
}
|
||
|
|
||
|
while (TRUE)
|
||
|
{
|
||
|
ret = WSAIoctl(_socket,
|
||
|
SIO_ADDRESS_LIST_QUERY,
|
||
|
NULL,
|
||
|
0,
|
||
|
_pAddrQueryBuf,
|
||
|
_dwAddrQueryBufSize,
|
||
|
&dwBytesReturned,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
if (ret == 0)
|
||
|
{
|
||
|
// Success, break out and keep going
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Failed. If need bigger buffer, allocate it
|
||
|
// and try again. Otherwise fail.
|
||
|
if (WSAGetLastError() == WSAEFAULT)
|
||
|
{
|
||
|
ASSERT(dwBytesReturned > _dwAddrQueryBufSize);
|
||
|
|
||
|
delete _pAddrQueryBuf;
|
||
|
_dwAddrQueryBufSize = 0;
|
||
|
|
||
|
_pAddrQueryBuf = new BYTE[dwBytesReturned];
|
||
|
if (!_pAddrQueryBuf)
|
||
|
return NULL;
|
||
|
|
||
|
_dwAddrQueryBufSize = dwBytesReturned;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// some other error
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Okay, we now have successfully queried the socket for
|
||
|
// the latest and greatest IP addresses assigned to this
|
||
|
// machine. Now we need to allocate and fill in a
|
||
|
// NetworkAddressVector structure.
|
||
|
|
||
|
pSocketAddrList = (LPSOCKET_ADDRESS_LIST)_pAddrQueryBuf;
|
||
|
|
||
|
// Handle case with no addresses
|
||
|
if (pSocketAddrList->iAddressCount == 0)
|
||
|
{
|
||
|
// Allocate an empty vector
|
||
|
pVector = (NetworkAddressVector*)PrivMemAlloc(sizeof(NetworkAddressVector));
|
||
|
if (pVector)
|
||
|
{
|
||
|
pVector->Count = 0;
|
||
|
pVector->NetworkAddresses = NULL;
|
||
|
}
|
||
|
return pVector;
|
||
|
}
|
||
|
|
||
|
// Calculate how much memory needed
|
||
|
dwVectMemNeeded = sizeof(NetworkAddressVector) +
|
||
|
(pSocketAddrList->iAddressCount * sizeof(WCHAR*));
|
||
|
|
||
|
for (i = 0; i < pSocketAddrList->iAddressCount; i++)
|
||
|
{
|
||
|
pszIPAddress = inet_ntoa(((SOCKADDR_IN*)pSocketAddrList->Address[i].lpSockaddr)->sin_addr);
|
||
|
ASSERT(pszIPAddress);
|
||
|
|
||
|
dwVectMemNeeded += ((lstrlenA(pszIPAddress) + 1) * sizeof(WCHAR));
|
||
|
}
|
||
|
|
||
|
pVector = (NetworkAddressVector*)PrivMemAlloc(dwVectMemNeeded);
|
||
|
if (!pVector)
|
||
|
return NULL;
|
||
|
|
||
|
// Init struct
|
||
|
pVector->Count = pSocketAddrList->iAddressCount;
|
||
|
pVector->NetworkAddresses = (WCHAR**)&pVector[1];
|
||
|
pVector->NetworkAddresses[0] = (WCHAR*)&pVector->NetworkAddresses[pSocketAddrList->iAddressCount];
|
||
|
|
||
|
// Copy in addresses
|
||
|
for (i = 0; i < pSocketAddrList->iAddressCount; i++)
|
||
|
{
|
||
|
pszIPAddress = inet_ntoa(((SOCKADDR_IN*)pSocketAddrList->Address[i].lpSockaddr)->sin_addr);
|
||
|
ASSERT(pszIPAddress);
|
||
|
|
||
|
ret = MultiByteToWideChar(
|
||
|
CP_ACP,
|
||
|
0,
|
||
|
pszIPAddress,
|
||
|
-1,
|
||
|
pVector->NetworkAddresses[i],
|
||
|
IPMaximumPrettyName
|
||
|
);
|
||
|
if (ret == 0)
|
||
|
{
|
||
|
PrivMemFree(pVector);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (i != (pSocketAddrList->iAddressCount - 1))
|
||
|
{
|
||
|
// Setup for next address, if any
|
||
|
pVector->NetworkAddresses[i+1] = pVector->NetworkAddresses[i];
|
||
|
pVector->NetworkAddresses[i+1] += lstrlenW(pVector->NetworkAddresses[i]) + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pVector;
|
||
|
}
|