/*========================================================================== * * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved. * * File: SPAddress.cpp * Content: Winsock address base class * * * History: * Date By Reason * ==== == ====== * 01/20/1999 jtk Created * 05/12/1999 jtk Derived from modem endpoint class ***************************************************************************/ #include "dnwsocki.h" //********************************************************************** // Constant definitions //********************************************************************** // // maximum allowed hostname string size, in bytes, including NULL termination // #define MAX_HOSTNAME_SIZE 512 // // broadcast address as a string // const WCHAR g_IPBroadcastAddress[] = L"255.255.255.255"; const DWORD g_dwIPBroadcastAddressSize = sizeof( g_IPBroadcastAddress ); // // string for IP helper API // static const TCHAR c_tszIPHelperDLLName[] = TEXT("IPHLPAPI.DLL"); static const char c_szAdapterNameTemplate[] = "%s - %s"; #ifndef DPNBUILD_NOIPX // // length of IPX host names 'xxxxxxxx,xxxxxxxxxxxx' including NULL // #define IPX_ADDRESS_STRING_LENGTH 22 // // default broadcast and listen addresses // static const WCHAR g_IPXBroadcastAddress[] = L"00000000,FFFFFFFFFFFF"; static const WCHAR g_IPXListenAddress[] = L"00000000,000000000000"; // // string used for single IPX adapter // static const WCHAR g_IPXAdapterString[] = L"Local IPX Adapter"; #endif // ! DPNBUILD_NOIPX #ifndef DPNBUILD_NOIPV6 static const WCHAR c_wszIPv6AdapterNameTemplate[] = L"%s - IPv6 - %s"; static const WCHAR c_wszIPv4AdapterNameTemplate[] = L"%s - IPv4 - %s"; static const WCHAR c_wszIPv6AdapterNameNoDescTemplate[] = L"IPv6 - %s"; static const WCHAR c_wszIPv4AdapterNameNoDescTemplate[] = L"IPv4 - %s"; // // string used for IPv4 loopback adapter // static const WCHAR c_wszIPv4LoopbackAdapterString[] = L"IPv4 Loopback Adapter"; #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOMULTICAST // // 238.1.1.1 in network byte order // #define SAMPLE_MULTICAST_ADDRESS 0x010101EE #define INVALID_INTERFACE_INDEX -1 static const WCHAR c_wszPrivateScopeString[] = L"Private Multicast Scope - TTL " MULTICAST_TTL_PRIVATE_AS_STRING; static const WCHAR c_wszLocalScopeString[] = L"Local Multicast Scope - TTL " MULTICAST_TTL_LOCAL_AS_STRING; static const WCHAR c_wszGlobalScopeString[] = L"Global Multicast Scope - TTL " MULTICAST_TTL_GLOBAL_AS_STRING; #endif // ! DPNBUILD_NOMULTICAST //********************************************************************** // Macro definitions //********************************************************************** //********************************************************************** // Structure definitions //********************************************************************** #ifndef DPNBUILD_NOIPV6 typedef struct _SORTADAPTERADDRESS { SOCKADDR * psockaddr; WCHAR * pwszDescription; } SORTADAPTERADDRESS; #endif // ! DPNBUILD_NOIPV6 //********************************************************************** // Variable definitions //********************************************************************** //********************************************************************** // Function prototypes //********************************************************************** #ifndef DPNBUILD_ONLYONEADAPTER #ifndef DPNBUILD_NOWINSOCK2 typedef DWORD (WINAPI *PFNGETADAPTERSINFO)(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen); #ifndef DPNBUILD_NOMULTICAST typedef DWORD (WINAPI *PFNGETBESTINTERFACE)(IPAddr dwDestAddr, PDWORD pdwBestIfIndex); #endif // ! DPNBUILD_NOMULTICAST #ifndef DPNBUILD_NOIPV6 typedef DWORD (WINAPI *PFNGETADAPTERSADDRESSES)(ULONG ulFamily, DWORD dwFlags, PVOID pvReserved, PIP_ADAPTER_ADDRESSES pAdapterAddresses, PULONG pulOutBufLen); #endif // ! DPNBUILD_NOIPV6 #endif // ! DPNBUILD_NOWINSOCK2 #endif // ! DPNBUILD_ONLYONEADAPTER //********************************************************************** // Function definitions //********************************************************************** //********************************************************************** // ------------------------------ // CSocketAddress::InitializeWithBroadcastAddress - initialize with the IP broadcast address // // Entry: Nothing // // Exit: Nothing // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::InitializeWithBroadcastAddress" void CSocketAddress::InitializeWithBroadcastAddress( void ) { #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPX case AF_IPX: { DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress.sa_netnum ) == sizeof( DWORD ) ); *reinterpret_cast( m_SocketAddress.IPXSocketAddress.sa_netnum ) = 0x00000000; DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress.sa_nodenum ) == 6 ); DBG_CASSERT( sizeof( DWORD ) == 4 ); *reinterpret_cast( &m_SocketAddress.IPXSocketAddress.sa_nodenum ) = 0xFFFFFFFF; *reinterpret_cast( &m_SocketAddress.IPXSocketAddress.sa_nodenum[ 2 ] ) = 0xFFFFFFFF; break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) case AF_INET: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr = INADDR_BROADCAST; #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; } default: { // // We should never try to initialize an IPv6 address with the broadcast // address. We use IPv4 broadcast addresses, and then convert to the // IPv6 enum multicast address on the fly. // DNASSERT(FALSE); break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } } //********************************************************************** //********************************************************************** // ------------------------------ // CSocketAddress::SetAddressFromSOCKADDR - set address from a socket address // // Entry: Reference to address // Size of address // // Exit: Nothing // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::SetAddressFromSOCKADDR" void CSocketAddress::SetAddressFromSOCKADDR( const SOCKADDR *pAddress, const INT_PTR iAddressSize ) { DNASSERT( iAddressSize == GetAddressSize() ); memcpy( &m_SocketAddress.SocketAddress, pAddress, iAddressSize ); #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 case AF_INET6: { // // We don't validate anything in the address. // break; } #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOIPX case AF_IPX: { // // IPX addresses are only 14 of the 16 bytes in the socket address structure, // make sure the extra bytes are zero! // DNASSERT( m_SocketAddress.SocketAddress.sa_data[ 12 ] == 0 ); DNASSERT( m_SocketAddress.SocketAddress.sa_data[ 13 ] == 0 ); break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { // // Since Winsock won't guarantee that the sin_zero part of an IP address is // really zero, we need 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( &m_SocketAddress.IPSocketAddress.sin_zero[ 0 ] ) = 0; *reinterpret_cast( &m_SocketAddress.IPSocketAddress.sin_zero[ sizeof( DWORD ) ] ) = 0; #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } } //********************************************************************** //********************************************************************** // ------------------------------ // CSocketAddress::SocketAddressFromDP8Address - convert a DP8Address into a socket address // NOTE: The address object may be modified // // Entry: Pointer to DP8Address // Secure transport key ID, or NULL if none. // Whether name resoultion (potentially blocking) is allowed. // Address type // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::SocketAddressFromDP8Address" HRESULT CSocketAddress::SocketAddressFromDP8Address( IDirectPlay8Address *const pDP8Address, #ifdef DPNBUILD_XNETSECURITY ULONGLONG * const pullKeyID, #endif // DPNBUILD_XNETSECURITY #ifndef DPNBUILD_ONLYONETHREAD const BOOL fAllowNameResolution, #endif // ! DPNBUILD_ONLYONETHREAD const SP_ADDRESS_TYPE AddressType ) { HRESULT hr; HRESULT hTempResult; BYTE abBuffer[MAX_HOSTNAME_SIZE]; DWORD dwPort; DWORD dwTempSize; DWORD dwDataType; #ifndef DPNBUILD_ONLYONEADAPTER GUID AdapterGuid; #endif // ! DPNBUILD_ONLYONEADAPTER DPFX(DPFPREP, 8, "(0x%p) Parameters: (0x%p, %u)", this, pDP8Address, AddressType); // // initialize // hr = DPN_OK; #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPX case AF_IPX: { DNASSERT( pDP8Address != NULL ); #ifdef DPNBUILD_XNETSECURITY DNASSERT( pullKeyID == NULL ); #endif // DPNBUILD_XNETSECURITY // // the address type will determine how the address is handled // 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: { union { SOCKADDR SocketAddress; SOCKADDR_IPX IPXSocketAddress; #ifndef DPNBUILD_NOIPV6 SOCKADDR_STORAGE SocketAddressStorage; #endif // ! DPNBUILD_NOIPV6 } NetAddress; // // 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. // #ifndef DPNBUILD_NOIPV6 AddressFromGuid( &AdapterGuid, &NetAddress.SocketAddressStorage ); #else // ! DPNBUILD_NOIPV6 AddressFromGuid( &AdapterGuid, &NetAddress.SocketAddress ); #endif // ! DPNBUILD_NOIPV6 if ( NetAddress.IPXSocketAddress.sa_family != m_SocketAddress.IPXSocketAddress.sa_family ) { DNASSERT( FALSE ); hr = DPNERR_ADDRESSING; DPFX(DPFPREP, 0, "Invalid device guid!" ); goto Failure; } DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress ) == sizeof( NetAddress.IPXSocketAddress ) ); memcpy( &m_SocketAddress.IPXSocketAddress, &NetAddress.IPXSocketAddress, sizeof( m_SocketAddress.IPXSocketAddress ) ); m_SocketAddress.IPXSocketAddress.sa_socket = HTONS( static_cast( dwPort ) ); break; } // // hostname // case SP_ADDRESS_TYPE_HOST: { // // 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 ); m_SocketAddress.IPXSocketAddress.sa_socket = HTONS( static_cast( dwPort ) ); break; } // // port not present, fill in the appropriate default // case DPNERR_DOESNOTEXIST: { #ifdef DPNBUILD_SINGLEPROCESS const DWORD dwTempPort = BASE_DPLAY8_PORT; #else // ! DPNBUILD_SINGLEPROCESS const DWORD dwTempPort = DPNA_DPNSVR_PORT; #endif // ! DPNBUILD_SINGLEPROCESS m_SocketAddress.IPXSocketAddress.sa_socket = HTONS( static_cast( dwTempPort ) ); 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; } } // // attempt to determine host name // dwTempSize = sizeof(abBuffer); hr = IDirectPlay8Address_GetComponentByName( pDP8Address, DPNA_KEY_HOSTNAME, abBuffer, &dwTempSize, &dwDataType ); switch ( hr ) { // // keep the following codes and fail // case DPNERR_OUTOFMEMORY: case DPNERR_INCOMPLETEADDRESS: { goto Failure; break; } // // no problem // case DPN_OK: { switch (dwDataType) { case DPNA_DATATYPE_STRING: { BYTE abBuffer2[MAX_HOSTNAME_SIZE]; // // Unicode string, convert it to ANSI. // dwTempSize /= sizeof(WCHAR); hr = STR_jkWideToAnsi( (char*) abBuffer2, (WCHAR*) abBuffer, dwTempSize ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to convert hostname to ANSI!" ); DisplayDNError( 0, hr ); goto Failure; } strncpy((char*) abBuffer, (char*) abBuffer2, dwTempSize); // // Fall through... // } case DPNA_DATATYPE_STRING_ANSI: { long val; char temp[3]; char *a, *b; UINT_PTR uIndex; // // convert the text host name into the SOCKADDR structure // if ( dwTempSize != IPX_ADDRESS_STRING_LENGTH ) { DPFX(DPFPREP, 0, "Invalid IPX net/node. Must be %d bytes of ASCII hex (net,node:socket)", ( IPX_ADDRESS_STRING_LENGTH - 1 ) ); DPFX(DPFPREP, 0, "IPXAddressFromDP8Address: Failed to parse IPX host name!" ); goto Failure; } // we convert the string for the hostname field into the components temp[ 2 ] = 0; a = (char*) abBuffer; // the net number is 4 bytes for ( uIndex = 0; uIndex < 4; uIndex++ ) { strncpy( temp, a, 2 ); val = strtol( temp, &b, 16 ); m_SocketAddress.IPXSocketAddress.sa_netnum[ uIndex ] = (char) val; a += 2; } // followed by a dot a++; // the node is 6 bytes for ( uIndex = 0; uIndex < 6; uIndex++ ) { strncpy( temp, a, 2 ); val = strtol( temp, &b, 16 ); m_SocketAddress.IPXSocketAddress.sa_nodenum[ uIndex ] = (char) val; a += 2; } break; } default: { DPFX(DPFPREP, 0, "Hostname component wasn't a string (%u)!", dwDataType ); hr = DPNERR_ADDRESSING; goto Failure; break; } } break; } // // hostname does not exist, treat as an incomplete address // case DPNERR_DOESNOTEXIST: { hr = DPNERR_INCOMPLETEADDRESS; break; } // // remap other errors to an addressing error // default: { DNASSERT( FALSE ); hr = DPNERR_ADDRESSING; goto Failure; break; } } break; } // // unknown address type // default: { DNASSERT( FALSE ); break; } } break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) #ifndef DPNBUILD_NOIPV6 case AF_INET6: #endif // ! DPNBUILD_NOIPV6 default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { DNASSERT( pDP8Address != NULL ); 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: { union { SOCKADDR SocketAddress; SOCKADDR_IN INetAddress; #ifndef DPNBUILD_NOIPV6 SOCKADDR_IN6 INet6Address; SOCKADDR_STORAGE SocketAddressStorage; #endif // ! DPNBUILD_NOIPV6 } INetSocketAddress; #ifdef DPNBUILD_ONLYONEADAPTER XNADDR xnaddr; DWORD dwStatus; #else // ! DPNBUILD_ONLYONEADAPTER // // Ask for the adapter guid. If none is found, fail. // hTempResult = IDirectPlay8Address_GetDevice( pDP8Address, &AdapterGuid ); switch ( hTempResult ) { // // ok // case DPN_OK: { break; } // // remap missing component to 'addressing' error // case DPNERR_DOESNOTEXIST: { DPFX(DPFPREP, 0, "Device GUID does not exist!" ); DNASSERTX(! "Device GUID does not exist", 2); hr = DPNERR_ADDRESSING; goto Failure; break; } default: { DPFX(DPFPREP, 0, "Couldn't get device (0x%lx)!", hr ); hr = hTempResult; goto Failure; break; } } #endif // ! DPNBUILD_ONLYONEADAPTER // // 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: { DPFX(DPFPREP, 6, "Port component does not exist in address 0x%p.", pDP8Address ); 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: { DPFX(DPFPREP, 0, "Couldn't get port component (0x%lx)!", hr ); hr = hTempResult; goto Failure; break; } } DNASSERT( sizeof( dwPort ) == dwTempSize ); #ifdef DPNBUILD_ONLYONEADAPTER DNASSERT( GetFamily() == AF_INET ); // // Zero out the entire structure. This implies we use INADDR_ANY. // memset(&INetSocketAddress, 0, sizeof(INetSocketAddress)); dwStatus = XNetGetTitleXnAddr(&xnaddr); if ((dwStatus != XNET_GET_XNADDR_PENDING) && (dwStatus != XNET_GET_XNADDR_NONE)) { DPFX(DPFPREP, 5, "Using device %u.%u.%u.%u.", xnaddr.ina.S_un.S_un_b.s_b1, xnaddr.ina.S_un.S_un_b.s_b2, xnaddr.ina.S_un.S_un_b.s_b3, xnaddr.ina.S_un.S_un_b.s_b4); INetSocketAddress.INetAddress.sin_addr.S_un.S_addr = xnaddr.ina.S_un.S_addr; } else { DPFX(DPFPREP, 1, "Couldn't get XNet address, status = %u.", dwStatus); } #else // ! DPNBUILD_ONLYONEADAPTER // // convert the GUID to an address in temp space because the GUID is large enough to potentially hold // 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. // #ifdef DPNBUILD_NOIPV6 AddressFromGuid( &AdapterGuid, &INetSocketAddress.SocketAddress ); #else // ! DPNBUILD_NOIPV6 AddressFromGuid( &AdapterGuid, &INetSocketAddress.SocketAddressStorage ); #endif // ! DPNBUILD_NOIPV6 if ( ( INetSocketAddress.INetAddress.sin_family != AF_INET ) || ( reinterpret_cast( &INetSocketAddress.INetAddress.sin_zero[ 0 ] )[ 0 ] != 0 ) || ( reinterpret_cast( &INetSocketAddress.INetAddress.sin_zero[ 0 ] )[ 1 ] != 0 ) ) { #ifdef DPNBUILD_NOIPV6 hr = DPNERR_ADDRESSING; DPFX(DPFPREP, 0, "Invalid device guid!" ); goto Exit; #else // ! DPNBUILD_NOIPV6 // // Assume it is an IPv6 address. // SetFamilyProtocolAndSize(AF_INET6); AddressFromGuid( &AdapterGuid, &INetSocketAddress.SocketAddressStorage ); m_SocketAddress.IPv6SocketAddress.sin6_addr = INetSocketAddress.INet6Address.sin6_addr; m_SocketAddress.IPv6SocketAddress.sin6_port = HTONS( static_cast( dwPort ) ); m_SocketAddress.IPv6SocketAddress.sin6_scope_id = INetSocketAddress.INet6Address.sin6_scope_id; #endif // ! DPNBUILD_NOIPV6 } else #endif // ! DPNBUILD_ONLYONEADAPTER { m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr = INetSocketAddress.INetAddress.sin_addr.S_un.S_addr; m_SocketAddress.IPSocketAddress.sin_port = HTONS( static_cast( dwPort ) ); } break; } // // hostname // case SP_ADDRESS_TYPE_HOST: { // // 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: { #ifdef DPNBUILD_SINGLEPROCESS dwPort = BASE_DPLAY8_PORT; #else // ! DPNBUILD_SINGLEPROCESS dwPort = DPNA_DPNSVR_PORT; #endif // ! DPNBUILD_SINGLEPROCESS DPFX(DPFPREP, 6, "Port component does not exist in address 0x%p, defaulting to %u.", pDP8Address, dwPort ); break; } // // remap everything else to an addressing failure // default: { DPFX(DPFPREP, 0, "Couldn't get port component (0x%lx)!", hr ); hr = DPNERR_ADDRESSING; goto Failure; } } m_SocketAddress.IPSocketAddress.sin_port = HTONS( static_cast( dwPort ) ); // // get the host name // dwTempSize = sizeof(abBuffer); hTempResult = IDirectPlay8Address_GetComponentByName( pDP8Address, DPNA_KEY_HOSTNAME, abBuffer, &dwTempSize, &dwDataType ); switch ( hTempResult ) { // // host name present, convert from string to valid binary value // case DPN_OK: { switch (dwDataType) { case DPNA_DATATYPE_STRING: { BYTE abBuffer2[MAX_HOSTNAME_SIZE]; #ifdef DPNBUILD_XNETSECURITY // // The buffer should be large enough to hold an XNet address. // DBG_CASSERT(MAX_HOSTNAME_SIZE > ((sizeof(XNADDR) * 2) + 1) * sizeof(WCHAR)); #endif // DPNBUILD_XNETSECURITY // // Unicode string, convert it to ANSI. // dwTempSize /= sizeof(WCHAR); hr = STR_jkWideToAnsi( (char*) abBuffer2, (WCHAR*) abBuffer, dwTempSize ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to convert hostname to ANSI!" ); DisplayDNError( 0, hr ); goto Failure; } strncpy((char*) abBuffer, (char*) abBuffer2, dwTempSize); // // Fall through... // } case DPNA_DATATYPE_STRING_ANSI: { #ifdef DPNBUILD_XNETSECURITY // // This may be an XNet address. If we're allowed to check, and // the string is the right size, convert it. // if ((pullKeyID != NULL) && (dwTempSize == ((sizeof(XNADDR) * 2) + 1))) // 2 characters for every byte + NULL termination { char * pcCurrentSrc; XNADDR xnaddr; BYTE * pbCurrentDest; int iError; // // Convert all the hex characters into digits. // pcCurrentSrc = (char*) abBuffer; memset(&xnaddr, 0, sizeof(xnaddr)); for (pbCurrentDest = (BYTE*) &xnaddr; pbCurrentDest < (BYTE*) (&xnaddr + 1); pbCurrentDest++) { if (((*pcCurrentSrc) >= '0') && ((*pcCurrentSrc) <= '9')) { *pbCurrentDest = (*pcCurrentSrc) - '0'; } else if (((*pcCurrentSrc) >= 'a') && ((*pcCurrentSrc) <= 'f')) { *pbCurrentDest = (*pcCurrentSrc) - 'a' + 10; } else if (((*pcCurrentSrc) >= 'A') && ((*pcCurrentSrc) <= 'F')) { *pbCurrentDest = (*pcCurrentSrc) - 'A' + 10; } else { // // If the current character is not a valid hex digit // this is not a valid secure transport address. // break; } pcCurrentSrc++; *pbCurrentDest <<= 4; if (((*pcCurrentSrc) >= '0') && ((*pcCurrentSrc) <= '9')) { *pbCurrentDest += (*pcCurrentSrc) - '0'; } else if (((*pcCurrentSrc) >= 'a') && ((*pcCurrentSrc) <= 'f')) { *pbCurrentDest += (*pcCurrentSrc) - 'a' + 10; } else if (((*pcCurrentSrc) >= 'A') && ((*pcCurrentSrc) <= 'F')) { *pbCurrentDest += (*pcCurrentSrc) - 'A' + 10; } else { // // If the current character is not a valid hex digit // this is not a valid secure transport address. // break; } pcCurrentSrc++; } iError = XNetXnAddrToInAddr(&xnaddr, (XNKID*) pullKeyID, &m_SocketAddress.IPSocketAddress.sin_addr); if (iError == 0) { DNASSERT(hr == DPN_OK); goto Exit; } DPFX(DPFPREP, 1, "Couldn't convert XNet address \"%hs\" to InAddr (err = %i).", (char*) abBuffer, iError); DNASSERTX(! "Address exactly matching XNet address size and format failed to be converted!", 2); // // Continue on to trying to decode it as a // host name. // } else { // // XNet addresses should not be recognized, // or the string wasn't the right size. // } #endif // ! DPNBUILD_XNETSECURITY // // If we're here, it wasn't an XNet address. // #ifdef DPNBUILD_NOIPV6 // // Try to convert as a raw IPv4 address first. // m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr = inet_addr((char*) abBuffer); if ((m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr == INADDR_NONE) && (strcmp((char*) abBuffer, "255.255.255.255") != 0)) { #ifdef _XBOX #pragma TODO(vanceo, "Use Xbox specific name lookup if available") DPFX(DPFPREP, 0, "Unable to resolve IP address \"%hs\"!", (char*) abBuffer); DNASSERTX(! "Unable to resolve IP address!", 2); hr = DPNERR_INVALIDHOSTADDRESS; goto Failure; #else // ! _XBOX // // Converting raw IP failed, and it wasn't supposed to // be the broadcast address. Convert as a host name if // we're allowed. // #ifndef DPNBUILD_ONLYONETHREAD if (! fAllowNameResolution) { DPFX(DPFPREP, 2, "Couldn't convert \"%hs\" to IP address, not allowed to resolve as hostname.", (char*) abBuffer); hr = DPNERR_TIMEDOUT; } else #endif // ! DPNBUILD_ONLYONETHREAD { PHOSTENT phostent; phostent = gethostbyname((char*) abBuffer); if (phostent == NULL) { DPFX(DPFPREP, 0, "Couldn't get IP address from \"%hs\"!", (char*) abBuffer); DNASSERTX(! "Unable to resolve IP address!", 2); hr = DPNERR_INVALIDHOSTADDRESS; goto Failure; } // // Select the first IP address returned. // m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr = ((IN_ADDR*) (phostent->h_addr_list[0]))->S_un.S_addr; } #endif // ! _XBOX } else { DNASSERT(hr == DPN_OK); } #else // ! DPNBUILD_NOIPV6 char szPort[32]; addrinfo addrinfoHints; addrinfo * paddrinfoResult; addrinfo * paddrinfoCurrent; int iError; // // Try to convert the host name or raw address. // memset(&addrinfoHints, 0, sizeof(addrinfoHints)); if (! fAllowNameResolution) { addrinfoHints.ai_flags |= AI_NUMERICHOST; } addrinfoHints.ai_family = g_iIPAddressFamily; // IPv4, IPv6, or both addrinfoHints.ai_socktype = SOCK_DGRAM; addrinfoHints.ai_protocol = IPPROTO_UDP; //addrinfoHints.ai_addrlen = 0; //addrinfoHints.ai_canonname = NULL; //addrinfoHints.ai_addr = NULL; //addrinfoHints.ai_next = NULL; wsprintfA(szPort, "%u", dwPort); iError = getaddrinfo((char*) abBuffer, szPort, &addrinfoHints, &paddrinfoResult); if (iError == 0) { // // Pick the first valid address returned. // #pragma BUGBUG(vanceo, "Should we implement some mechanism to try the other results?") paddrinfoCurrent = paddrinfoResult; while (paddrinfoCurrent != NULL) { DNASSERT(paddrinfoCurrent->ai_addr != NULL); if ((paddrinfoCurrent->ai_addr->sa_family == AF_INET) || (paddrinfoCurrent->ai_addr->sa_family == AF_INET6)) { DNASSERT(paddrinfoCurrent->ai_addrlen <= sizeof(m_SocketAddress)); memcpy(&m_SocketAddress, paddrinfoCurrent->ai_addr, paddrinfoCurrent->ai_addrlen); m_iSocketAddressSize = paddrinfoCurrent->ai_addrlen; DNASSERT(GetPort() != 0); freeaddrinfo(paddrinfoResult); paddrinfoResult = NULL; DNASSERT(hr == DPN_OK); goto Exit; } DPFX(DPFPREP, 1, "Ignoring address family %u.", paddrinfoCurrent->ai_addr->sa_family); paddrinfoCurrent = paddrinfoCurrent->ai_next; } // // We didn't find any valid addresses. // DPFX(DPFPREP, 0, "Got address(es) from \"%hs\", but none were IP!", (char*) abBuffer); freeaddrinfo(paddrinfoResult); paddrinfoResult = NULL; hr = DPNERR_INVALIDHOSTADDRESS; goto Failure; } else { #ifndef DPNBUILD_ONLYONETHREAD if (! fAllowNameResolution) { DPFX(DPFPREP, 2, "Couldn't convert \"%hs\" to IP address (err = %i), not allowed to resolve as hostname.", (char*) abBuffer, iError); hr = DPNERR_TIMEDOUT; } else #endif // ! DPNBUILD_ONLYONETHREAD { DPFX(DPFPREP, 0, "Couldn't get IP address from \"%hs\" (err = %i)!", (char*) abBuffer, iError); DNASSERTX(! "Unable to resolve IP address!", 2); hr = DPNERR_INVALIDHOSTADDRESS; goto Failure; } } #endif // ! DPNBUILD_NOIPV6 break; } default: { DPFX(DPFPREP, 0, "Hostname component wasn't a string (%u)!", dwDataType ); hr = DPNERR_ADDRESSING; goto Failure; break; } } break; } // // return DPNERR_INCOMPLETEADDRESS if the host name didn't exist // case DPNERR_DOESNOTEXIST: { DPFX(DPFPREP, 6, "Hostname component does not exist in address 0x%p.", pDP8Address ); hr = DPNERR_INCOMPLETEADDRESS; goto Failure; } // // remap everything else to an addressing failure // default: { DPFX(DPFPREP, 0, "Couldn't get hostname component (0x%lx)!", hr ); hr = DPNERR_ADDRESSING; goto Failure; } } break; } // // unknown address type // default: { DNASSERT( FALSE ); break; } } #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } Exit: DPFX(DPFPREP, 8, "(0x%p) Returning [0x%lx]", this, hr); return hr; Failure: goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // CSocketAddress::DP8AddressFromSocketAddress - convert a socket address to a DP8Address // // Entry: Address type // // Exit: Pointer to DP8Address // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::DP8AddressFromSocketAddress" #ifdef DPNBUILD_XNETSECURITY IDirectPlay8Address *CSocketAddress::DP8AddressFromSocketAddress( ULONGLONG * const pullKeyID, const XNADDR * const pxnaddr, const SP_ADDRESS_TYPE AddressType ) const #else // ! DPNBUILD_XNETSECURITY IDirectPlay8Address *CSocketAddress::DP8AddressFromSocketAddress( const SP_ADDRESS_TYPE AddressType ) const #endif // ! DPNBUILD_XNETSECURITY { HRESULT hr; IDirectPlay8Address * pDP8Address; DWORD dwPort; // // initialize // hr = DPN_OK; pDP8Address = NULL; // // create and initialize the address // #ifdef DPNBUILD_LIBINTERFACE hr = DP8ACF_CreateInstance( IID_IDirectPlay8Address, reinterpret_cast( &pDP8Address ) ); #else // ! DPNBUILD_LIBINTERFACE hr = COM_CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, reinterpret_cast( &pDP8Address ), FALSE ); #endif // ! DPNBUILD_LIBINTERFACE if ( hr != S_OK ) { DNASSERT( pDP8Address == NULL ); DPFX(DPFPREP, 0, "Failed to create DP8Address when converting socket address" ); return NULL; } #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPX case AF_IPX: { #ifdef DPNBUILD_XNETSECURITY DNASSERT(pullKeyID == NULL); #endif // DPNBUILD_XNETSECURITY // // set SP // hr = IDirectPlay8Address_SetSP( pDP8Address, &CLSID_DP8SP_IPX ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to set SP type!" ); DisplayDNError( 0, hr ); goto FailureIPX; } // // add on the port because it's always set // dwPort = NTOHS( m_SocketAddress.IPXSocketAddress.sa_socket ); hr = IDirectPlay8Address_AddComponent( pDP8Address, DPNA_KEY_PORT, &dwPort, sizeof( dwPort ), DPNA_DATATYPE_DWORD ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to set port!" ); DisplayDNError( 0, hr ); goto FailureIPX; } // // add on the device or hostname depending on what type of address this is // switch ( AddressType ) { case SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT: case SP_ADDRESS_TYPE_DEVICE: { GUID DeviceGuid; GuidFromInternalAddressWithoutPort( &DeviceGuid ); hr = IDirectPlay8Address_AddComponent( pDP8Address, DPNA_KEY_DEVICE, &DeviceGuid, sizeof( DeviceGuid ), DPNA_DATATYPE_GUID ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to add device!" ); DisplayDNError( 0, hr ); goto FailureIPX; } break; } // // host address type // case SP_ADDRESS_TYPE_READ_HOST: case SP_ADDRESS_TYPE_HOST: { char HostName[ 255 ]; WCHAR WCharHostName[ sizeof( HostName ) ]; DWORD dwHostNameLength; DWORD dwWCharHostNameLength; // // remove constness of parameter for broken Socket API // dwHostNameLength = LENGTHOF( HostName ); if ( IPXAddressToStringNoSocket( const_cast( &m_SocketAddress.SocketAddress ), sizeof( m_SocketAddress.IPXSocketAddress ), HostName, &dwHostNameLength ) != 0 ) { DPFERR("Error returned from IPXAddressToString"); hr = DPNERR_ADDRESSING; goto ExitIPX; } // // convert ANSI host name to WCHAR // dwWCharHostNameLength = LENGTHOF( WCharHostName ); hr = STR_AnsiToWide( HostName, -1, WCharHostName, &dwWCharHostNameLength ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to convert hostname to WCHAR!" ); DisplayDNError( 0, hr ); goto FailureIPX; } hr = IDirectPlay8Address_AddComponent( pDP8Address, DPNA_KEY_HOSTNAME, WCharHostName, dwWCharHostNameLength * sizeof( WCHAR ), DPNA_DATATYPE_STRING ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to add hostname!" ); DisplayDNError( 0, hr ); goto FailureIPX; } break; } // // unknown address type // default: { DNASSERT( FALSE ); break; } } ExitIPX: return pDP8Address; FailureIPX: if ( pDP8Address != NULL ) { IDirectPlay8Address_Release( pDP8Address ); pDP8Address = NULL; } goto ExitIPX; break; } #endif // !DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) #ifndef DPNBUILD_NOIPV6 case AF_INET6: #endif // ! DPNBUILD_NOIPV6 default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_ONLYONESP // // set SP // hr = IDirectPlay8Address_SetSP( pDP8Address, &CLSID_DP8SP_TCPIP ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to set SP GUID!" ); DisplayDNError( 0, hr ); goto FailureIP; } #endif // ! DPNBUILD_ONLYONESP switch ( AddressType ) { case SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT: case SP_ADDRESS_TYPE_DEVICE: { #ifndef DPNBUILD_ONLYONEADAPTER GUID DeviceGuid; GuidFromInternalAddressWithoutPort( &DeviceGuid ); hr = IDirectPlay8Address_SetDevice( pDP8Address, &DeviceGuid ); if (hr != DPN_OK) { DPFX(DPFPREP, 0, "Couldn't add device GUID!"); goto FailureIP; } #endif // ! DPNBUILD_ONLYONEADAPTER break; } case SP_ADDRESS_TYPE_PUBLIC_HOST_ADDRESS: case SP_ADDRESS_TYPE_READ_HOST: case SP_ADDRESS_TYPE_HOST: #ifndef DPNBUILD_NOMULTICAST case SP_ADDRESS_TYPE_MULTICAST_GROUP: #endif // ! DPNBUILD_NOMULTICAST { TCHAR tszHostname[MAX_HOSTNAME_SIZE / sizeof(TCHAR)]; #ifdef DPNBUILD_XNETSECURITY TCHAR * ptszCurrent; BYTE * pbCurrent; DWORD dwTemp; // // The buffer should be large enough to hold an XNet address. // DBG_CASSERT(MAX_HOSTNAME_SIZE > ((sizeof(XNADDR) * 2) + 1) * sizeof(WCHAR)); #endif // DPNBUILD_XNETSECURITY #ifndef DPNBUILD_NOIPV6 if (GetFamily() == AF_INET6) { DBG_CASSERT((sizeof(tszHostname) / sizeof(TCHAR)) >= INET6_ADDRSTRLEN); #ifdef UNICODE DNIpv6AddressToStringW(&m_SocketAddress.IPv6SocketAddress.sin6_addr, tszHostname); #else // ! UNICODE Won't compile because we haven't implemented DNIpv6AddressToStringA #endif // ! UNICODE } else #endif // ! DPNBUILD_NOIPV6 { #ifdef DPNBUILD_XNETSECURITY if (pxnaddr != NULL) { ptszCurrent = tszHostname; pbCurrent = (BYTE*) pxnaddr; for(dwTemp = 0; dwTemp < sizeof(XNADDR); dwTemp++) { ptszCurrent += wsprintf(ptszCurrent, _T("%02X"), (*pbCurrent)); pbCurrent++; } } else if ((pullKeyID != NULL) && (m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr != INADDR_BROADCAST)) { int iError; XNADDR xnaddr; #ifdef DBG XNKID xnkid; #endif // DBG DBG_CASSERT(sizeof(xnkid) == sizeof(*pullKeyID)); #ifdef DPNBUILD_ONLYONEADAPTER IN_ADDR inaddrToUse; // // Special case 0.0.0.0, the XNet library expects the loopback address // instead when retrieving the local address. // inaddrToUse = m_SocketAddress.IPSocketAddress.sin_addr; if (inaddrToUse.S_un.S_addr == 0) { inaddrToUse.S_un.S_addr = IP_LOOPBACK_ADDRESS; } iError = XNetInAddrToXnAddr(inaddrToUse, #else // ! DPNBUILD_ONLYONEADAPTER iError = XNetInAddrToXnAddr(m_SocketAddress.IPSocketAddress.sin_addr, #endif // ! DPNBUILD_ONLYONEADAPTER &xnaddr, #ifdef DBG &xnkid); #else // ! DBG NULL); #endif // ! DBG if (iError != 0) { DPFX(DPFPREP, 0, "Converting XNet address to InAddr failed (err = %i)!", iError); DNASSERT(FALSE); //hr = DPNERR_NOCONNECTION; goto FailureIP; } #ifdef DPNBUILD_ONLYONEADAPTER if (inaddrToUse.S_un.S_addr != IP_LOOPBACK_ADDRESS) #endif // DPNBUILD_ONLYONEADAPTER { #ifdef DBG DNASSERT(memcmp(&xnkid, pullKeyID, sizeof(xnkid)) == 0); #endif // DBG } ptszCurrent = tszHostname; pbCurrent = (BYTE*) (&xnaddr); for(dwTemp = 0; dwTemp < sizeof(XNADDR); dwTemp++) { ptszCurrent += wsprintf(tszHostname, _T("%02X"), (*pbCurrent)); pbCurrent++; } } else #endif // DPNBUILD_XNETSECURITY { wsprintf(tszHostname, _T("%u.%u.%u.%u"), m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b1, m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b2, m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b3, m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b4); } } #ifdef UNICODE hr = IDirectPlay8Address_AddComponent( pDP8Address, DPNA_KEY_HOSTNAME, tszHostname, (_tcslen(tszHostname) + 1) * sizeof (TCHAR), DPNA_DATATYPE_STRING ); #else // ! UNICODE hr = IDirectPlay8Address_AddComponent( pDP8Address, DPNA_KEY_HOSTNAME, tszHostname, (_tcslen(tszHostname) + 1) * sizeof (TCHAR), DPNA_DATATYPE_STRING_ANSI ); #endif // ! UNICODE if (hr != DPN_OK) { DPFX(DPFPREP, 0, "Couldn't add hostname component!"); goto FailureIP; } break; } default: { DNASSERT( FALSE ); break; } } dwPort = NTOHS( m_SocketAddress.IPSocketAddress.sin_port ); hr = IDirectPlay8Address_AddComponent( pDP8Address, DPNA_KEY_PORT, &dwPort, (sizeof(dwPort)), DPNA_DATATYPE_DWORD ); if (hr != DPN_OK) { DPFX(DPFPREP, 0, "Couldn't add port component!"); goto FailureIP; } ExitIP: return pDP8Address; FailureIP: if ( pDP8Address != NULL ) { IDirectPlay8Address_Release( pDP8Address ); pDP8Address = NULL; } goto ExitIP; #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } } //********************************************************************** //********************************************************************** // ------------------------------ // CSocketAddress::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 "CSocketAddress::CompareToBaseAddress" INT_PTR CSocketAddress::CompareToBaseAddress( const SOCKADDR *const pBaseAddress ) const { DNASSERT( pBaseAddress != NULL ); #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 case AF_INET6: { const SOCKADDR_IN6 *pBaseIPv6Address; if ( pBaseAddress->sa_family != m_SocketAddress.SocketAddress.sa_family ) { DNASSERT(pBaseAddress->sa_family == AF_INET); return -1; } pBaseIPv6Address = reinterpret_cast( pBaseAddress ); return (memcmp(&m_SocketAddress.IPv6SocketAddress.sin6_addr, &pBaseIPv6Address->sin6_addr, sizeof(m_SocketAddress.IPv6SocketAddress.sin6_addr))); break; } #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOIPX case AF_IPX: { const SOCKADDR_IPX *pBaseIPXAddress; DNASSERT( pBaseAddress->sa_family == m_SocketAddress.SocketAddress.sa_family ); pBaseIPXAddress = reinterpret_cast( pBaseAddress ); DBG_CASSERT( OFFSETOF( SOCKADDR_IPX, sa_nodenum ) == OFFSETOF( SOCKADDR_IPX, sa_netnum ) + sizeof( pBaseIPXAddress->sa_netnum ) ); return memcmp( &m_SocketAddress.IPXSocketAddress.sa_nodenum, &pBaseIPXAddress->sa_nodenum, sizeof( pBaseIPXAddress->sa_nodenum ) ); break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { const SOCKADDR_IN *pBaseIPAddress; DNASSERT( GetFamily() == AF_INET ); #ifndef DPNBUILD_NOIPV6 if ( pBaseAddress->sa_family != m_SocketAddress.SocketAddress.sa_family ) { DNASSERT(pBaseAddress->sa_family == AF_INET6); return -1; } #endif // ! DPNBUILD_NOIPV6 pBaseIPAddress = reinterpret_cast( 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; } } #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } } //********************************************************************** #ifndef DPNBUILD_ONLYONEADAPTER //********************************************************************** // ------------------------------ // CSocketAddress::EnumAdapters - enumerate all of the adapters for this machine // // Entry: Pointer to enum adapters data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::EnumAdapters" HRESULT CSocketAddress::EnumAdapters( SPENUMADAPTERSDATA *const pEnumData ) const { #ifndef DPNBUILD_NOIPX if (GetFamily() == AF_IPX) { return EnumIPXAdapters(pEnumData); } else #endif // ! DPNBUILD_NOIPX { #ifdef DPNBUILD_NOIPV6 return EnumIPv4Adapters(pEnumData); #else // ! DPNBUILD_NOIPV6 return EnumIPv6and4Adapters(pEnumData); #endif // ! DPNBUILD_NOIPV6 } } //********************************************************************** #ifndef DPNBUILD_NOIPX //********************************************************************** // ------------------------------ // CSocketAddress::EnumIPXAdapters - enumerate all of the adapters for this machine // // Entry: Pointer to enum adapters data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::EnumIPXAdapters" HRESULT CSocketAddress::EnumIPXAdapters( SPENUMADAPTERSDATA *const pEnumData ) const { HRESULT hr; CPackedBuffer PackedBuffer; SOCKET TestSocket; INT iWSAReturn; DWORD dwAddressCount; union { SOCKADDR_IPX IPXSocketAddress; SOCKADDR SocketAddress; } SockAddr; // // initialize // hr = DPN_OK; DNASSERT( pEnumData != NULL ); // // initialize // DEBUG_ONLY( memset( pEnumData->pAdapterData, 0xAA, pEnumData->dwAdapterDataSize ) ); PackedBuffer.Initialize( pEnumData->pAdapterData, pEnumData->dwAdapterDataSize ); pEnumData->dwAdapterCount = 0; TestSocket = INVALID_SOCKET; dwAddressCount = 0; // // create a socket and attempt to query for all of the IPX addresses. If // that fails, fall back to using just the address from 'getsockname'. // TestSocket = socket( GetFamily(), SOCK_DGRAM, NSPROTO_IPX ); if ( TestSocket == INVALID_SOCKET ) { DWORD dwWSAError; hr = DPNERR_UNSUPPORTED; dwWSAError = WSAGetLastError(); DPFX(DPFPREP, 0, "Failed to create IPX socket when enumerating adapters!" ); DisplayWinsockError( 0, dwWSAError ); goto Failure; } memset( &SockAddr, 0x00, sizeof( SockAddr ) ); SockAddr.IPXSocketAddress.sa_family = GetFamily(); iWSAReturn = bind( TestSocket, &SockAddr.SocketAddress, sizeof( SockAddr.IPXSocketAddress ) ); if ( iWSAReturn == SOCKET_ERROR ) { DWORD dwWSAError; hr = DPNERR_OUTOFMEMORY; dwWSAError = WSAGetLastError(); DPFX(DPFPREP, 0, "Failed to bind IPX socket when enumerating adapters!" ); DisplayWinsockError( 0, dwWSAError ); goto Failure; } // // NOTE: THE CODE TO EXTRACT ALL IPX ADDRESSES ON NT HAS BEEN DISABLED BECAUSE // NT TREATS ALL OF THEM AS THE SAME ONCE THEY ARE BOUND TO THE NETWORK. IF THE // CORE IS ATTEMPTING TO BIND TO ALL ADAPTERS THIS WILL CAUSE ALL OF THE BINDS // AFTER THE FIRST TO FAIL! // // iIPXAdapterCount = 0; // iIPXAdapterCountSize = sizeof( iIPXAdapterCount ); // iWSAReturn = getsockopt( TestSocket, // NSPROTO_IPX, // IPX_MAX_ADAPTER_NUM, // reinterpret_cast( &iIPXAdapterCount ), // &iIPXAdapterCountSize ); // if ( iWSAReturn != 0 ) // { // DWORD dwWSAError; // // // dwWSAError = WSAGetLastError(); // switch ( dwWSAError ) // { // // // // can't enumerate adapters on this machine, fallback to getsockname() // // // case WSAENOPROTOOPT: // { INT iReturn; INT iSocketNameSize; union { SOCKADDR SocketAddress; SOCKADDR_IPX SocketAddressIPX; } SocketAddress; memset( &SocketAddress, 0x00, sizeof( SocketAddress ) ); iSocketNameSize = sizeof( SocketAddress ); iReturn = getsockname( TestSocket, &SocketAddress.SocketAddress, &iSocketNameSize ); if ( iReturn != 0 ) { DWORD dwWSAError; hr = DPNERR_OUTOFMEMORY; dwWSAError = WSAGetLastError(); DPFX(DPFPREP, 0, "Failed to get socket name enumerating IPX sockets!", dwWSAError ); goto Failure; } else { GUID SocketAddressGUID; SocketAddress.SocketAddressIPX.sa_socket = 0; GuidFromAddress( &SocketAddressGUID, &SocketAddress.SocketAddress ); DPFX(DPFPREP, 7, "Returning adapter 0: \"%ls\" {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}, flags = 0x0.", g_IPXAdapterString, SocketAddressGUID.Data1, SocketAddressGUID.Data2, SocketAddressGUID.Data3, SocketAddressGUID.Data4[0], SocketAddressGUID.Data4[1], SocketAddressGUID.Data4[2], SocketAddressGUID.Data4[3], SocketAddressGUID.Data4[4], SocketAddressGUID.Data4[5], SocketAddressGUID.Data4[6], SocketAddressGUID.Data4[7]); hr = AddInfoToBuffer( &PackedBuffer, g_IPXAdapterString, &SocketAddressGUID, 0 ); if ( ( hr != DPN_OK ) && ( hr != DPNERR_BUFFERTOOSMALL ) ) { DPFX(DPFPREP, 0, "Failed to add adapter (getsockname)!" ); DisplayDNError( 0, hr ); goto Failure; } dwAddressCount++; } // break; // } // // // // // other Winsock error // // // default: // { // DWORD dwWSAError; // // // hr = DPNERR_OUTOFMEMORY; // dwWSAError = WSAGetLastError(); // DPFX(DPFPREP, 0, "Failed to get IPX adapter count!" ); // DisplayWinsockError( 0, dwWSAError ); // goto Failure; // // break; // } // } // } // else // { // while ( iIPXAdapterCount != 0 ) // { // IPX_ADDRESS_DATA IPXData; // int iIPXDataSize; // // // iIPXAdapterCount--; // memset( &IPXData, 0x00, sizeof( IPXData ) ); // iIPXDataSize = sizeof( IPXData ); // IPXData.adapternum = iIPXAdapterCount; // // iWSAReturn = p_getsockopt( TestSocket, // NSPROTO_IPX, // IPX_ADDRESS, // reinterpret_cast( &IPXData ), // &iIPXDataSize ); // if ( iWSAReturn != 0 ) // { // DPFX(DPFPREP, 0, "Failed to get adapter information for adapter: 0x%x", ( iIPXAdapterCount + 1 ) ); // } // else // { // char Buffer[ 500 ]; // GUID SocketAddressGUID; // union // { // SOCKADDR_IPX IPXSocketAddress; // SOCKADDR SocketAddress; // } SocketAddress; // // // wsprintf( Buffer, // "IPX Adapter %d - (%02X%02X%02X%02X-%02X%02X%02X%02X%02X%02X)", // ( iIPXAdapterCount + 1 ), // IPXData.netnum[ 0 ], // IPXData.netnum[ 1 ], // IPXData.netnum[ 2 ], // IPXData.netnum[ 3 ], // IPXData.nodenum[ 0 ], // IPXData.nodenum[ 1 ], // IPXData.nodenum[ 2 ], // IPXData.nodenum[ 3 ], // IPXData.nodenum[ 4 ], // IPXData.nodenum[ 5 ] ); // // memset( &SocketAddress, 0x00, sizeof( SocketAddress ) ); // SocketAddress.IPXSocketAddress.sa_family = GetFamily(); // DBG_CASSERT( sizeof( SocketAddress.IPXSocketAddress.sa_netnum ) == sizeof( IPXData.netnum ) ); // memcpy( &SocketAddress.IPXSocketAddress.sa_netnum, IPXData.netnum, sizeof( SocketAddress.IPXSocketAddress.sa_netnum ) ); // DBG_CASSERT( sizeof( SocketAddress.IPXSocketAddress.sa_nodenum ) == sizeof( IPXData.nodenum ) ); // memcpy( &SocketAddress.IPXSocketAddress.sa_nodenum, IPXData.nodenum, sizeof( SocketAddress.IPXSocketAddress.sa_nodenum ) ); // GuidFromAddress( SocketAddressGUID, SocketAddress.SocketAddress ); // // hr = AddInfoToBuffer( &PackedBuffer, Buffer, &SocketAddressGUID, 0 ); // if ( ( hr != DPN_OK ) && ( hr != DPNERR_BUFFERTOOSMALL ) ) // { // DPFX(DPFPREP, 0, "Failed to add adapter (getsockname)!" ); // DisplayDNError( 0, hr ); // goto Failure; // } // // dwAddressCount++; // } // } // } // // // // if there was one adapter added, we can return 'All Adapters' // // // if ( dwAddressCount != 0 ) // { // dwAddressCount++; // hr = AddInfoToBuffer( &PackedBuffer, g_AllAdaptersString, &ALL_ADAPTERS_GUID, 0 ); // if ( ( hr != DPN_OK ) && ( hr != DPNERR_BUFFERTOOSMALL ) ) // { // DPFX(DPFPREP, 0, "Failed to add 'All Adapters'" ); // DisplayDNError( 0, hr ); // goto Failure; // } // } pEnumData->dwAdapterCount = dwAddressCount; pEnumData->dwAdapterDataSize = PackedBuffer.GetSizeRequired(); Exit: if ( TestSocket != INVALID_SOCKET ) { closesocket( TestSocket ); TestSocket = INVALID_SOCKET; } return hr; Failure: goto Exit; } //********************************************************************** #endif // ! DPNBUILD_NOIPX //********************************************************************** // ------------------------------ // CSocketAddress::EnumIPv4Adapters - enumerate all of the IPv4 adapters for this machine // // Entry: Pointer to enum adapters data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::EnumIPv4Adapters" HRESULT CSocketAddress::EnumIPv4Adapters( SPENUMADAPTERSDATA *const pEnumData ) const { HRESULT hr = DPN_OK; #if !defined(DPNBUILD_NOWINSOCK2) || defined(DBG) DWORD dwError; #endif // !DPNBUILD_NOWINSOCK2 OR DBG SOCKADDR_IN saddrinTemp; const HOSTENT * pHostData; IN_ADDR ** ppinaddrTemp; DWORD dwAddressCount; BOOL fFoundPrivateICS = FALSE; IN_ADDR * pinaddrBuffer = NULL; DWORD dwIndex; ULONG ulAdapterInfoBufferSize = 0; GUID guidAdapter; DWORD dwDeviceFlags; CPackedBuffer PackedBuffer; char acBuffer[512]; WCHAR wszIPAddress[512]; #ifndef DPNBUILD_NOWINSOCK2 HMODULE hIpHlpApiDLL; IP_ADAPTER_INFO * pCurrentAdapterInfo; PIP_ADDR_STRING pIPAddrString; PFNGETADAPTERSINFO pfnGetAdaptersInfo; IP_ADAPTER_INFO * pAdapterInfoBuffer = NULL; const char * pszIPAddress; #ifndef DPNBUILD_NOMULTICAST DWORD dwMcastInterfaceIndex; #endif // ! DPNBUILD_NOMULTICAST #endif // ! DPNBUILD_NOWINSOCK2 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 (gethostname(acBuffer, sizeof(acBuffer)) == SOCKET_ERROR) { #ifdef DBG dwError = WSAGetLastError(); DPFX(DPFPREP, 0, "Failed to get host name into fixed size buffer (err = %u)!", dwError); DisplayWinsockError(0, dwError); #endif // DBG hr = DPNERR_GENERIC; goto Failure; } pHostData = gethostbyname(acBuffer); if (pHostData == NULL) { #ifdef DBG dwError = WSAGetLastError(); DPFX(DPFPREP, 0, "Failed to get host data (err = %u)!", dwError); DisplayWinsockError(0, dwError); #endif // DBG 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 = IP_LOOPBACK_ADDRESS; 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. // #ifndef DPNBUILD_NOWINSOCK2 // // Load the IPHLPAPI module and get the adapter list if possible. // hIpHlpApiDLL = LoadLibrary(c_tszIPHelperDLLName); if (hIpHlpApiDLL != NULL) { #ifndef DPNBUILD_NOMULTICAST PFNGETBESTINTERFACE pfnGetBestInterface; pfnGetBestInterface = (PFNGETBESTINTERFACE) GetProcAddress(hIpHlpApiDLL, _TWINCE("GetBestInterface")); if (pfnGetBestInterface != NULL) { // // Ask IPHLPAPI for its opinion on the best multicast interface. // We use an arbitrary multicast address, and assume that the // TCP/IP stack doesn't treat individual multicast addresses // differently. // dwError = pfnGetBestInterface(SAMPLE_MULTICAST_ADDRESS, &dwMcastInterfaceIndex); if (dwError != ERROR_SUCCESS) { DPFX(DPFPREP, 0, "Couldn't determine best multicast interface index (err = %u)! Continuing.", dwError); dwMcastInterfaceIndex = INVALID_INTERFACE_INDEX; } else { DPFX(DPFPREP, 7, "Best interface for multicasting is index 0x%x.", dwMcastInterfaceIndex); } } else { dwError = GetLastError(); DPFX(DPFPREP, 0, "Couldn't load \"GetBestInterface\" function (err = %u)! Continuing.", dwError); } #endif // ! DPNBUILD_NOMULTICAST pfnGetAdaptersInfo = (PFNGETADAPTERSINFO) GetProcAddress(hIpHlpApiDLL, _TWINCE("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 DBG 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 = %hs, %hs, \"%hs\".", pCurrentAdapterInfo->Index, szIPList, pCurrentAdapterInfo->AdapterName, pCurrentAdapterInfo->Description); // // Go to next adapter. // pCurrentAdapterInfo = pCurrentAdapterInfo->Next; } } // end else (got valid buffer size) #endif // DBG break; } if ((dwError != ERROR_BUFFER_OVERFLOW) && (dwError != ERROR_INSUFFICIENT_BUFFER)) { 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 DBG dwError = GetLastError(); DPFX(DPFPREP, 0, "Failed to get proc address for GetAdaptersInfo!"); DisplayErrorCode(0, dwError); #endif // DBG // // Continue. We'll use the fallback to generate the names. // } // // We don't need the library anymore. // FreeLibrary(hIpHlpApiDLL); hIpHlpApiDLL = NULL; } else { #ifdef DBG dwError = GetLastError(); DPFX(DPFPREP, 0, "Failed to get proc address for GetAdaptersInfo!"); DisplayErrorCode(0, dwError); #endif // DBG // // Continue. We'll use the fallback to generate the names. // } #endif // !DPNBUILD_NOWINSOCK2 // // Loop through all IP addresses, generating names and GUIDs. // for(dwIndex = 0; dwIndex < dwAddressCount; dwIndex++) { // // Start off assuming this IP address won't have any special // flags. // dwDeviceFlags = 0; #ifndef DPNBUILD_NOMULTICAST // // If this is the first device and we couldn't use IPHLPAPI to // determine the best multicast interface, then just say the // default multicast interface is the first (for lack of a // better idea). // #ifdef DPNBUILD_NOWINSOCK2 if (dwIndex == 0) #else // ! DPNBUILD_NOWINSOCK2 if ((dwIndex == 0) && (dwMcastInterfaceIndex == INVALID_INTERFACE_INDEX)) #endif // ! DPNBUILD_NOWINSOCK2 { dwDeviceFlags |= DPNSPINFO_DEFAULTMULTICASTDEVICE; } #endif // ! DPNBUILD_NOMULTICAST #ifdef DPNBUILD_NOWINSOCK2 DNinet_ntow(pinaddrBuffer[dwIndex], wszIPAddress); #else // ! DPNBUILD_NOWINSOCK2 // // 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 = 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) { #ifndef DPNBUILD_NOMULTICAST // // If it's the interface reported earlier as the best // multicast interface, remember that fact. // if (pCurrentAdapterInfo->Index == dwMcastInterfaceIndex) { DPFX(DPFPREP, 7, "Found %hs under adapter index %u (\"%hs\"), and it's the best multicast interface.", pszIPAddress, pCurrentAdapterInfo->Index, pCurrentAdapterInfo->Description); DNASSERT(pCurrentAdapterInfo->Index != INVALID_INTERFACE_INDEX); dwDeviceFlags |= DPNSPINFO_DEFAULTMULTICASTDEVICE; } else #endif // ! DPNBUILD_NOMULTICAST { DPFX(DPFPREP, 9, "Found %hs under adapter index %u (\"%hs\").", pszIPAddress, pCurrentAdapterInfo->Index, pCurrentAdapterInfo->Description); } // // Build the name string. // DBG_CASSERT(sizeof(acBuffer) > MAX_ADAPTER_DESCRIPTION_LENGTH); 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. // } hr = STR_jkAnsiToWide(wszIPAddress, pszIPAddress, 512); if (FAILED(hr)) { DPFX(DPFPREP, 0, "Failed to convert adapter name to wide (err = 0x%lx)!", hr); DisplayDNError( 0, hr ); goto Failure; } #endif // ! DPNBUILD_NOWINSOCK2 // // Generate the GUID. // saddrinTemp.sin_addr = pinaddrBuffer[dwIndex]; GuidFromAddress(&guidAdapter, (SOCKADDR*) (&saddrinTemp)); DPFX(DPFPREP, 7, "Returning adapter %u: \"%ls\" {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}, flags = 0x%lx.", dwIndex, wszIPAddress, 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], dwDeviceFlags); // // Add adapter to buffer. // hr = AddInfoToBuffer(&PackedBuffer, wszIPAddress, &guidAdapter, dwDeviceFlags); 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; } } // end for (each IP address) // // 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: #ifndef DPNBUILD_NOWINSOCK2 if (pAdapterInfoBuffer != NULL) { DNFree(pAdapterInfoBuffer); pAdapterInfoBuffer = NULL; } #endif // !DPNBUILD_NOWINSOCK2 if (pinaddrBuffer != NULL) { DNFree(pinaddrBuffer); pinaddrBuffer = NULL; } DPFX(DPFPREP, 6, "Return [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** #ifndef DPNBUILD_NOIPV6 //********************************************************************** // ------------------------------ // CSocketAddress::EnumIPv6and4Adapters - enumerate all of the IPv6 and IPv4 adapters for this machine // // Entry: Pointer to enum adapters data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::EnumIPv6and4Adapters" HRESULT CSocketAddress::EnumIPv6and4Adapters( SPENUMADAPTERSDATA *const pEnumData ) const { HRESULT hr; DWORD dwError; HMODULE hIpHlpApiDLL = NULL; PFNGETADAPTERSADDRESSES pfnGetAdaptersAddresses; CPackedBuffer PackedBuffer; IP_ADAPTER_ADDRESSES * pIpAdapterAddresses = NULL; ULONG ulIpAdapterAddressesLength = 0; DWORD dwTotalNumIPv6Addresses = 0; DWORD dwTotalNumIPv4Addresses = 0; DWORD dwLongestDescription = 0; WCHAR * pwszBuffer = NULL; IP_ADAPTER_ADDRESSES * pIpAdapterAddressesCurrent; IP_ADAPTER_UNICAST_ADDRESS * pIpAdapterUnicastAddressCurrent; SORTADAPTERADDRESS * paSortAdapterAddress = NULL; DWORD dwNumIPv6Addresses = 0; DWORD dwNumIPv4Addresses = 0; BOOL fSkipIPv4Loopback = FALSE; BOOL fFoundIPv4Loopback = FALSE; SOCKADDR_IN saddrinLoopback; GUID guidAdapter; DWORD dwTemp; DWORD dwDeviceFlags; WCHAR wszIPAddress[INET6_ADDRSTRLEN]; DPFX(DPFPREP, 6, "Parameters: (0x%p)", pEnumData); PackedBuffer.Initialize( pEnumData->pAdapterData, pEnumData->dwAdapterDataSize ); // // Load the IPHLPAPI module and get the adapter list if possible. // hIpHlpApiDLL = LoadLibrary(c_tszIPHelperDLLName); if (hIpHlpApiDLL == NULL) { #ifdef DBG dwError = GetLastError(); DPFX(DPFPREP, 1, "Couldn't load IPHLPAPI, unable to look for IPv6 adapters (err = %u).", dwError); #endif // DBG // // Just enumerate IPv4 adapters. // hr = EnumIPv4Adapters(pEnumData); goto Exit; } pfnGetAdaptersAddresses = (PFNGETADAPTERSADDRESSES) GetProcAddress(hIpHlpApiDLL, _TWINCE("GetAdaptersAddresses")); if (pfnGetAdaptersAddresses == NULL) { #ifdef DBG dwError = GetLastError(); DPFX(DPFPREP, 1, "Couldn't find \"GetAdaptersAddresses\" function, unable to look for IPv6 adapters (err = %u).", dwError); #endif // DBG // // Just enumerate IPv4 adapters. // hr = EnumIPv4Adapters(pEnumData); goto Exit; } // // OK, we're on a platform where it's possible to look for both IPv6 & IPv4 adapters. // do { dwError = pfnGetAdaptersAddresses(g_iIPAddressFamily, (GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER), NULL, pIpAdapterAddresses, &ulIpAdapterAddressesLength); if (dwError == ERROR_SUCCESS) { // // We got all the info we're going to get. Make sure it was something. // if (ulIpAdapterAddressesLength < sizeof(IP_ADAPTER_ADDRESSES)) { DPFX(DPFPREP, 0, "GetAdaptersAddresses returned invalid size %u!", ulIpAdapterAddressesLength); // // Get rid of the buffer if allocated. // if (pIpAdapterAddresses != NULL) { DNFree(pIpAdapterAddresses); pIpAdapterAddresses = NULL; ulIpAdapterAddressesLength = 0; } // // Continue with exiting the loop. // } break; } if ((dwError != ERROR_BUFFER_OVERFLOW) && (dwError != ERROR_INSUFFICIENT_BUFFER)) { DPFX(DPFPREP, 0, "GetAdaptersAddresses failed (err = 0x%lx)!", dwError); hr = DPNERR_OUTOFMEMORY; // assume it's a resource issue goto Failure; } // // If we're here, then we need to reallocate the buffer. // if (pIpAdapterAddresses != NULL) { DNFree(pIpAdapterAddresses); pIpAdapterAddresses = NULL; } pIpAdapterAddresses = (IP_ADAPTER_ADDRESSES*) DNMalloc(ulIpAdapterAddressesLength); if (pIpAdapterAddresses == NULL) { DPFX(DPFPREP, 0, "Couldn't allocate memory for adapter list!"); hr = DPNERR_OUTOFMEMORY; goto Failure; } } while (TRUE); // // If there aren't any addresses, throw in the IPv4 loopback address. We will assume that // IPv4 is available because IPv6 should always report loopback/link local address and // therefore cause pIpAdapterAddresses to be allocated. If IPv6 is not available, then IPv4 // must be available otherwise we wouldn't have allowed this SP to be loaded. // // If there are addresses, loop through all the adapters we found to count them and to // figure out the longest description name. // if (pIpAdapterAddresses == NULL) { DNASSERT(pIpAdapterAddresses == NULL); dwTotalNumIPv4Addresses++; } else { pIpAdapterAddressesCurrent = pIpAdapterAddresses; while (pIpAdapterAddressesCurrent != NULL) { if (pIpAdapterAddressesCurrent->FriendlyName != NULL) { dwTemp = wcslen(pIpAdapterAddressesCurrent->FriendlyName); if (dwTemp > dwLongestDescription) { dwLongestDescription = dwTemp; } } else { if (pIpAdapterAddressesCurrent->Description != NULL) { dwTemp = wcslen(pIpAdapterAddressesCurrent->Description); if (dwTemp > dwLongestDescription) { dwLongestDescription = dwTemp; } } else { // // No friendly name or description. // } } // // Count the number of addresses. // pIpAdapterUnicastAddressCurrent = pIpAdapterAddressesCurrent->FirstUnicastAddress; while (pIpAdapterUnicastAddressCurrent != NULL) { DumpSocketAddress(8, pIpAdapterUnicastAddressCurrent->Address.lpSockaddr, pIpAdapterUnicastAddressCurrent->Address.lpSockaddr->sa_family); #pragma TODO(vanceo, "Option to allow non-preferred addresses? See below, too.") if (pIpAdapterUnicastAddressCurrent->DadState == IpDadStatePreferred) { if (pIpAdapterUnicastAddressCurrent->Address.lpSockaddr->sa_family == AF_INET6) { // // Skip the loopback pseudo-interface. Windows reports the true // loopback address, and then a link-local-looking address. We // don't care about the link-local one either because there should // be real link-local addresses available under other interfaces. // So completely jump out of the address loop when we see the // IPv6 loopback address. See sorting loop below as well. // if (IN6_IS_ADDR_LOOPBACK(&(((SOCKADDR_IN6*) pIpAdapterUnicastAddressCurrent->Address.lpSockaddr)->sin6_addr))) { DNASSERT(pIpAdapterUnicastAddressCurrent == pIpAdapterAddressesCurrent->FirstUnicastAddress); #pragma TODO(vanceo, "Are we sure we want to depend on the order the addresses are reported? See below, too.") break; } if ((IN6_IS_ADDR_LINKLOCAL(&(((SOCKADDR_IN6*) pIpAdapterUnicastAddressCurrent->Address.lpSockaddr)->sin6_addr))) || (IN6_IS_ADDR_SITELOCAL(&(((SOCKADDR_IN6*) pIpAdapterUnicastAddressCurrent->Address.lpSockaddr)->sin6_addr)))) { DNASSERT(((SOCKADDR_IN6*) pIpAdapterUnicastAddressCurrent->Address.lpSockaddr)->sin6_scope_id != 0); } dwTotalNumIPv6Addresses++; fSkipIPv4Loopback = TRUE; } else { DNASSERT(pIpAdapterUnicastAddressCurrent->Address.lpSockaddr->sa_family == AF_INET); // // Skip the IPv4 loopback address if there are other addresses. // if (((SOCKADDR_IN*) pIpAdapterUnicastAddressCurrent->Address.lpSockaddr)->sin_addr.S_un.S_addr != IP_LOOPBACK_ADDRESS) { fSkipIPv4Loopback = TRUE; } else { fFoundIPv4Loopback = TRUE; } dwTotalNumIPv4Addresses++; } } else { DPFX(DPFPREP, 7, "Skipping address whose state (%u) is not preferred.", pIpAdapterUnicastAddressCurrent->DadState); } pIpAdapterUnicastAddressCurrent = pIpAdapterUnicastAddressCurrent->Next; } pIpAdapterAddressesCurrent = pIpAdapterAddressesCurrent->Next; } // // If we found the IPv4 loopback address but we can skip it, decrement our IPv4 // address count. // if ((fFoundIPv4Loopback) && (fSkipIPv4Loopback)) { DNASSERT(dwTotalNumIPv4Addresses > 0); dwTotalNumIPv4Addresses--; } } // // Allocate a buffer to hold the largest friendly name + the other info we add to the // adapter description. INET6_ADDRSTRLEN is larger than INET_ADDRSTRLEN, and // includes NULL termination char (+ other things we don't actually use). // pwszBuffer = (WCHAR*) DNMalloc((dwLongestDescription + sizeof(c_wszIPv6AdapterNameTemplate) + INET6_ADDRSTRLEN) * sizeof(WCHAR)); if (pwszBuffer == NULL) { DPFX(DPFPREP, 0, "Couldn't allocate memory for name string!"); hr = DPNERR_OUTOFMEMORY; goto Failure; } paSortAdapterAddress = (SORTADAPTERADDRESS*) DNMalloc((dwTotalNumIPv6Addresses + dwTotalNumIPv4Addresses) * sizeof(SORTADAPTERADDRESS)); if (paSortAdapterAddress == NULL) { DPFX(DPFPREP, 0, "Couldn't allocate memory for sorted adapter list!"); hr = DPNERR_OUTOFMEMORY; goto Failure; } memset(paSortAdapterAddress, 0, ((dwTotalNumIPv6Addresses + dwTotalNumIPv4Addresses) * sizeof(SORTADAPTERADDRESS))); if (pIpAdapterAddresses == NULL) { memset(&saddrinLoopback, 0, sizeof(saddrinLoopback)); saddrinLoopback.sin_family = AF_INET; saddrinLoopback.sin_addr.S_un.S_addr = IP_LOOPBACK_ADDRESS; paSortAdapterAddress[0].psockaddr = (SOCKADDR*) &saddrinLoopback; paSortAdapterAddress[0].pwszDescription = (WCHAR*) c_wszIPv4LoopbackAdapterString; } else { // // Loop through all the adapters again to sort them. // The rules are (in order of precedence): // 1) Skip addresses that are not in the 'preferred' state. // 2) IPv6 before IPv4. // 3) Skip IPv6 loopback pseudo-interface. // 4) IPv4 ICS-private-adapter-looking IP addresses (192.168.0.1) first. // 5) Skip IPv4 loopback address (127.0.0.1) if we determined there were other addresses. // pIpAdapterAddressesCurrent = pIpAdapterAddresses; while (pIpAdapterAddressesCurrent != NULL) { pIpAdapterUnicastAddressCurrent = pIpAdapterAddressesCurrent->FirstUnicastAddress; while (pIpAdapterUnicastAddressCurrent != NULL) { if (pIpAdapterUnicastAddressCurrent->DadState == IpDadStatePreferred) { // // Insert IPv6 adapters in the first half of the array, IPv4 in the second half. // if (pIpAdapterUnicastAddressCurrent->Address.lpSockaddr->sa_family == AF_INET6) { SOCKADDR_IN6 * psaddrin6; psaddrin6 = (SOCKADDR_IN6*) pIpAdapterUnicastAddressCurrent->Address.lpSockaddr; // // Skip the loopback pseudo-interface as described earlier. // if (IN6_IS_ADDR_LOOPBACK(&psaddrin6->sin6_addr)) { break; } // // Save the pointers in the current slot. // paSortAdapterAddress[dwNumIPv6Addresses].psockaddr = (SOCKADDR*) psaddrin6; if (pIpAdapterAddressesCurrent->FriendlyName != NULL) { paSortAdapterAddress[dwNumIPv6Addresses].pwszDescription = pIpAdapterAddressesCurrent->FriendlyName; } else { if (pIpAdapterAddressesCurrent->Description != NULL) { paSortAdapterAddress[dwNumIPv6Addresses].pwszDescription = pIpAdapterAddressesCurrent->Description; } } DNASSERT(dwNumIPv6Addresses < dwTotalNumIPv6Addresses); dwNumIPv6Addresses++; } else { DNASSERT(pIpAdapterUnicastAddressCurrent->Address.lpSockaddr->sa_family == AF_INET); if ((((SOCKADDR_IN*) pIpAdapterUnicastAddressCurrent->Address.lpSockaddr)->sin_addr.S_un.S_addr != IP_LOOPBACK_ADDRESS) || (! fSkipIPv4Loopback)) { // // If this looks like an ICS private adapter and there are other adapters, put it first, // otherwise add to the end. // if ((((SOCKADDR_IN*) pIpAdapterUnicastAddressCurrent->Address.lpSockaddr)->sin_addr.S_un.S_addr == IP_PRIVATEICS_ADDRESS) && (dwNumIPv4Addresses > 0)) { // // Move all existing entries down one. // for(dwTemp = dwTotalNumIPv6Addresses + dwNumIPv4Addresses; dwTemp > dwTotalNumIPv6Addresses; dwTemp--) { memcpy(&paSortAdapterAddress[dwTemp], &paSortAdapterAddress[dwTemp - 1], sizeof(SORTADAPTERADDRESS)); } // // Add this new entry at the start of the IPv4 addresses. // paSortAdapterAddress[dwTotalNumIPv6Addresses].psockaddr = pIpAdapterUnicastAddressCurrent->Address.lpSockaddr; if (pIpAdapterAddressesCurrent->FriendlyName != NULL) { paSortAdapterAddress[dwTotalNumIPv6Addresses].pwszDescription = pIpAdapterAddressesCurrent->FriendlyName; } else { if (pIpAdapterAddressesCurrent->Description != NULL) { paSortAdapterAddress[dwTotalNumIPv6Addresses].pwszDescription = pIpAdapterAddressesCurrent->Description; } } } else { // // Add this entry at the current IPv4 address slot. // paSortAdapterAddress[dwTotalNumIPv6Addresses + dwNumIPv4Addresses].psockaddr = pIpAdapterUnicastAddressCurrent->Address.lpSockaddr; if (pIpAdapterAddressesCurrent->FriendlyName != NULL) { paSortAdapterAddress[dwTotalNumIPv6Addresses + dwNumIPv4Addresses].pwszDescription = pIpAdapterAddressesCurrent->FriendlyName; } else { if (pIpAdapterAddressesCurrent->Description != NULL) { paSortAdapterAddress[dwTotalNumIPv6Addresses + dwNumIPv4Addresses].pwszDescription = pIpAdapterAddressesCurrent->Description; } } } DNASSERT(dwNumIPv4Addresses < dwTotalNumIPv4Addresses); dwNumIPv4Addresses++; } else { // // Skip the IPv4 loopback address. // } } } else { // // Deprecated or otherwise non-preferred address. // } pIpAdapterUnicastAddressCurrent = pIpAdapterUnicastAddressCurrent->Next; } pIpAdapterAddressesCurrent = pIpAdapterAddressesCurrent->Next; } } // // Finally loop through the sorted adapters and store them in the buffer (or get size needed). // for(dwTemp = 0; dwTemp < dwTotalNumIPv6Addresses + dwTotalNumIPv4Addresses; dwTemp++) { // // Start off assuming this IP address won't have any special // flags. // dwDeviceFlags = 0; #pragma BUGBUG(vanceo, "Move to appropriate location so that turning on DPNBUILD_NOMULTICAST doesn't break") /* #ifndef DPNBUILD_NOMULTICAST // // If this is the first device and we couldn't use IPHLPAPI to // determine the best multicast interface, then just say the // default multicast interface is the first (for lack of a // better idea). // #ifdef DPNBUILD_NOWINSOCK2 if (dwIndex == 0) #else // ! DPNBUILD_NOWINSOCK2 if ((dwIndex == 0) && (dwMcastInterfaceIndex == INVALID_INTERFACE_INDEX)) #endif // ! DPNBUILD_NOWINSOCK2 { dwDeviceFlags |= DPNSPINFO_DEFAULTMULTICASTDEVICE; } #endif // ! DPNBUILD_NOMULTICAST */ // // Create a string representation of the IP address and generate the name. // if (paSortAdapterAddress[dwTemp].psockaddr->sa_family == AF_INET6) { DNIpv6AddressToStringW(&((SOCKADDR_IN6*) paSortAdapterAddress[dwTemp].psockaddr)->sin6_addr, wszIPAddress); if (paSortAdapterAddress[dwTemp].pwszDescription != NULL) { wsprintfW(pwszBuffer, c_wszIPv6AdapterNameTemplate, paSortAdapterAddress[dwTemp].pwszDescription, wszIPAddress); } else { wsprintfW(pwszBuffer, c_wszIPv6AdapterNameNoDescTemplate, wszIPAddress); } } else { DNinet_ntow(((SOCKADDR_IN*) paSortAdapterAddress[dwTemp].psockaddr)->sin_addr, wszIPAddress); if (paSortAdapterAddress[dwTemp].pwszDescription != NULL) { wsprintfW(pwszBuffer, c_wszIPv4AdapterNameTemplate, paSortAdapterAddress[dwTemp].pwszDescription, wszIPAddress); } else { wsprintfW(pwszBuffer, c_wszIPv4AdapterNameNoDescTemplate, wszIPAddress); } } // // Generate the GUID. // GuidFromAddress(&guidAdapter, paSortAdapterAddress[dwTemp].psockaddr); DPFX(DPFPREP, 7, "Returning adapter %u: \"%ls\" {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}, flags = 0x%lx.", dwTemp, pwszBuffer, 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], dwDeviceFlags); // // Add adapter to buffer. // hr = AddInfoToBuffer(&PackedBuffer, pwszBuffer, &guidAdapter, dwDeviceFlags); 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 = dwTotalNumIPv6Addresses + dwTotalNumIPv4Addresses; pEnumData->dwAdapterDataSize = PackedBuffer.GetSizeRequired(); Exit: if (paSortAdapterAddress != NULL) { DNFree(paSortAdapterAddress); paSortAdapterAddress = NULL; } if (pwszBuffer != NULL) { DNFree(pwszBuffer); pwszBuffer = NULL; } if (pIpAdapterAddresses != NULL) { DNFree(pIpAdapterAddresses); pIpAdapterAddresses = NULL; } if (hIpHlpApiDLL != NULL) { FreeLibrary(hIpHlpApiDLL); hIpHlpApiDLL = NULL; } DPFX(DPFPREP, 6, "Return [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** #endif // ! DPNBUILD_NOIPV6 #endif // ! DPNBUILD_ONLYONEADAPTER #ifndef DPNBUILD_NOMULTICAST //********************************************************************** // ------------------------------ // CSocketAddress::EnumMulticastScopes - enumerate all multicast scopes for an adapter // // Entry: Pointer to enum multicast scopes data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::EnumMulticastScopes" HRESULT CSocketAddress::EnumMulticastScopes( SPENUMMULTICASTSCOPESDATA *const pEnumData, BOOL const fUseMADCAP ) const { HRESULT hr; CPackedBuffer PackedBuffer; #ifdef DPNBUILD_NOIPV6 SOCKADDR saddrAdapter; #else // ! DPNBUILD_NOIPV6 SOCKADDR_STORAGE saddrAdapter; #endif // ! DPNBUILD_NOIPV6 SOCKET sTemp = INVALID_SOCKET; DWORD dwScopeCount = 0; #ifdef DBG DWORD dwError; #endif // DBG DPFX(DPFPREP, 6, "Parameters: (0x%p, %i)", pEnumData, fUseMADCAP); PackedBuffer.Initialize(pEnumData->pScopeData, pEnumData->dwScopeDataSize); #pragma TODO(vanceo, "Make IPv6 ready") AddressFromGuid(pEnumData->pguidAdapter, &saddrAdapter); // // Make sure the adapter is valid by asking WinSock. // sTemp = socket(GetFamily(), SOCK_DGRAM, IPPROTO_UDP); if (sTemp == INVALID_SOCKET) { #ifdef DBG dwError = WSAGetLastError(); DPFX(DPFPREP, 0, "Couldn't create temporary UDP socket (err = %u)!", dwError); DNASSERT(FALSE); #endif // DBG hr = DPNERR_GENERIC; goto Failure; } #ifndef DPNBUILD_NOIPV6 if (saddrAdapter.ss_family == AF_INET6) { saddrAdapter.ss_family = GetFamily(); #pragma TODO(vanceo, "Make IPv6 ready") } else #endif // ! DPNBUILD_NOIPV6 { ((SOCKADDR_IN*) (&saddrAdapter))->sin_family = GetFamily(); ((SOCKADDR_IN*) (&saddrAdapter))->sin_port = ANY_PORT; } if (bind(sTemp, (SOCKADDR*) (&saddrAdapter), sizeof(saddrAdapter)) != 0) { #ifdef DBG dwError = WSAGetLastError(); DPFX(DPFPREP, 0, "Adapter GUID is invalid (err = %u)!", dwError); DisplayWinsockError(0, dwError); DNASSERT(dwError == WSAEADDRNOTAVAIL); #endif // DBG hr = DPNERR_INVALIDDEVICEADDRESS; goto Failure; } closesocket(sTemp); sTemp = INVALID_SOCKET; // // The adapter is valid. First, fill in the 3 default multicast scopes. // hr = AddInfoToBuffer(&PackedBuffer, c_wszPrivateScopeString, &GUID_DP8MULTICASTSCOPE_PRIVATE, 0); if ((hr != DPN_OK) && (hr != DPNERR_BUFFERTOOSMALL)) { DPFX(DPFPREP, 0, "Failed to add private scope to buffer (err = 0x%lx)!", hr); DisplayDNError(0, hr); goto Failure; } DPFX(DPFPREP, 7, "Returning scope %u: \"%ls\" {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}.", dwScopeCount, c_wszPrivateScopeString, GUID_DP8MULTICASTSCOPE_PRIVATE.Data1, GUID_DP8MULTICASTSCOPE_PRIVATE.Data2, GUID_DP8MULTICASTSCOPE_PRIVATE.Data3, GUID_DP8MULTICASTSCOPE_PRIVATE.Data4[0], GUID_DP8MULTICASTSCOPE_PRIVATE.Data4[1], GUID_DP8MULTICASTSCOPE_PRIVATE.Data4[2], GUID_DP8MULTICASTSCOPE_PRIVATE.Data4[3], GUID_DP8MULTICASTSCOPE_PRIVATE.Data4[4], GUID_DP8MULTICASTSCOPE_PRIVATE.Data4[5], GUID_DP8MULTICASTSCOPE_PRIVATE.Data4[6], GUID_DP8MULTICASTSCOPE_PRIVATE.Data4[7]); dwScopeCount++; hr = AddInfoToBuffer(&PackedBuffer, c_wszLocalScopeString, &GUID_DP8MULTICASTSCOPE_LOCAL, 0); if ((hr != DPN_OK) && (hr != DPNERR_BUFFERTOOSMALL)) { DPFX(DPFPREP, 0, "Failed to add local scope to buffer (err = 0x%lx)!", hr); DisplayDNError(0, hr); goto Failure; } DPFX(DPFPREP, 7, "Returning scope %u: \"%ls\" {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}.", dwScopeCount, c_wszLocalScopeString, GUID_DP8MULTICASTSCOPE_LOCAL.Data1, GUID_DP8MULTICASTSCOPE_LOCAL.Data2, GUID_DP8MULTICASTSCOPE_LOCAL.Data3, GUID_DP8MULTICASTSCOPE_LOCAL.Data4[0], GUID_DP8MULTICASTSCOPE_LOCAL.Data4[1], GUID_DP8MULTICASTSCOPE_LOCAL.Data4[2], GUID_DP8MULTICASTSCOPE_LOCAL.Data4[3], GUID_DP8MULTICASTSCOPE_LOCAL.Data4[4], GUID_DP8MULTICASTSCOPE_LOCAL.Data4[5], GUID_DP8MULTICASTSCOPE_LOCAL.Data4[6], GUID_DP8MULTICASTSCOPE_LOCAL.Data4[7]); dwScopeCount++; hr = AddInfoToBuffer(&PackedBuffer, c_wszGlobalScopeString, &GUID_DP8MULTICASTSCOPE_GLOBAL, 0); if ((hr != DPN_OK) && (hr != DPNERR_BUFFERTOOSMALL)) { DPFX(DPFPREP, 0, "Failed to add global scope to buffer (err = 0x%lx)!", hr); DisplayDNError(0, hr); goto Failure; } DPFX(DPFPREP, 7, "Returning scope %u: \"%ls\" {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}.", dwScopeCount, c_wszGlobalScopeString, GUID_DP8MULTICASTSCOPE_GLOBAL.Data1, GUID_DP8MULTICASTSCOPE_GLOBAL.Data2, GUID_DP8MULTICASTSCOPE_GLOBAL.Data3, GUID_DP8MULTICASTSCOPE_GLOBAL.Data4[0], GUID_DP8MULTICASTSCOPE_GLOBAL.Data4[1], GUID_DP8MULTICASTSCOPE_GLOBAL.Data4[2], GUID_DP8MULTICASTSCOPE_GLOBAL.Data4[3], GUID_DP8MULTICASTSCOPE_GLOBAL.Data4[4], GUID_DP8MULTICASTSCOPE_GLOBAL.Data4[5], GUID_DP8MULTICASTSCOPE_GLOBAL.Data4[6], GUID_DP8MULTICASTSCOPE_GLOBAL.Data4[7]); dwScopeCount++; // // If this platform supports MADCAP, retrieve its list of scopes for // this adapter. // NOTE: This assumes MADCAP has been loaded by the thread pool // already. // #ifdef WINNT if (fUseMADCAP) { #ifndef DBG DWORD dwError; #endif // ! DBG PMCAST_SCOPE_ENTRY paScopes = NULL; DWORD dwScopesSize = 0; DWORD dwNumScopeEntries; DWORD dwTemp; WCHAR * pwszScratch; GUID guidScope; // // Determine how much room we need to hold the list of scopes. // dwError = McastEnumerateScopes(GetFamily(), TRUE, NULL, &dwScopesSize, &dwNumScopeEntries); if (((dwError == ERROR_SUCCESS) || (dwError == ERROR_MORE_DATA)) && (dwScopesSize >= sizeof(MCAST_SCOPE_ENTRY)) && (dwNumScopeEntries > 0)) { // // We want to add " - TTL xxx" to every string entry, so allocate // enough extra room for a scratch buffer for the largest possible // string plus that extra information. // dwTemp = dwScopesSize - (dwNumScopeEntries * sizeof(MCAST_SCOPE_ENTRY)) + (10 * sizeof(WCHAR)); paScopes = (PMCAST_SCOPE_ENTRY) DNMalloc(dwScopesSize + dwTemp); if (paScopes != NULL) { pwszScratch = (WCHAR*) (((BYTE*) (paScopes)) + dwScopesSize); // // Retrieve the list of scopes. // dwError = McastEnumerateScopes(GetFamily(), FALSE, paScopes, &dwScopesSize, &dwNumScopeEntries); if ((dwError == ERROR_SUCCESS) && (dwScopesSize >= sizeof(MCAST_SCOPE_ENTRY)) && (dwNumScopeEntries > 0)) { // // Look for scopes that match the device we were given. // for(dwTemp = 0; dwTemp < dwNumScopeEntries; dwTemp++) { BOOL fResult; #ifndef DPNBUILD_NOIPV6 if (GetFamily() == AF_INET6) { if (memcmp(&paScopes[dwTemp].ScopeCtx.Interface.IpAddrV6, &(((SOCKADDR_IN6*) (&saddrAdapter))->sin6_addr), sizeof(paScopes[dwTemp].ScopeCtx.Interface.IpAddrV6)) == 0) { fResult = TRUE; } else { fResult = FALSE; } } else #endif // ! DPNBUILD_NOIPV6 { if (paScopes[dwTemp].ScopeCtx.Interface.IpAddrV4 == ((SOCKADDR_IN*) (&saddrAdapter))->sin_addr.S_un.S_addr) { fResult = TRUE; } else { fResult = FALSE; } } if (fResult) { // // Encrypt the scope context and TTL as a GUID. // #ifdef DPNBUILD_NOIPV6 CSocketAddress::CreateScopeGuid(&(paScopes[dwTemp].ScopeCtx), #else // ! DPNBUILD_NOIPV6 CSocketAddress::CreateScopeGuid(GetFamily(), &(paScopes[dwTemp].ScopeCtx), #endif // ! DPNBUILD_NOIPV6 (BYTE) (paScopes[dwTemp].TTL), &guidScope); // // Use the scratch space at the end of our buffer to // append " - TTL xxx" to the description string. // wsprintfW(pwszScratch, L"%ls - TTL %u", paScopes[dwTemp].ScopeDesc.Buffer, (BYTE) (paScopes[dwTemp].TTL)); hr = AddInfoToBuffer(&PackedBuffer, pwszScratch, &guidScope, 0); if ((hr != DPN_OK) && (hr != DPNERR_BUFFERTOOSMALL)) { DPFX(DPFPREP, 0, "Failed to add scope \"%ls\" to buffer (err = 0x%lx)!", pwszScratch, hr); DisplayDNError(0, hr); DNFree(paScopes); paScopes = NULL; goto Failure; } DPFX(DPFPREP, 7, "Returning scope %u: \"%ls\" {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}.", dwScopeCount, pwszScratch, guidScope.Data1, guidScope.Data2, guidScope.Data3, guidScope.Data4[0], guidScope.Data4[1], guidScope.Data4[2], guidScope.Data4[3], guidScope.Data4[4], guidScope.Data4[5], guidScope.Data4[6], guidScope.Data4[7]); dwScopeCount++; } else { DPFX(DPFPREP, 7, "Ignoring scope \"%ls - TTL %u\" for different adapter.", paScopes[dwTemp].ScopeDesc.Buffer, paScopes[dwTemp].TTL); } } } else { DPFX(DPFPREP, 0, "Failed enumerating MADCAP scopes (err = %u, size %u, expected size %u, count %u)! Ignoring.", dwError, dwScopesSize, sizeof(MCAST_SCOPE_ENTRY), dwNumScopeEntries); } DNFree(paScopes); paScopes = NULL; } else { DPFX(DPFPREP, 0, "Failed allocating memory for MADCAP scopes! Ignoring."); } } else { DPFX(DPFPREP, 0, "Enumerating scopes for size required didn't return expected error or size (err = %u, size %u, expected size %u, count %u)! Ignoring.", dwError, dwScopesSize, sizeof(MCAST_SCOPE_ENTRY), dwNumScopeEntries); } } // end if (MADCAP should be used) else { DPFX(DPFPREP, 7, "Not enumerating MADCAP scopes."); } #endif // WINNT // // 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->dwScopeCount = dwScopeCount; pEnumData->dwScopeDataSize = PackedBuffer.GetSizeRequired(); Exit: DPFX(DPFPREP, 6, "Returning: [0x%lx]", hr); return hr; Failure: if (sTemp != INVALID_SOCKET) { closesocket(sTemp); sTemp = INVALID_SOCKET; } goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // CSocketAddress::SocketAddressFromMulticastDP8Address - convert a multicast style DP8Address into a socket address (may not be complete) // // Entry: Pointer to DP8Address // Place to store scope GUID. // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::SocketAddressFromMulticastDP8Address" HRESULT CSocketAddress::SocketAddressFromMulticastDP8Address( IDirectPlay8Address *const pDP8Address, #ifdef DPNBUILD_XNETSECURITY ULONGLONG * const pullKeyID, #endif // DPNBUILD_XNETSECURITY GUID * const pScopeGuid ) { HRESULT hr; WCHAR wszMulticastAddress[16]; // nnn.nnn.nnn.nnn + NULL termination char szMulticastAddress[16]; // nnn.nnn.nnn.nnn + NULL termination DWORD dwSize; DWORD dwDataType; DWORD dwPort; DNASSERT(pDP8Address != NULL); #ifdef DPNBUILD_XNETSECURITY #error ("Multicast doesn't currently support secure transport!") #endif // DPNBUILD_XNETSECURITY // // Get the multicast IP address, if it's there. // dwSize = sizeof(wszMulticastAddress); hr = IDirectPlay8Address_GetComponentByName(pDP8Address, DPNA_KEY_HOSTNAME, wszMulticastAddress, &dwSize, &dwDataType); if (hr == DPN_OK) { switch (dwDataType) { case DPNA_DATATYPE_STRING: { STR_jkWideToAnsi(szMulticastAddress, wszMulticastAddress, (sizeof(szMulticastAddress) / sizeof(char))); break; } case DPNA_DATATYPE_STRING_ANSI: { DWORD dwStrSize; // // For some reason, addressing returned the string as ANSI, // not Unicode. Not sure why this would happen, but go // ahead and convert it. // First make sure it's a reasonable size. // If you're wondering about the funkiness of this copying, // it's because PREfast goes a little overboard... // dwStrSize = (strlen((char*) wszMulticastAddress) + 1) * sizeof(char); DNASSERT(dwStrSize == dwSize); if (dwStrSize > (sizeof(szMulticastAddress) / sizeof(char))) { DPFX(DPFPREP, 0, "Unexpectedly long ANSI hostname string (%u bytes)!", dwStrSize); hr = DPNERR_INVALIDADDRESSFORMAT; goto Failure; } memcpy(szMulticastAddress, (char*) wszMulticastAddress, dwStrSize); break; } default: { DPFX(DPFPREP, 0, "Unexpected data type %u for hostname component!", dwDataType); hr = DPNERR_INVALIDADDRESSFORMAT; goto Failure; break; } } // // Convert the IP address string into an address. // m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr = inet_addr(szMulticastAddress); // // Make sure it's a valid multicast IP address. // if (! (IS_CLASSD_IPV4_ADDRESS(m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr))) { DPFX(DPFPREP, 0, "Hostname component \"%hs\" does not resolve to valid multicast IP address!", szMulticastAddress); hr = DPNERR_INVALIDHOSTADDRESS; goto Failure; } } else { DPFX(DPFPREP, 3, "Address didn't contain multicast hostname (err = 0x%lx).", hr); DNASSERT(m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr == INADDR_ANY); } // // Get the multicast port, if it's there. // dwSize = sizeof(dwPort); hr = IDirectPlay8Address_GetComponentByName(pDP8Address, DPNA_KEY_PORT, &dwPort, &dwSize, &dwDataType); if (hr == DPN_OK) { if (dwDataType != DPNA_DATATYPE_DWORD) { DPFX(DPFPREP, 0, "Unexpected data type %u for port component!", dwDataType); hr = DPNERR_INVALIDADDRESSFORMAT; goto Failure; } m_SocketAddress.IPSocketAddress.sin_port = HTONS((WORD) dwPort); } else { DPFX(DPFPREP, 3, "Address didn't contain multicast port (err = 0x%lx).", hr); DNASSERT(m_SocketAddress.IPSocketAddress.sin_port == ANY_PORT); } // // Get the multicast scope, if it's there. // dwSize = sizeof(*pScopeGuid); hr = IDirectPlay8Address_GetComponentByName(pDP8Address, DPNA_KEY_SCOPE, pScopeGuid, &dwSize, &dwDataType); if (hr == DPN_OK) { if (dwDataType != DPNA_DATATYPE_GUID) { DPFX(DPFPREP, 0, "Unexpected data type %u for scope component!", dwDataType); hr = DPNERR_INVALIDADDRESSFORMAT; goto Failure; } } else { DPFX(DPFPREP, 3, "Address didn't contain multicast scope (err = 0x%lx), using private scope.", hr); memcpy(pScopeGuid, &GUID_DP8MULTICASTSCOPE_PRIVATE, sizeof(*pScopeGuid)); } hr = DPN_OK; Exit: return hr; Failure: goto Exit; } //********************************************************************** #endif // ! DPNBUILD_NOMULTICAST //********************************************************************** // ------------------------------ // CSocketAddress::CompareFunction - compare against another address // // Entry: Pointer to other address // // Exit: Bool indicating equality of two addresses // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::CompareFunction" BOOL CSocketAddress::CompareFunction( PVOID pvKey1, PVOID pvKey2 ) { CSocketAddress* pAddress1 = (CSocketAddress*)pvKey1; CSocketAddress* pAddress2 = (CSocketAddress*)pvKey2; DNASSERT(pAddress1 != NULL); DNASSERT(pAddress2 != NULL); DNASSERT(pAddress1->GetFamily() == pAddress2->GetFamily()); #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (pAddress1->GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 case AF_INET6: { // // we need to compare the IPv6 address and port to guarantee uniqueness // if (IN6_ADDR_EQUAL(&(pAddress1->m_SocketAddress.IPv6SocketAddress.sin6_addr), &(pAddress2->m_SocketAddress.IPv6SocketAddress.sin6_addr))) { if ( pAddress1->m_SocketAddress.IPv6SocketAddress.sin6_port == pAddress2->m_SocketAddress.IPv6SocketAddress.sin6_port ) { return TRUE; } } return FALSE; break; } #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOIPX case AF_IPX: { // // We only need to compare: // netnumber (IPX network address) [ 4 bytes ] // nodenumber (netcard adapter address) [ 6 bytes ] // port [ 2 bytes ] // // Note that the nodenumber and port fields are sequentially arranged in the // address structure and can be compared with DWORDs // DBG_CASSERT( OFFSETOF( SOCKADDR_IPX, sa_nodenum ) == ( OFFSETOF( SOCKADDR_IPX, sa_netnum ) + sizeof( pAddress1->m_SocketAddress.IPXSocketAddress.sa_netnum ) ) ); DBG_CASSERT( OFFSETOF( SOCKADDR_IPX, sa_socket ) == ( OFFSETOF( SOCKADDR_IPX, sa_nodenum ) + sizeof( pAddress1->m_SocketAddress.IPXSocketAddress.sa_nodenum ) ) ); return memcmp( &pAddress1->m_SocketAddress.IPXSocketAddress.sa_netnum, pAddress2->m_SocketAddress.IPXSocketAddress.sa_netnum, ( sizeof( pAddress1->m_SocketAddress.IPXSocketAddress.sa_netnum ) + sizeof( pAddress1->m_SocketAddress.IPXSocketAddress.sa_nodenum ) + sizeof( pAddress1->m_SocketAddress.IPXSocketAddress.sa_socket ) ) ) == 0; break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { DNASSERT(pAddress1->GetFamily() == AF_INET); // // we need to compare the IP address and port to guarantee uniqueness // if ( pAddress1->m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr == pAddress2->m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr ) { if ( pAddress1->m_SocketAddress.IPSocketAddress.sin_port == pAddress2->m_SocketAddress.IPSocketAddress.sin_port ) { return TRUE; } } return FALSE; #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } } //********************************************************************** //********************************************************************** // ------------------------------ // CSocketAddress::HashFunction - hash address to N bits // // Entry: Count of bits to hash to // // Exit: Hashed value // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::HashFunction" DWORD CSocketAddress::HashFunction( PVOID pvKey, BYTE bBitDepth ) { DWORD dwReturn; UINT_PTR Temp; CSocketAddress* pAddress = (CSocketAddress*) pvKey; DNASSERT( bBitDepth != 0 ); DNASSERT( bBitDepth < 32 ); // // initialize // dwReturn = 0; #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (pAddress->GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 case AF_INET6: { DWORD dwTemp; // // hash IPv6 address // for(dwTemp = 0; dwTemp < (sizeof(pAddress->m_SocketAddress.IPv6SocketAddress.sin6_addr) / sizeof(UINT_PTR)); dwTemp++) { Temp = ((UINT_PTR*) (&pAddress->m_SocketAddress.IPv6SocketAddress.sin6_addr))[dwTemp]; do { dwReturn ^= Temp & ( ( 1 << bBitDepth ) - 1 ); Temp >>= bBitDepth; } while ( Temp != 0 ); } // // hash IPv6 port // Temp = pAddress->m_SocketAddress.IPv6SocketAddress.sin6_port; do { dwReturn ^= Temp & ( ( 1 << bBitDepth ) - 1 ); Temp >>= bBitDepth; } while ( Temp != 0 ); break; } #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOIPX case AF_IPX: { // // hash first DWORD of IPX address // Temp = *reinterpret_cast( &pAddress->m_SocketAddress.IPXSocketAddress.sa_nodenum[ 0 ] ); do { dwReturn ^= Temp & ( ( 1 << bBitDepth ) - 1 ); Temp >>= bBitDepth; } while ( Temp != 0 ); // // hash second DWORD of IPX address and IPX socket // Temp = *reinterpret_cast( &pAddress->m_SocketAddress.IPXSocketAddress.sa_nodenum[ sizeof( DWORD ) ] ); Temp += ( pAddress->m_SocketAddress.IPXSocketAddress.sa_socket << ( sizeof( WORD ) * 8 ) ); do { dwReturn ^= Temp & ( ( 1 << bBitDepth ) - 1 ); Temp >>= bBitDepth; } while ( Temp != 0 ); break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { DNASSERT(pAddress->GetFamily() == AF_INET); // // hash IP address // Temp = pAddress->m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr; do { dwReturn ^= Temp & ( ( 1 << bBitDepth ) - 1 ); Temp >>= bBitDepth; } while ( Temp != 0 ); // // hash IP port // Temp = pAddress->m_SocketAddress.IPSocketAddress.sin_port; do { dwReturn ^= Temp & ( ( 1 << bBitDepth ) - 1 ); Temp >>= bBitDepth; } while ( Temp != 0 ); #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } return dwReturn; } //********************************************************************** //********************************************************************** // ------------------------------ // CSocketAddress::GuidFromInternalAddressWithoutPort - get a guid from the internal // address without a port. // // Entry: Reference to desintation GUID // // Exit: Nothing // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::GuidFromInternalAddressWithoutPort" void CSocketAddress::GuidFromInternalAddressWithoutPort( GUID * pOutputGuid ) const { #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 case AF_INET6: { GuidFromAddress( pOutputGuid, &m_SocketAddress.SocketAddress ); break; } #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOIPX case AF_IPX: { union { SOCKADDR SockAddr; SOCKADDR_IPX IPXSockAddr; } TempSocketAddress; memcpy( &TempSocketAddress.SockAddr, &m_SocketAddress.SocketAddress, sizeof( TempSocketAddress.SockAddr ) ); TempSocketAddress.IPXSockAddr.sa_socket = 0; GuidFromAddress( pOutputGuid, &TempSocketAddress.SockAddr ); break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { union { SOCKADDR SockAddr; SOCKADDR_IN IPSockAddr; } TempSocketAddress; DNASSERT(GetFamily() == AF_INET); memcpy( &TempSocketAddress.SockAddr, &m_SocketAddress.SocketAddress, sizeof( TempSocketAddress.SockAddr ) ); TempSocketAddress.IPSockAddr.sin_port = 0; GuidFromAddress( pOutputGuid, &TempSocketAddress.SockAddr ); #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } } //********************************************************************** //********************************************************************** // ------------------------------ // CSocketAddress::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 "CSocketAddress::IsUndefinedHostAddress" BOOL CSocketAddress::IsUndefinedHostAddress( void ) const { BOOL fReturn; fReturn = FALSE; #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 case AF_INET6: { if (IN6_IS_ADDR_UNSPECIFIED(&m_SocketAddress.IPv6SocketAddress.sin6_addr)) { fReturn = TRUE; } break; } #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOIPX case AF_IPX: { DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress.sa_netnum ) == sizeof( DWORD ) ); DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress.sa_nodenum ) == 6 ); if ( ( *reinterpret_cast( &m_SocketAddress.IPXSocketAddress.sa_netnum ) == 0 ) && ( *reinterpret_cast( &m_SocketAddress.IPXSocketAddress.sa_nodenum ) == 0 ) && ( *reinterpret_cast( &m_SocketAddress.IPXSocketAddress.sa_nodenum[ 2 ] ) == 0 ) ) { fReturn = TRUE; } break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { if ( m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr == INADDR_ANY ) { fReturn = TRUE; } #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } return fReturn; } //********************************************************************** //********************************************************************** // ------------------------------ // CSocketAddress::IsValidUnicastAddress - determine if this is valid unicast address // address // // Entry: Whether to also allow the broadcast address or not. // // Exit: Boolean indicating whether this is a reachable address // TRUE = this is a reachable address // FALSE = this is not a reachable address // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::IsValidUnicastAddress" BOOL CSocketAddress::IsValidUnicastAddress( BOOL fAllowBroadcastAddress ) const { BOOL fReturn; fReturn = TRUE; #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 case AF_INET6: { // // Make sure the address is not all zeros. // if (IN6_IS_ADDR_UNSPECIFIED(&m_SocketAddress.IPv6SocketAddress.sin6_addr)) { fReturn = FALSE; DNASSERTX(! "IPv6 address is :: (all zeros)!", 2); } // // Make sure the address is not a multicast address, unless broadcast is allowed // and it's the special enum multicast address. // if (IN6_IS_ADDR_MULTICAST(&m_SocketAddress.IPv6SocketAddress.sin6_addr)) { if ((! fAllowBroadcastAddress) || (! IN6_ADDR_EQUAL(&m_SocketAddress.IPv6SocketAddress.sin6_addr, &c_in6addrEnumMulticast))) { fReturn = FALSE; DNASSERTX(! "IPv6 address is a multicast address!", 2); } } // // Disallow port 0. // if (m_SocketAddress.IPv6SocketAddress.sin6_port == 0) { fReturn = FALSE; DNASSERTX(! "IPv6 port is 0!", 2); } break; } #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOIPX case AF_IPX: { DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress.sa_netnum ) == sizeof( DWORD ) ); DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress.sa_nodenum ) == 6 ); if ( ( *reinterpret_cast( &m_SocketAddress.IPXSocketAddress.sa_netnum ) == 0 ) && ( *reinterpret_cast( &m_SocketAddress.IPXSocketAddress.sa_nodenum ) == 0 ) && ( *reinterpret_cast( &m_SocketAddress.IPXSocketAddress.sa_nodenum[ 2 ] ) == 0 ) ) { fReturn = FALSE; } if (m_SocketAddress.IPXSocketAddress.sa_socket == 0) { fReturn = FALSE; DNASSERTX(! "IPX socket/port is 0!", 2); } break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { // // Disallow 0.0.0.0, and multicast addresses 224.0.0.0 - 239.255.255.255. // if ( ( m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr == INADDR_ANY ) || ( IS_CLASSD_IPV4_ADDRESS( m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr ) ) ) { fReturn = FALSE; DNASSERTX(! "IPv4 address is 0.0.0.0 or multicast!", 2); } // // Prevent the broadcast address, unless caller allows it. // if ( ( ! fAllowBroadcastAddress ) && ( m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr == INADDR_BROADCAST ) ) { fReturn = FALSE; DNASSERTX(! "IPv4 address is broadcast!", 2); } // // Disallow ports 0, 1900 (SSDP), 2234 (PAST), and 47624 (DPlay4). // if ( ( m_SocketAddress.IPSocketAddress.sin_port == HTONS( 0 ) ) || ( m_SocketAddress.IPSocketAddress.sin_port == HTONS( 1900 ) ) || ( m_SocketAddress.IPSocketAddress.sin_port == HTONS( 2234 ) ) || ( m_SocketAddress.IPSocketAddress.sin_port == HTONS( 47624 ) ) ) { fReturn = FALSE; DNASSERTX(! "IPv4 port is 0, 1900, 2234, or 47624!", 2); } #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } return fReturn; } //********************************************************************** #ifndef DPNBUILD_NOREGISTRY //********************************************************************** // ------------------------------ // CSocketAddress::IsBannedAddress - determine if this is a banned address // // Entry: Nothing // // Exit: Boolean indicating whether this is a banned address // TRUE = this is a banned address // FALSE = this is not a banned address // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::IsBannedAddress" BOOL CSocketAddress::IsBannedAddress( void ) const { BOOL fReturn; fReturn = FALSE; #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 case AF_INET6: { break; } #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOIPX case AF_IPX: { break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { if (g_pHashBannedIPv4Addresses != NULL) { DWORD dwAddr; DWORD dwBit; PVOID pvMask; // // Try matching the IP address using masks. // Start with a 32 bit mask (meaning match the IP address exactly) // and gradually relax the mask until we get to a class A mask. // We expect the network byte order of the IP address to be the // opposite of host byte order. // dwAddr = m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr; for(dwBit = 0x80000000; dwBit >= 0x00000080; dwBit >>= 1) { // // Only hash based on this mask if we read in at least one entry that used it. // if (dwBit & g_dwBannedIPv4Masks) { if (g_pHashBannedIPv4Addresses->Find((PVOID) ((DWORD_PTR) dwAddr), &pvMask)) { DNASSERT(((DWORD) ((DWORD_PTR) pvMask)) & dwBit); DPFX(DPFPREP, 7, "Address %u.%u.%u.%u is banned (found as 0x%08x, bit 0x%08x).", m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b1, m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b2, m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b3, m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b4, dwAddr, dwBit); fReturn = TRUE; break; } } dwAddr &= ~dwBit; } } #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } return fReturn; } //********************************************************************** #endif // ! DPNBUILD_NOREGISTRY //********************************************************************** // ------------------------------ // CSocketAddress::ChangeLoopBackToLocalAddress - change loopback to a local address // // Entry: Pointer to other address // // Exit: Nothing // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::ChangeLoopBackToLocalAddress" void CSocketAddress::ChangeLoopBackToLocalAddress( const CSocketAddress *const pOtherSocketAddress ) { #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (pOtherSocketAddress->GetFamily()) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 case AF_INET6: { if (GetFamily() == AF_INET6) { SOCKADDR_IN6 *psaddrin6; psaddrin6 = (SOCKADDR_IN6*) GetAddress(); if (IN6_IS_ADDR_LOOPBACK(&psaddrin6->sin6_addr)) { memcpy(&psaddrin6->sin6_addr, &(((SOCKADDR_IN6*) pOtherSocketAddress->GetAddress())->sin6_addr), sizeof(psaddrin6->sin6_addr)); psaddrin6->sin6_scope_id = ((SOCKADDR_IN6*) pOtherSocketAddress->GetAddress())->sin6_scope_id; DPFX(DPFPREP, 2, "Changing IPv6 loopback address to:" ); DumpSocketAddress( 2, (SOCKADDR*) psaddrin6, AF_INET6 ); } } break; } #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOIPX case AF_IPX: { DNASSERT( pOtherSocketAddress != NULL ); // // there is no 'loopback' for IPX so this function doesn't do anything // break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 if (GetFamily() == AF_INET) #endif // ! DPNBUILD_NOIPV6 { if ( m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr == IP_LOOPBACK_ADDRESS ) { DPFX(DPFPREP, 2, "Changing IPv4 loopback address to %u.%u.%u.%u.", m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b1, m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b2, m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b3, m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_un_b.s_b4); m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr = pOtherSocketAddress->m_SocketAddress.IPSocketAddress.sin_addr.S_un.S_addr; } } #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } } //********************************************************************** //********************************************************************** // ------------------------------ // EncryptGuid - encrypt a guid // // Entry: Pointer to source guid // Pointer to destination guid // Pointer to encryption key // // Exit: Nothing // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "EncryptGuid" void EncryptGuid( const GUID *const pSourceGuid, GUID *const pDestinationGuid, const GUID *const pEncryptionKey ) { const char *pSourceBytes; char *pDestinationBytes; const char *pEncryptionBytes; DWORD_PTR dwIndex; DNASSERT( pSourceGuid != NULL ); DNASSERT( pDestinationGuid != NULL ); DNASSERT( pEncryptionKey != NULL ); DBG_CASSERT( sizeof( pSourceBytes ) == sizeof( pSourceGuid ) ); pSourceBytes = reinterpret_cast( pSourceGuid ); DBG_CASSERT( sizeof( pDestinationBytes ) == sizeof( pDestinationGuid ) ); pDestinationBytes = reinterpret_cast( pDestinationGuid ); DBG_CASSERT( sizeof( pEncryptionBytes ) == sizeof( pEncryptionKey ) ); pEncryptionBytes = reinterpret_cast( pEncryptionKey ); DBG_CASSERT( ( sizeof( *pSourceGuid ) == sizeof( *pEncryptionKey ) ) && ( sizeof( *pDestinationGuid ) == sizeof( *pEncryptionKey ) ) ); dwIndex = sizeof( *pSourceGuid ); while ( dwIndex != 0 ) { dwIndex--; pDestinationBytes[ dwIndex ] = pSourceBytes[ dwIndex ] ^ pEncryptionBytes[ dwIndex ]; } } //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::GuidFromAddress" void CSocketAddress::GuidFromAddress( GUID * pOutputGuid, const SOCKADDR * pSocketAddress ) const { #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (pSocketAddress->sa_family) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 case AF_INET6: { const SOCKADDR_IN6 *pSocketAddressIPv6 = reinterpret_cast( pSocketAddress ); DNASSERT((GetFamily() == AF_INET) || (GetFamily() == AF_INET6)); DBG_CASSERT(sizeof(pSocketAddressIPv6->sin6_addr) == sizeof(GUID)); // // Hopefully the beginning of IPv6 addresses will never look like an IPv4 // socket family so our unpacking routine won't get confused. // DNASSERT(((SOCKADDR*) (&pSocketAddressIPv6->sin6_addr))->sa_family != AF_INET); // // Even though IPv6 addresses are already 128 bits long and fill an entire // entire GUID, we need to somehow pack the scope ID for link local and // site local addresses into the GUID as well. We do this by storing the // scope ID in bytes 3-6. This is because the prefix identifier for link local // addresses is FE80::/64, and for site local addresses is FEC0::/48, // leaving us 38 bits of what should always be zeros after the 10 bit prefix // headers. We round to 16 to get to the WORD boundary, and therefore // have a handy 32 bits left. // if ((IN6_IS_ADDR_LINKLOCAL(&pSocketAddressIPv6->sin6_addr)) || (IN6_IS_ADDR_SITELOCAL(&pSocketAddressIPv6->sin6_addr))) { GUID guidTemp; WORD * pawSrcAddr; WORD * pawDstAddr; memcpy(&guidTemp, &pSocketAddressIPv6->sin6_addr, sizeof(GUID)); // // Assert that the scope is not 0 and that bits 17-48 really are zero. // Then copy the scope ID. // The destination bits are WORD, but not DWORD aligned. // DNASSERT(pSocketAddressIPv6->sin6_scope_id != 0); pawSrcAddr = (WORD*) (&pSocketAddressIPv6->sin6_scope_id); pawDstAddr = (WORD*) (&guidTemp); DBG_CASSERT(sizeof(pSocketAddressIPv6->sin6_scope_id) == 4); DNASSERT((pawDstAddr[1] == 0) && (pawDstAddr[2] == 0)); pawDstAddr[1] = pawSrcAddr[0]; pawDstAddr[2] = pawSrcAddr[1]; EncryptGuid( &guidTemp, pOutputGuid, &g_IPSPEncryptionGuid ); } else { EncryptGuid( (GUID*) (&pSocketAddressIPv6->sin6_addr), pOutputGuid, &g_IPSPEncryptionGuid ); } break; } #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOIPX case AF_IPX: { const SOCKADDR_IPX *pSocketAddressIPX = reinterpret_cast( pSocketAddress ); DNASSERT(GetFamily() == AF_IPX); memcpy( pOutputGuid, pSocketAddressIPX, sizeof( *pSocketAddressIPX ) ); memset( &( reinterpret_cast( pOutputGuid )[ sizeof( *pSocketAddressIPX ) ] ), 0, ( sizeof( *pOutputGuid ) - sizeof( *pSocketAddressIPX ) ) ); EncryptGuid( pOutputGuid, pOutputGuid, &g_IPXSPEncryptionGuid ); break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { const SOCKADDR_IN *pSocketAddressIP = reinterpret_cast( pSocketAddress ); DNASSERT(GetFamily() == AF_INET); memcpy( pOutputGuid, pSocketAddressIP, ( sizeof( *pOutputGuid ) - sizeof( pSocketAddressIP->sin_zero ) ) ); memset( &( reinterpret_cast( pOutputGuid )[ OFFSETOF( SOCKADDR_IN, sin_zero ) ] ), 0, sizeof( pSocketAddressIP->sin_zero ) ); EncryptGuid( pOutputGuid, pOutputGuid, &g_IPSPEncryptionGuid ); #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } } #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::PoolAllocFunction" BOOL CSocketAddress::PoolAllocFunction( void* pvItem, void* pvContext ) { CSocketAddress* pAddress = (CSocketAddress*)pvItem; // Base class pAddress->m_Sig[0] = 'S'; pAddress->m_Sig[1] = 'P'; pAddress->m_Sig[2] = 'A'; pAddress->m_Sig[3] = 'D'; return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::PoolGetFunction" void CSocketAddress::PoolGetFunction( void* pvItem, void* pvContext ) { CSocketAddress* pAddress = (CSocketAddress*)pvItem; // // The context is the socket address type if IPv6 and/or IPX are available in // this build. If neither are available, it will be NULL, but SetFamilyProtocolAndSize // should ignore the value. // pAddress->SetFamilyProtocolAndSize((short)(DWORD_PTR)pvContext); } #undef DPF_MODNAME #define DPF_MODNAME "CSocketAddress::PoolReturnFunction" void CSocketAddress::PoolReturnFunction( void* pvItem ) { #ifdef DBG const CSocketAddress* pAddress = (CSocketAddress*)pvItem; #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) switch (pAddress->m_SocketAddress.SocketAddress.sa_family) #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { #ifndef DPNBUILD_NOIPV6 case AF_INET6: { DNASSERT( pAddress->m_iSocketAddressSize == sizeof( pAddress->m_SocketAddress.IPv6SocketAddress ) ); DNASSERT( pAddress->m_SocketAddress.IPSocketAddress.sin_family == AF_INET6 ); DNASSERT( pAddress->m_iSocketProtocol == IPPROTO_UDP ); break; } #endif // ! DPNBUILD_NOIPV6 #ifndef DPNBUILD_NOIPX case AF_IPX: { DNASSERT( pAddress->m_iSocketAddressSize == sizeof( pAddress->m_SocketAddress.IPXSocketAddress ) ); DNASSERT( pAddress->m_SocketAddress.IPXSocketAddress.sa_family == AF_IPX ); DNASSERT( pAddress->m_iSocketProtocol == NSPROTO_IPX ); break; } #endif // ! DPNBUILD_NOIPX #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) default: #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX { DNASSERT( pAddress->m_iSocketAddressSize == sizeof( pAddress->m_SocketAddress.IPSocketAddress ) ); DNASSERT( pAddress->m_SocketAddress.IPSocketAddress.sin_family == AF_INET ); DNASSERT( pAddress->m_iSocketProtocol == IPPROTO_UDP ); #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX))) break; #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX } } #endif // DBG }