2025-04-27 07:49:33 -04:00

1632 lines
42 KiB
C++

/*==========================================================================
*
* Copyright (C) 1998-2000 Microsoft Corporation. All Rights Reserved.
*
* File: IPAddress.cpp
* Content: Winsock IP address class
*
*
* History:
* Date By Reason
* ==== == ======
* 01/20/99 jtk Created
* 05/12/99 jtk Derived from modem endpoint class
* 01/10/20000 rmt Updated to build with Millenium build process
* 03/22/20000 jtk Updated with changes to interface names
***************************************************************************/
#include "dnwsocki.h"
#undef DPF_SUBCOMP
#define DPF_SUBCOMP DN_SUBCOMP_WSOCK
//**********************************************************************
// Constant definitions
//**********************************************************************
//
// 192.168.0.1 in network byte order
//
#define IP_PRIVATEICS_ADDRESS 0x0100A8C0
//
// default size of buffers when parsing
//
#define DEFAULT_COMPONENT_BUFFER_SIZE 1000
//
// default broadcast and listen addresses
//
const WCHAR g_IPBroadcastAddress[] = L"255.255.255.255";
const DWORD g_dwIPBroadcastAddressSize = sizeof( g_IPBroadcastAddress );
static const WCHAR g_IPListenAddress[] = L"0.0.0.0";
//
// string for IP helper API
//
static const TCHAR c_tszIPHelperDLLName[] = TEXT("IPHLPAPI.DLL");
static const char c_szAdapterNameTemplate[] = "%s - %s";
//**********************************************************************
// Macro definitions
//**********************************************************************
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
//**********************************************************************
// Function prototypes
//**********************************************************************
typedef DWORD (WINAPI *PFNGETADAPTERSINFO)(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen);
//**********************************************************************
// Function definitions
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::InitializeWithBroadcastAddress - initialize with the IP broadcast address
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
void CIPAddress::InitializeWithBroadcastAddress( void )
{
m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr = p_htonl( INADDR_BROADCAST );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::SetAddressFromSOCKADDR - set address from a socket address
//
// Entry: Reference to address
// Size of address
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::SetAddressFromSOCKADDR"
void CIPAddress::SetAddressFromSOCKADDR( const SOCKADDR &Address, const INT_PTR iAddressSize )
{
DNASSERT( iAddressSize == GetAddressSize() );
memcpy( &m_SocketAddress.SocketAddress, &Address, iAddressSize );
//
// Since Winsock won't guarantee that the sin_zero part of an IP address is
// really zero, we ned to do it ourself. If we don't, it'll make a mess out
// of the Guid<-->Address code.
//
DBG_CASSERT( sizeof( &m_SocketAddress.IPSocketAddress.sin_zero[ 0 ] ) == sizeof( DWORD* ) );
DBG_CASSERT( sizeof( &m_SocketAddress.IPSocketAddress.sin_zero[ sizeof( DWORD ) ] ) == sizeof( DWORD* ) );
*reinterpret_cast<DWORD*>( &m_SocketAddress.IPSocketAddress.sin_zero[ 0 ] ) = 0;
*reinterpret_cast<DWORD*>( &m_SocketAddress.IPSocketAddress.sin_zero[ sizeof( DWORD ) ] ) = 0;
DNASSERT( SinZeroIsZero( &m_SocketAddress.IPSocketAddress ) != FALSE );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::SocketAddressFromDP8Address - convert a DP8Address to a socket address
// NOTE: The address object may be modified
//
// Entry: Pointer to address
// Address type
//
// Exit: Error code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::SocketAddressFromDP8Address"
HRESULT CIPAddress::SocketAddressFromDP8Address( IDirectPlay8Address *const pDP8Address,
const SP_ADDRESS_TYPE AddressType )
{
HRESULT hr;
DWORD dwAddressSize;
IDirectPlay8AddressIP *pIPAddress;
//IDirectPlay8Address *pDuplicateAddress;
SOCKADDR *pSocketAddresses;
DNASSERT( pDP8Address != NULL );
//
// initialize
//
hr = DPN_OK;
pIPAddress = NULL;
//pDuplicateAddress = NULL;
pSocketAddresses = NULL;
//
// reset internal flags
//
Reset();
switch ( AddressType )
{
//
// local device address, ask for the device guid and port to build a socket
// address
//
case SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT:
case SP_ADDRESS_TYPE_DEVICE_PROXIED_ENUM_TARGET:
{
HRESULT hTempResult;
DWORD dwTempSize;
GUID AdapterGuid;
DWORD dwPort;
DWORD dwDataType;
union
{
SOCKADDR SocketAddress;
SOCKADDR_IN INetAddress;
} INetSocketAddress;
//
// Ask for the adapter guid. If none is found, fail.
//
dwTempSize = sizeof( AdapterGuid );
hTempResult = IDirectPlay8Address_GetComponentByName( pDP8Address, DPNA_KEY_DEVICE, &AdapterGuid, &dwTempSize, &dwDataType );
switch ( hTempResult )
{
//
// ok
//
case DPN_OK:
{
DNASSERT( dwDataType == DPNA_DATATYPE_GUID );
break;
}
//
// remap missing component to 'addressing' error
//
case DPNERR_DOESNOTEXIST:
{
hr = DPNERR_ADDRESSING;
goto Failure;
break;
}
default:
{
hr = hTempResult;
goto Failure;
break;
}
}
DNASSERT( sizeof( AdapterGuid ) == dwTempSize );
//
// Ask for the port. If none is found, choose a default.
//
dwTempSize = sizeof( dwPort );
hTempResult = IDirectPlay8Address_GetComponentByName( pDP8Address, DPNA_KEY_PORT, &dwPort, &dwTempSize, &dwDataType );
switch ( hTempResult )
{
//
// port present, nothing to do
//
case DPN_OK:
{
DNASSERT( dwDataType == DPNA_DATATYPE_DWORD );
break;
}
//
// port not present, fill in the appropriate default
//
case DPNERR_DOESNOTEXIST:
{
DNASSERT( hr == DPN_OK );
switch ( AddressType )
{
case SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT:
{
dwPort = ANY_PORT;
break;
}
default:
{
DNASSERT( FALSE );
break;
}
}
break;
}
//
// other error, fail
//
default:
{
hr = hTempResult;
goto Failure;
break;
}
}
DNASSERT( sizeof( dwPort ) == dwTempSize );
//
// convert the GUID to an address in temp space because the GUID contains ALL address information (port, etc)
// and we don't want to blindly wail on any information that might have already been set. Verify data
// integrity and then only copy the raw address.
//
AddressFromGuid( AdapterGuid, INetSocketAddress.SocketAddress );
if ( ( INetSocketAddress.INetAddress.sin_family != m_SocketAddress.IPSocketAddress.sin_family ) ||
( reinterpret_cast<DWORD*>( &INetSocketAddress.INetAddress.sin_zero[ 0 ] )[ 0 ] != 0 ) ||
( reinterpret_cast<DWORD*>( &INetSocketAddress.INetAddress.sin_zero[ 0 ] )[ 1 ] != 0 ) )
{
DNASSERT( FALSE );
hr = DPNERR_ADDRESSING;
DPFX(DPFPREP, 0, "Invalid device guid!" );
goto Exit;
}
//
// if this is a proxied enum, check for the all-adapters address
// being passed because it's not a valid target (it needs to be
// remapped to the local loopback).
//
if ( ( AddressType == SP_ADDRESS_TYPE_DEVICE_PROXIED_ENUM_TARGET ) &&
( INetSocketAddress.INetAddress.sin_addr.S_un.S_addr == p_htonl( INADDR_ANY ) ) )
{
m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr = p_htonl( INADDR_LOOPBACK );
}
else
{
m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr = INetSocketAddress.INetAddress.sin_addr.S_un.S_addr;
}
m_SocketAddress.IPSocketAddress.sin_port = p_htons( static_cast<WORD>( dwPort ) );
break;
}
//
// hostname
//
case SP_ADDRESS_TYPE_HOST:
{
HRESULT hTempResult;
DWORD dwPort;
DWORD dwTempSize;
DWORD dwDataType;
/*
//
// duplicate the input address because it might need to be modified
//
DNASSERT( pDuplicateAddress == NULL );
IDirectPlay8Address_Duplicate( pDP8Address, &pDuplicateAddress );
if ( pDuplicateAddress == NULL )
{
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
*/
//
// Ask for the port. If none is found, choose a default.
//
dwTempSize = sizeof( dwPort );
//hTempResult = IDirectPlay8Address_GetComponentByName( pDuplicateAddress, DPNA_KEY_PORT, &dwPort, &dwTempSize, &dwDataType );
hTempResult = IDirectPlay8Address_GetComponentByName( pDP8Address, DPNA_KEY_PORT, &dwPort, &dwTempSize, &dwDataType );
switch ( hTempResult )
{
//
// port present, nothing to do
//
case DPN_OK:
{
DNASSERT( dwDataType == DPNA_DATATYPE_DWORD );
m_SocketAddress.IPSocketAddress.sin_port = p_htons( static_cast<WORD>( dwPort ) );
break;
}
//
// port not present, fill in the appropriate default
//
case DPNERR_DOESNOTEXIST:
{
const DWORD dwTempPort = DPNA_DPNSVR_PORT;
m_SocketAddress.IPSocketAddress.sin_port = p_htons( static_cast<const WORD>( dwTempPort ) );
//hTempResult = IDirectPlay8Address_AddComponent( pDuplicateAddress,
hTempResult = IDirectPlay8Address_AddComponent( pDP8Address,
DPNA_KEY_PORT,
&dwTempPort,
sizeof( dwTempPort ),
DPNA_DATATYPE_DWORD
);
if ( hTempResult != DPN_OK )
{
hr = hTempResult;
goto Failure;
}
break;
}
//
// remap everything else to an addressing failure
//
default:
{
hr = DPNERR_ADDRESSING;
goto Failure;
}
}
//
// get an IP interface
//
/*
DNASSERT( pDuplicateAddress != NULL );
hr = IDirectPlay8Address_QueryInterface( pDuplicateAddress, IID_IDirectPlay8AddressIP, reinterpret_cast<void**>( &pIPAddress ) );
*/
hr = IDirectPlay8Address_QueryInterface( pDP8Address, IID_IDirectPlay8AddressIP, reinterpret_cast<void**>( &pIPAddress ) );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "SocketAddressFromDP8Address: Failed to get IPAddress interface" );
DisplayDNError( 0, hr );
goto Failure;
}
//
// attempt to determine the host name
//
dwAddressSize = 0;
DNASSERT( pSocketAddresses == NULL );
RegetSocketAddressData:
memset( pSocketAddresses, 0x00, dwAddressSize );
hr = IDirectPlay8AddressIP_GetSockAddress( pIPAddress, pSocketAddresses, &dwAddressSize );
switch ( hr )
{
//
// conversion succeeded, check the size of the data returned
// before setting the information in the local address structure.
//
case DPN_OK:
{
if ( dwAddressSize < sizeof( *pSocketAddresses ) )
{
hr = DPNERR_ADDRESSING;
goto Failure;
}
SetAddressFromSOCKADDR( *pSocketAddresses, sizeof( *pSocketAddresses ) );
break;
}
//
// Buffer too small, if there is no buffer, allocate one. If
// there is a buffer, resize it to containt the data before
// attempting to get the data again.
//
case DPNERR_BUFFERTOOSMALL:
{
if ( pSocketAddresses == NULL )
{
pSocketAddresses = static_cast<SOCKADDR*>( DNMalloc( dwAddressSize ) );
if ( pSocketAddresses == NULL )
{
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
}
else
{
void *pTemp;
pTemp = DNRealloc( pSocketAddresses, dwAddressSize );
if ( pTemp == NULL )
{
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
pSocketAddresses = static_cast<SOCKADDR*>( pTemp );
}
goto RegetSocketAddressData;
break;
}
//
// Incomplete address, set the address type and return. It's
// up to the caller to decide if this is really a problem.
//
case DPNERR_INCOMPLETEADDRESS:
{
break;
}
//
// pass these error returns untouched
//
case DPNERR_OUTOFMEMORY:
{
goto Failure;
break;
}
//
// other problem, map it to an addressing error
//
default:
{
hr = DPNERR_ADDRESSING;
goto Failure;
break;
}
}
break;
}
//
// unknown address type
//
default:
{
DNASSERT( FALSE );
break;
}
}
DNASSERT( SinZeroIsZero( &m_SocketAddress.IPSocketAddress ) != FALSE );
//
// now that the address has been completely parsed, set the address type
//
m_AddressType = AddressType;
Exit:
if ( pIPAddress != NULL )
{
IDirectPlay8AddressIP_Release( pIPAddress );
pIPAddress = NULL;
}
/*
if ( pDuplicateAddress != NULL )
{
IDirectPlay8Address_Release( pDuplicateAddress );
pDuplicateAddress = NULL;
}
*/
if ( pSocketAddresses != NULL )
{
DNFree( pSocketAddresses );
pSocketAddresses = NULL;
}
if (( hr != DPN_OK ) && ( hr != DPNERR_INCOMPLETEADDRESS ))
{
DPFX(DPFPREP, 0, "Problem with IPAddress::SocketAddressFromDP8Address() (0x%lx)", hr );
DisplayDNError( 0, hr );
}
return hr;
Failure:
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::DP8AddressFromSocketAddress - convert a socket address to a DP8Address
//
// Entry: Nothing
//
// Exit: Pointer to DP8Address
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::DP8AddressFromSocketAddress"
IDirectPlay8Address *CIPAddress::DP8AddressFromSocketAddress( void ) const
{
HRESULT hr;
IDirectPlay8Address *pDP8Address;
IDirectPlay8AddressIP *pIPAddress;
DNASSERT( ( m_ComponentInitializationState[ SPADDRESS_PARSE_KEY_DEVICE ] != SP_ADDRESS_COMPONENT_INITIALIZATION_FAILED ) &&
( m_ComponentInitializationState[ SPADDRESS_PARSE_KEY_HOSTNAME ] != SP_ADDRESS_COMPONENT_INITIALIZATION_FAILED ) &&
( m_ComponentInitializationState[ SPADDRESS_PARSE_KEY_PORT ] != SP_ADDRESS_COMPONENT_INITIALIZATION_FAILED ) );
//
// intialize
//
hr = DPN_OK;
pDP8Address = NULL;
pIPAddress = NULL;
//
// create and initialize the address
//
hr = COM_CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8AddressIP, reinterpret_cast<void**>( &pIPAddress ) );
if ( hr != S_OK )
{
DNASSERT( pIPAddress == NULL );
DPFX(DPFPREP, 0, "DP8AddressFromSocketAddress: Failed to create IPAddress when converting socket address do DP8Address" );
DNASSERT( FALSE );
goto Failure;
}
switch ( m_AddressType )
{
case SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT:
{
GUID DeviceGuid;
GuidFromInternalAddressWithoutPort( DeviceGuid );
hr = IDirectPlay8AddressIP_BuildLocalAddress( pIPAddress,
&DeviceGuid,
p_ntohs( m_SocketAddress.IPSocketAddress.sin_port )
);
break;
}
case SP_ADDRESS_TYPE_PUBLIC_HOST_ADDRESS:
case SP_ADDRESS_TYPE_READ_HOST:
case SP_ADDRESS_TYPE_HOST:
{
hr = IDirectPlay8AddressIP_BuildFromSockAddr( pIPAddress, &m_SocketAddress.SocketAddress );
break;
}
default:
{
DNASSERT( FALSE );
break;
}
}
Exit:
//
// clean up the IP interface pointer. If we got this far and there was
// no error it means that we built the IP address properly. Get a generic
// address interface to return to the user.
//
if ( pIPAddress != NULL )
{
if ( hr == DPN_OK )
{
DNASSERT( pDP8Address == NULL );
hr = IDirectPlay8AddressIP_QueryInterface( pIPAddress, IID_IDirectPlay8Address, reinterpret_cast<void**>( &pDP8Address ) );
DNASSERT( ( hr == DPN_OK ) || ( pDP8Address == NULL ) );
}
IDirectPlay8AddressIP_Release( pIPAddress );
}
return pDP8Address;
Failure:
if ( pDP8Address != NULL )
{
IDirectPlay8Address_Release( pDP8Address );
pDP8Address = NULL;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::CompareFunction - compare against another address
//
// Entry: Pointer to other address
//
// Exit: Integer indicating relative magnitude:
// 0 = items equal
// -1 = other item is of greater magnitude
// 1 = this item is of lesser magnitude
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::CompareFunction"
INT_PTR CIPAddress::CompareFunction( const CSocketAddress *const pOtherAddress ) const
{
INT_PTR iReturn;
const CIPAddress *const pIPAddress = static_cast<const CIPAddress*>( pOtherAddress );
DNASSERT( pOtherAddress != NULL );
DNASSERT( m_SocketAddress.IPSocketAddress.sin_family == pIPAddress->m_SocketAddress.IPSocketAddress.sin_family );
//
// we need to compare the IP address and port to guarantee uniqueness
//
if ( m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr == pIPAddress->m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr )
{
if ( m_SocketAddress.IPSocketAddress.sin_port == pIPAddress->m_SocketAddress.IPSocketAddress.sin_port )
{
iReturn = 0;
}
else
{
if ( m_SocketAddress.IPSocketAddress.sin_port < pIPAddress->m_SocketAddress.IPSocketAddress.sin_port )
{
iReturn = -1;
}
else
{
iReturn = 1;
}
}
}
else
{
if ( m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr < pIPAddress->m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr )
{
iReturn = -1;
}
else
{
iReturn = 1;
}
}
return iReturn;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::CreateBroadcastAddress - create DP8Address used for broadcast sends
//
// Entry: Nothing
//
// Exit: Pointer to address
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::CreateBroadcastAddress"
IDirectPlay8Address *CIPAddress::CreateBroadcastAddress( void )
{
HRESULT hr;
IDirectPlay8Address *pDPlayAddress;
IDirectPlay8AddressIP *pIPAddress;
//
// initialize
//
pDPlayAddress = NULL;
pIPAddress = NULL;
hr = COM_CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, reinterpret_cast<void**>( &pDPlayAddress ) );
if ( hr != S_OK )
{
DNASSERT( pDPlayAddress == NULL );
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to create IPAddress when converting socket address do DP8Address" );
DNASSERT( FALSE );
goto Failure;
}
hr = IDirectPlay8Address_QueryInterface( pDPlayAddress, IID_IDirectPlay8AddressIP, reinterpret_cast<void**>( &pIPAddress ) );
if ( hr != S_OK )
{
goto Failure;
}
hr = IDirectPlay8AddressIP_BuildAddress( pIPAddress, g_IPBroadcastAddress, DPNA_DPNSVR_PORT );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to set hostname and port!" );
DisplayDNError( 0, hr );
goto Failure;
}
Exit:
if ( pIPAddress != NULL )
{
IDirectPlay8AddressIP_Release( pIPAddress );
pIPAddress = NULL;
}
return pDPlayAddress;
Failure:
if ( pDPlayAddress != NULL )
{
IDirectPlay8Address_Release( pDPlayAddress );
pDPlayAddress = NULL;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::CreateListenAddress - create DP8Address used for listens
//
// Entry: Nothing
//
// Exit: Pointer to address
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::CreateListenAddress"
IDirectPlay8Address *CIPAddress::CreateListenAddress( void )
{
HRESULT hr;
IDirectPlay8Address *pDPlayAddress;
IDirectPlay8AddressIP *pIPAddress;
//
// initialize
//
pDPlayAddress = NULL;
pIPAddress = NULL;
hr = COM_CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, reinterpret_cast<void**>( &pDPlayAddress ) );
if ( hr != S_OK )
{
DNASSERT( pDPlayAddress == NULL );
DPFX(DPFPREP, 0, "CreateListenAddress: Failed to create IPAddress when converting socket address do DP8Address" );
DNASSERT( FALSE );
goto Failure;
}
hr = IDirectPlay8Address_QueryInterface( pDPlayAddress, IID_IDirectPlay8AddressIP, reinterpret_cast<void**>( &pIPAddress ) );
if ( hr != S_OK )
{
goto Failure;
}
hr = IDirectPlay8AddressIP_BuildAddress( pIPAddress, g_IPListenAddress, ANY_PORT );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateListenAddress: Failed to set hostname and port!" );
DisplayDNError( 0, hr );
goto Failure;
}
Exit:
if ( pIPAddress != NULL )
{
IDirectPlay8AddressIP_Release( pIPAddress );
pIPAddress = NULL;
}
return pDPlayAddress;
Failure:
if ( pDPlayAddress != NULL )
{
IDirectPlay8Address_Release( pDPlayAddress );
pDPlayAddress = NULL;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::CreateGenericAddress - create a generic address
//
// Entry: Nothing
//
// Exit: Pointer to address
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::CreateGenericAddress"
IDirectPlay8Address *CIPAddress::CreateGenericAddress( void )
{
HRESULT hr;
IDirectPlay8Address *pDPlayAddress;
IDirectPlay8AddressIP *pIPAddress;
//
// initialize
//
pDPlayAddress = NULL;
pIPAddress = NULL;
hr = COM_CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, reinterpret_cast<void**>( &pDPlayAddress ) );
if ( hr != S_OK )
{
DNASSERT( pDPlayAddress == NULL );
DPFX(DPFPREP, 0, "CreateGenericAddress: Failed to create IPAddress when converting socket address do DP8Address" );
DNASSERT( FALSE );
goto Failure;
}
hr = IDirectPlay8Address_QueryInterface( pDPlayAddress, IID_IDirectPlay8AddressIP, reinterpret_cast<void**>( &pIPAddress ) );
if ( hr != S_OK )
{
goto Failure;
}
hr = IDirectPlay8AddressIP_BuildAddress( pIPAddress, g_IPListenAddress, ANY_PORT );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateGenericAddress: Failed to set hostname and port!" );
DisplayDNError( 0, hr );
goto Failure;
}
Exit:
if ( pIPAddress != NULL )
{
IDirectPlay8AddressIP_Release( pIPAddress );
pIPAddress = NULL;
}
return pDPlayAddress;
Failure:
if ( pDPlayAddress != NULL )
{
IDirectPlay8Address_Release( pDPlayAddress );
pDPlayAddress = NULL;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::CompareToBaseAddress - compare this address to a 'base' address
// of this class
//
// Entry: Pointer to base address
//
// Exit: Integer indicating relative magnitude:
// 0 = items equal
// -1 = other item is of greater magnitude
// 1 = this item is of lesser magnitude
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::CompareToBaseAddress"
INT_PTR CIPAddress::CompareToBaseAddress( const SOCKADDR *const pBaseAddress ) const
{
const SOCKADDR_IN *pBaseIPAddress;
DNASSERT( pBaseAddress != NULL );
DNASSERT( pBaseAddress->sa_family == m_SocketAddress.SocketAddress.sa_family );
pBaseIPAddress = reinterpret_cast<const SOCKADDR_IN*>( pBaseAddress );
if ( m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr == pBaseIPAddress->sin_addr.S_un.S_addr )
{
return 0;
}
else
{
if ( m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr < pBaseIPAddress->sin_addr.S_un.S_addr )
{
return 1;
}
else
{
return -1;
}
}
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::HashFunction - hash address to N bits
//
// Entry: Count of bits to hash to
//
// Exit: Hashed value
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::HashFunction"
INT_PTR CIPAddress::HashFunction( const INT_PTR iHashBitCount ) const
{
INT_PTR iReturn;
UINT_PTR Temp;
DNASSERT( iHashBitCount != 0 );
//
// initialize
//
iReturn = 0;
//
// hash IP address
//
Temp = m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr;
do
{
iReturn ^= Temp & ( ( 1 << iHashBitCount ) - 1 );
Temp >>= iHashBitCount;
} while ( Temp != 0 );
//
// hash IP port
//
Temp = m_SocketAddress.IPSocketAddress.sin_port;
do
{
iReturn^= Temp & ( ( 1 << iHashBitCount ) - 1 );
Temp >>= iHashBitCount;
}
while ( Temp != 0 );
return iReturn;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::EnumAdapters - enumerate all of the adapters for this machine
//
// Entry: Pointer to enum adapters data
//
// Exit: Error code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::EnumAdapters"
HRESULT CIPAddress::EnumAdapters( SPENUMADAPTERSDATA *const pEnumData ) const
{
HRESULT hr;
DWORD dwError;
SOCKADDR_IN saddrinTemp;
const HOSTENT * pHostData;
IN_ADDR ** ppinaddrTemp;
DWORD dwAddressCount;
BOOL fFoundPrivateICS = FALSE;
IN_ADDR * pinaddrBuffer = NULL;
DWORD dwIndex;
HMODULE hIpHlpApiDLL;
PFNGETADAPTERSINFO pfnGetAdaptersInfo;
IP_ADAPTER_INFO * pAdapterInfoBuffer = NULL;
ULONG ulAdapterInfoBufferSize = 0;
const char * pszIPAddress;
IP_ADAPTER_INFO * pCurrentAdapterInfo;
PIP_ADDR_STRING pIPAddrString;
GUID guidAdapter;
CPackedBuffer PackedBuffer;
char acBuffer[512];
DPFX(DPFPREP, 6, "Parameters: (0x%p)", pEnumData);
PackedBuffer.Initialize( pEnumData->pAdapterData, pEnumData->dwAdapterDataSize );
ZeroMemory(&saddrinTemp, sizeof(saddrinTemp));
saddrinTemp.sin_family = GetFamily();
//
// Get the list of local IPs from WinSock. We use this method since it's
// available on all platforms and conveniently returns the loopback address
// when no valid adapters are currently available.
//
if (p_gethostname(acBuffer, sizeof(acBuffer)) == SOCKET_ERROR)
{
#ifdef DEBUG
dwError = p_WSAGetLastError();
DPFX(DPFPREP, 0, "Failed to get host name into fixed size buffer (err = %u)!", dwError);
DisplayWinsockError(0, dwError);
#endif // DEBUG
hr = DPNERR_GENERIC;
goto Failure;
}
pHostData = p_gethostbyname(acBuffer);
if (pHostData == NULL)
{
#ifdef DEBUG
dwError = p_WSAGetLastError();
DPFX(DPFPREP, 0, "Failed to get host data (err = %u)!", dwError);
DisplayWinsockError(0, dwError);
#endif // DEBUG
hr = DPNERR_GENERIC;
goto Failure;
}
//
// Count number of addresses.
//
dwAddressCount = 0;
ppinaddrTemp = (IN_ADDR**) (pHostData->h_addr_list);
while ((*ppinaddrTemp) != NULL)
{
//
// Remember if it's 192.168.0.1. See below
//
if ((*ppinaddrTemp)->S_un.S_addr == IP_PRIVATEICS_ADDRESS)
{
fFoundPrivateICS = TRUE;
}
dwAddressCount++;
ppinaddrTemp++;
}
if (dwAddressCount == 0)
{
DPFX(DPFPREP, 1, "No IP addresses, forcing loopback address.");
DNASSERTX(!" No IP addresses!", 2);
dwAddressCount++;
}
else
{
DPFX(DPFPREP, 3, "WinSock reported %u addresses.", dwAddressCount);
}
//
// Winsock says we should copy this data before any other Winsock calls.
//
// We also use this as an opportunity to ensure that the order returned to the caller is
// to our liking. In particular, we make sure the private address 192.168.0.1 appears
// first.
//
DNASSERT(pHostData->h_length == sizeof(IN_ADDR));
pinaddrBuffer = (IN_ADDR*) DNMalloc(dwAddressCount * sizeof(IN_ADDR));
if (pinaddrBuffer == NULL)
{
DPFX(DPFPREP, 0, "Failed to allocate memory to store copy of addresses!");
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
dwIndex = 0;
//
// First, store 192.168.0.1 if we found it.
//
if (fFoundPrivateICS)
{
pinaddrBuffer[dwIndex].S_un.S_addr = IP_PRIVATEICS_ADDRESS;
dwIndex++;
}
//
// Then copy the rest.
//
ppinaddrTemp = (IN_ADDR**) (pHostData->h_addr_list);
while ((*ppinaddrTemp) != NULL)
{
if ((*ppinaddrTemp)->S_un.S_addr != IP_PRIVATEICS_ADDRESS)
{
pinaddrBuffer[dwIndex].S_un.S_addr = (*ppinaddrTemp)->S_un.S_addr;
dwIndex++;
}
ppinaddrTemp++;
}
//
// If we didn't have any addresses, slap in the loopback address.
//
if (dwIndex == 0)
{
pinaddrBuffer[0].S_un.S_addr = p_htonl(INADDR_LOOPBACK);
dwIndex++;
}
DNASSERT(dwIndex == dwAddressCount);
//
// Now we try to generate names and GUIDs for these IP addresses.
// We'll use what IPHLPAPI reports for a name if possible, and fall
// back to just using the IP address string as the name.
//
//
// Load the IPHLPAPI module and get the adapter list if possible.
//
hIpHlpApiDLL = LoadLibrary(c_tszIPHelperDLLName);
if (hIpHlpApiDLL != NULL)
{
pfnGetAdaptersInfo = (PFNGETADAPTERSINFO) GetProcAddress(hIpHlpApiDLL, "GetAdaptersInfo");
if (pfnGetAdaptersInfo != NULL)
{
//
// Keep resizing the buffer until there's enough room.
//
do
{
dwError = pfnGetAdaptersInfo(pAdapterInfoBuffer,
&ulAdapterInfoBufferSize);
if (dwError == ERROR_SUCCESS)
{
//
// We got all the info we're going to get. Make sure it
// was something.
//
if (ulAdapterInfoBufferSize == 0)
{
DPFX(DPFPREP, 0, "GetAdaptersInfo returned 0 byte size requirement! Ignoring.");
//
// Get rid of the buffer if allocated.
//
if (pAdapterInfoBuffer != NULL)
{
DNFree(pAdapterInfoBuffer);
pAdapterInfoBuffer = NULL;
}
//
// Continue with exiting the loop.
//
}
#ifdef DEBUG
else
{
int iStrLen;
char szIPList[256];
char * pszCurrentIP;
//
// Print out all the adapters for debugging purposes.
//
pCurrentAdapterInfo = pAdapterInfoBuffer;
while (pCurrentAdapterInfo != NULL)
{
//
// Initialize IP address list string.
//
szIPList[0] = '\0';
pszCurrentIP = szIPList;
//
// Loop through all addresses for this adapter.
//
pIPAddrString = &pCurrentAdapterInfo->IpAddressList;
while (pIPAddrString != NULL)
{
//
// Copy the IP address string (if there's enough room),
// then tack on a space and NULL terminator.
//
iStrLen = strlen(pIPAddrString->IpAddress.String);
if ((pszCurrentIP + iStrLen + 2) < (szIPList + sizeof(szIPList)))
{
memcpy(pszCurrentIP, pIPAddrString->IpAddress.String, iStrLen);
pszCurrentIP += iStrLen;
(*pszCurrentIP) = ' ';
pszCurrentIP++;
(*pszCurrentIP) = '\0';
pszCurrentIP++;
}
pIPAddrString = pIPAddrString->Next;
}
DPFX(DPFPREP, 8, "Adapter index %u IPs = %s, %s, \"%s\".",
pCurrentAdapterInfo->Index,
szIPList,
pCurrentAdapterInfo->AdapterName,
pCurrentAdapterInfo->Description);
//
// Go to next adapter.
//
pCurrentAdapterInfo = pCurrentAdapterInfo->Next;
}
} // end else (got valid buffer size)
#endif // DEBUG
break;
}
if (dwError != ERROR_BUFFER_OVERFLOW)
{
DPFX(DPFPREP, 0, "GetAdaptersInfo failed (err = 0x%lx)! Ignoring.", dwError);
//
// Get rid of the buffer if allocated, and then bail out of
// the loop.
//
if (pAdapterInfoBuffer != NULL)
{
DNFree(pAdapterInfoBuffer);
pAdapterInfoBuffer = NULL;
}
break;
}
//
// If we're here, then we need to reallocate the buffer.
//
if (pAdapterInfoBuffer != NULL)
{
DNFree(pAdapterInfoBuffer);
pAdapterInfoBuffer = NULL;
}
pAdapterInfoBuffer = (IP_ADAPTER_INFO*) DNMalloc(ulAdapterInfoBufferSize);
if (pAdapterInfoBuffer == NULL)
{
//
// Couldn't allocate memory. Bail out of the loop.
//
break;
}
//
// Successfully allocated buffer. Try again.
//
}
while (TRUE);
//
// We get here in all cases, so we may have failed to get an info
// buffer. That's fine, we'll use the fallback to generate the
// names.
//
}
else
{
#ifdef DEBUG
dwError = GetLastError();
DPFX(DPFPREP, 0, "Failed to get proc address for GetAdaptersInfo!");
DisplayErrorCode(0, dwError);
#endif // DEBUG
//
// Continue. We'll use the fallback to generate the names.
//
}
//
// We don't need the library anymore.
//
FreeLibrary(hIpHlpApiDLL);
hIpHlpApiDLL = NULL;
}
else
{
#ifdef DEBUG
dwError = GetLastError();
DPFX(DPFPREP, 0, "Failed to get proc address for GetAdaptersInfo!");
DisplayErrorCode(0, dwError);
#endif // DEBUG
//
// Continue. We'll use the fallback to generate the names.
//
}
//
// Loop through all IP addresses, generating names and GUIDs.
//
for(dwIndex = 0; dwIndex < dwAddressCount; dwIndex++)
{
//
// Get the IP address string. We don't make any other WinSock
// calls, so holding on to the pointer is OK. This pointer
// may be used as the device name string, too.
//
pszIPAddress = p_inet_ntoa(pinaddrBuffer[dwIndex]);
//
// Look for an adapter name from IPHLPAPI if possible.
//
if (pAdapterInfoBuffer != NULL)
{
pCurrentAdapterInfo = pAdapterInfoBuffer;
while (pCurrentAdapterInfo != NULL)
{
//
// Look for matching IP.
//
pIPAddrString = &pCurrentAdapterInfo->IpAddressList;
while (pIPAddrString != NULL)
{
if (strcmp(pIPAddrString->IpAddress.String, pszIPAddress) == 0)
{
DPFX(DPFPREP, 9, "Found %s under adapter index %u (\"%s\").",
pszIPAddress, pCurrentAdapterInfo->Index,
pCurrentAdapterInfo->Description);
//
// Build the name string.
//
wsprintfA(acBuffer,
c_szAdapterNameTemplate,
pCurrentAdapterInfo->Description,
pszIPAddress);
//
// Point the name string to the buffer and drop out
// of the loop.
//
pszIPAddress = acBuffer;
break;
}
//
// Move to next IP address.
//
pIPAddrString = pIPAddrString->Next;
}
//
// If we found the address, stop looping through adapters,
// too.
//
if (pszIPAddress == acBuffer)
{
break;
}
//
// Otherwise, go to next adapter.
//
pCurrentAdapterInfo = pCurrentAdapterInfo->Next;
}
//
// If we never found the adapter, pszIPAddress will still point to
// the IP address string.
//
}
else
{
//
// Didn't successfully get IPHLPAPI adapter info. pszIPAddress will
// still point to the IP address string.
//
}
//
// Generate the GUID.
//
saddrinTemp.sin_addr = pinaddrBuffer[dwIndex];
GuidFromAddress(guidAdapter, *((SOCKADDR*) (&saddrinTemp)));
DPFX(DPFPREP, 7, "Returning adapter %u: \"%s\" {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}.",
dwIndex,
pszIPAddress,
guidAdapter.Data1,
guidAdapter.Data2,
guidAdapter.Data3,
guidAdapter.Data4[0],
guidAdapter.Data4[1],
guidAdapter.Data4[2],
guidAdapter.Data4[3],
guidAdapter.Data4[4],
guidAdapter.Data4[5],
guidAdapter.Data4[6],
guidAdapter.Data4[7]);
//
// Add to buffer.
//
hr = AddNetworkAdapterToBuffer(&PackedBuffer, pszIPAddress, &guidAdapter);
if ((hr != DPN_OK) && (hr != DPNERR_BUFFERTOOSMALL))
{
DPFX(DPFPREP, 0, "Failed to add adapter to buffer (err = 0x%lx)!", hr);
DisplayDNError( 0, hr );
goto Failure;
}
}
//
// If we're here, we successfully built the list of adapters, although
// the caller may not have given us enough buffer space to store it.
//
pEnumData->dwAdapterCount = dwAddressCount;
pEnumData->dwAdapterDataSize = PackedBuffer.GetSizeRequired();
Exit:
if (pAdapterInfoBuffer != NULL)
{
DNFree(pAdapterInfoBuffer);
pAdapterInfoBuffer = NULL;
}
if (pinaddrBuffer != NULL)
{
DNFree(pinaddrBuffer);
pinaddrBuffer = NULL;
}
DPFX(DPFPREP, 6, "Return [0x%lx]", hr);
return hr;
Failure:
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::GuidFromInternalAddressWithoutPort - get a guid from the internal
// address without a port.
//
// Entry: Reference to desintation GUID
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::GuidFromInternalAddressWithoutPort"
void CIPAddress::GuidFromInternalAddressWithoutPort( GUID &OutputGuid ) const
{
union
{
SOCKADDR SockAddr;
SOCKADDR_IN IPSockAddr;
} TempSocketAddress;
DBG_CASSERT( sizeof( TempSocketAddress.SockAddr ) == sizeof( m_SocketAddress.SocketAddress ) );
memcpy( &TempSocketAddress.SockAddr, &m_SocketAddress.SocketAddress, sizeof( TempSocketAddress.SockAddr ) );
TempSocketAddress.IPSockAddr.sin_port = 0;
GuidFromAddress( OutputGuid, TempSocketAddress.SockAddr );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::IsUndefinedHostAddress - determine if this is an undefined host
// address
//
// Entry: Nothing
//
// Exit: Boolean indicating whether this is an undefined host address
// TRUE = this is an undefined address
// FALSE = this is not an undefined address
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::IsUndefinedHostAddress"
BOOL CIPAddress::IsUndefinedHostAddress( void ) const
{
BOOL fReturn;
fReturn = FALSE;
if ( m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr == p_htonl( INADDR_ANY ) )
{
fReturn = TRUE;
}
return fReturn;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::ChangeLoopBackToLocalAddress - change loopback to a local address
//
// Entry: Pointer to other address
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::ChangeLoopBackToLocalAddress"
void CIPAddress::ChangeLoopBackToLocalAddress( const CSocketAddress *const pOtherSocketAddress )
{
const CIPAddress *pOtherIPAddress;
DNASSERT( pOtherSocketAddress != NULL );
pOtherIPAddress = static_cast<const CIPAddress*>( pOtherSocketAddress );
if ( m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr == p_htonl( INADDR_LOOPBACK ) )
{
DPFX(DPFPREP, 2, "Changing loopback address to %s.", p_inet_ntoa(m_SocketAddress.IPSocketAddress.sin_addr));
m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr = pOtherIPAddress->m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr;
}
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPAddress::CopyInternalSocketAddressWithoutPort - copy socket address
// without the port field.
//
// Entry: Reference to destination address
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPAddress::CopyInternalSocketAddressWithoutPort"
void CIPAddress::CopyInternalSocketAddressWithoutPort( SOCKADDR &AddressDestination ) const
{
SOCKADDR_IN *pIPSocketAddress;
DNASSERT( SinZeroIsZero( &m_SocketAddress.IPSocketAddress ) != FALSE );
//
// copy address and zero out the port
//
DBG_CASSERT( sizeof( AddressDestination ) == sizeof( m_SocketAddress.SocketAddress ) );
memcpy( &AddressDestination, &m_SocketAddress.SocketAddress, sizeof( AddressDestination ) );
DBG_CASSERT( sizeof( SOCKADDR_IN* ) == sizeof( &AddressDestination ) );
pIPSocketAddress = reinterpret_cast<SOCKADDR_IN*>( &AddressDestination );
pIPSocketAddress->sin_port = p_htons( 0 );
}
//**********************************************************************