2020-09-30 16:53:49 +02:00

1502 lines
42 KiB
C++

/*==========================================================================
*
* Copyright (C) 1998-2000 Microsoft Corporation. All Rights Reserved.
*
* File: IPXAddress.cpp
* Content: Winsock IPX address class
*
*
* History:
* Date By Reason
* ==== == ======
* 01/20/99 jtk Created
* 05/12/99 jtk Derived from modem endpoint class
* 01/10/20000 rmt Updated to build with Millenium build process
* 03/22/20000 jtk Updated with changes to interface names
***************************************************************************/
#include "dnwsocki.h"
#undef DPF_SUBCOMP
#define DPF_SUBCOMP DN_SUBCOMP_WSOCK
//**********************************************************************
// Constant definitions
//**********************************************************************
//
// length of IPX host names 'xxxxxxxx,xxxxxxxxxxxx' including NULL
//
#define IPX_ADDRESS_STRING_LENGTH 22
//
// default buffer size to use when parsing address components
//
#define DEFAULT_COMPONENT_BUFFER_SIZE 1000
//
// 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 char g_IPXAdapterString[] = "Local IPX Adapter";
//**********************************************************************
// Macro definitions
//**********************************************************************
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
//**********************************************************************
// Function prototypes
//**********************************************************************
//**********************************************************************
// Function definitions
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::InitializeWithBroadcastAddress - initialize with the broadcast address
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::InitializeWithBroadcastAddress"
void CIPXAddress::InitializeWithBroadcastAddress( void )
{
DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress.sa_netnum ) == sizeof( DWORD ) );
*reinterpret_cast<DWORD*>( m_SocketAddress.IPXSocketAddress.sa_netnum ) = 0x00000000;
DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress.sa_nodenum ) == 6 );
DBG_CASSERT( sizeof( DWORD ) == 4 );
*reinterpret_cast<DWORD*>( &m_SocketAddress.IPXSocketAddress.sa_nodenum ) = 0xFFFFFFFF;
*reinterpret_cast<DWORD*>( &m_SocketAddress.IPXSocketAddress.sa_nodenum[ 2 ] ) = 0xFFFFFFFF;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::SetAddressFromSOCKADDR - set address from a socket address
//
// Entry: Reference to address
// Size of address
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::SetAddressFromSOCKADDR"
void CIPXAddress::SetAddressFromSOCKADDR( const SOCKADDR &Address, const INT_PTR iAddressSize )
{
DNASSERT( iAddressSize == GetAddressSize() );
DNASSERT( iAddressSize == GetAddressSize() );
memcpy( &m_SocketAddress.SocketAddress, &Address, iAddressSize );
//
// IPX addresses are only 14 of the 16 bytes in the socket address structure,
// make sure the exrta bytes are zero!
//
DNASSERT( m_SocketAddress.SocketAddress.sa_data[ 12 ] == 0 );
DNASSERT( m_SocketAddress.SocketAddress.sa_data[ 13 ] == 0 );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::SocketAddressFromDP8Address - convert a DP8Address into a socket address
// NOTE: The address object may be modified
//
// Entry: Pointer to DP8Address
// Address type
//
// Exit: Error code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::SocketAddressFromDP8Address"
HRESULT CIPXAddress::SocketAddressFromDP8Address( IDirectPlay8Address *const pDP8Address, const SP_ADDRESS_TYPE AddressType )
{
HRESULT hr;
char *pHostNameBuffer;
DWORD dwWCharHostNameSize;
//IDirectPlay8Address *pDuplicateAddress;
DNASSERT( pDP8Address != NULL );
//
// initialize
//
hr = DPN_OK;
//pDuplicateAddress = NULL;
pHostNameBuffer = NULL;
dwWCharHostNameSize = 0;
//
// 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_PROXIED_ENUM_TARGET:
case SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT:
{
HRESULT hTempResult;
DWORD dwTempSize;
GUID AdapterGuid;
DWORD dwPort;
DWORD dwDataType;
union
{
SOCKADDR SocketAddress;
SOCKADDR_IPX IPXSocketAddress;
} 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.
//
AddressFromGuid( AdapterGuid, NetAddress.SocketAddress );
if ( NetAddress.IPXSocketAddress.sa_family != m_SocketAddress.IPXSocketAddress.sa_family )
{
DNASSERT( FALSE );
hr = DPNERR_ADDRESSING;
DPFX(DPFPREP, 0, "Invalid device guid!" );
goto Exit;
}
DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress ) == sizeof( NetAddress.IPXSocketAddress ) );
memcpy( &m_SocketAddress.IPXSocketAddress, &NetAddress.IPXSocketAddress, sizeof( m_SocketAddress.IPXSocketAddress ) );
m_SocketAddress.IPXSocketAddress.sa_socket = p_htons( static_cast<WORD>( dwPort ) );
break;
}
//
// hostname
//
case SP_ADDRESS_TYPE_HOST:
{
HRESULT hTempResult;
DWORD dwPort;
DWORD dwTempSize;
DWORD dwDataType;
/*
//
// duplicate the input address because it might need to be modified
//
DNASSERT( pDuplicateAddress == NULL );
IDirectPlay8Address_Duplicate( pDP8Address, &pDuplicateAddress );
if ( pDuplicateAddress == NULL )
{
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
*/
//
// Ask for the port. If none is found, choose a default.
//
dwTempSize = sizeof( dwPort );
//hTempResult = IDirectPlay8Address_GetComponentByName( pDuplicateAddress, DPNA_KEY_PORT, &dwPort, &dwTempSize, &dwDataType );
hTempResult = IDirectPlay8Address_GetComponentByName( pDP8Address, DPNA_KEY_PORT, &dwPort, &dwTempSize, &dwDataType );
switch ( hTempResult )
{
//
// port present, nothing to do
//
case DPN_OK:
{
DNASSERT( dwDataType == DPNA_DATATYPE_DWORD );
m_SocketAddress.IPXSocketAddress.sa_socket = p_htons( static_cast<WORD>( dwPort ) );
break;
}
//
// port not present, fill in the appropriate default
//
case DPNERR_DOESNOTEXIST:
{
const DWORD dwTempPort = DPNA_DPNSVR_PORT;
m_SocketAddress.IPXSocketAddress.sa_socket = p_htons( static_cast<const WORD>( dwTempPort ) );
//hTempResult = IDirectPlay8Address_AddComponent( pDuplicateAddress,
hTempResult = IDirectPlay8Address_AddComponent( pDP8Address,
DPNA_KEY_PORT,
&dwTempPort,
sizeof( dwTempPort ),
DPNA_DATATYPE_DWORD
);
if ( hTempResult != DPN_OK )
{
hr = hTempResult;
goto Failure;
}
break;
}
//
// remap everything else to an addressing failure
//
default:
{
hr = DPNERR_ADDRESSING;
goto Failure;
}
}
//
// attempt to determine host name
//
dwWCharHostNameSize = 0;
//hr = IDirectPlay8Address_GetComponentByName( pDuplicateAddress, DPNA_KEY_HOSTNAME, pHostNameBuffer, &dwWCharHostNameSize, &dwDataType );
hr = IDirectPlay8Address_GetComponentByName( pDP8Address, DPNA_KEY_HOSTNAME, pHostNameBuffer, &dwWCharHostNameSize, &dwDataType );
switch ( hr )
{
//
// keep the following codes and fail
//
case DPNERR_OUTOFMEMORY:
case DPNERR_INCOMPLETEADDRESS:
{
goto Failure;
break;
}
//
// Buffer too small. Allocate a buffer large enough to store both
// the Unicode and ASCII versions of the hostname and then attempt
// to parse the hostname.
//
case DPNERR_BUFFERTOOSMALL:
{
DWORD dwAnsiHostNameSize;
DWORD dwTempAnsiHostNameSize;
DWORD dwTempWCharHostNameSize;
DWORD dwTempDataType;
dwAnsiHostNameSize = dwWCharHostNameSize / sizeof( WCHAR );
dwTempWCharHostNameSize = dwWCharHostNameSize + dwAnsiHostNameSize;
pHostNameBuffer = static_cast<char*>( DNMalloc( dwTempWCharHostNameSize ) );
if ( pHostNameBuffer == NULL )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "IPXAddressFromDP8Address: Failed to allocate memory for hostname!" );
goto Failure;
}
//hr = IDirectPlay8Address_GetComponentByName( pDuplicateAddress, DPNA_KEY_HOSTNAME, pHostNameBuffer, &dwTempWCharHostNameSize, &dwTempDataType );
hr = IDirectPlay8Address_GetComponentByName( pDP8Address, DPNA_KEY_HOSTNAME, pHostNameBuffer, &dwTempWCharHostNameSize, &dwTempDataType );
switch( hr )
{
//
// no problem
//
case DPN_OK:
{
DNASSERT( dwTempDataType == DPNA_DATATYPE_STRING );
DNASSERT( dwTempWCharHostNameSize == dwWCharHostNameSize );
break;
}
//
// return these error codes unmodified
//
case DPNERR_OUTOFMEMORY:
{
goto Failure;
break;
}
//
// remap other errors to an addressing error
//
default:
{
DNASSERT( FALSE );
hr = DPNERR_ADDRESSING;
goto Failure;
break;
}
}
//
// convert host name to ANSI, ASSERT that we had just enough space
//
DNASSERT( dwAnsiHostNameSize == ( dwWCharHostNameSize / sizeof( WCHAR ) ) );
dwTempAnsiHostNameSize = dwAnsiHostNameSize;
hr = STR_WideToAnsi( reinterpret_cast<WCHAR*>( pHostNameBuffer ), -1, &pHostNameBuffer[ dwWCharHostNameSize ], &dwTempAnsiHostNameSize );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "IPXAddressFromDP8Address: Failed to convert hostname to ANSI!" );
DisplayDNError( 0, hr );
goto Failure;
}
DNASSERT( dwTempAnsiHostNameSize == dwAnsiHostNameSize );
//
// convert the text host name into the SOCKADDR structure
//
hr = ParseHostName( &pHostNameBuffer[ dwWCharHostNameSize ], dwAnsiHostNameSize );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "IPXAddressFromDP8Address: Failed to parse IPX host name!" );
goto Failure;
}
break;
}
//
// hostname does not exist, treat as an incomplete address
//
case DPNERR_DOESNOTEXIST:
{
hr = DPNERR_INCOMPLETEADDRESS;
break;
}
//
// other problem, remap to addressing failure. We're expecting
// a 'buffer too small' error so success here is treated as an
// error.
//
case DPN_OK:
default:
{
hr = DPNERR_ADDRESSING;
goto Failure;
break;
}
}
break;
}
//
// unknown address type
//
default:
{
DNASSERT( FALSE );
break;
}
}
//
// now that the address has been completely parsed, set the address type
//
m_AddressType = AddressType;
Exit:
if ( pHostNameBuffer != NULL )
{
DNFree( pHostNameBuffer );
pHostNameBuffer = NULL;
}
/*
if ( pDuplicateAddress != NULL )
{
IDirectPlay8Address_Release( pDuplicateAddress );
pDuplicateAddress = NULL;
}
*/
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Problem with IPXAddress::SocketAddressFromDNAddress()" );
DisplayDNError( 0, hr );
}
return hr;
Failure:
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::DP8AddressFromSocketAddress - convert a socket address into a DP8Address
//
// Entry: Nothing
//
// Exit: Pointer to DP8Address
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::DP8AddressFromSocketAddress"
IDirectPlay8Address *CIPXAddress::DP8AddressFromSocketAddress( void ) const
{
HRESULT hr;
IDirectPlay8Address *pDP8Address;
DWORD dwPort;
//
// intialize
//
hr = DPN_OK;
pDP8Address = NULL;
//
// create and initialize the address
//
hr = COM_CoCreateInstance( CLSID_DirectPlay8Address,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address,
reinterpret_cast<void**>( &pDP8Address ) );
if ( hr != S_OK )
{
DNASSERT( pDP8Address == NULL );
DPFX(DPFPREP, 0, "DP8AddressFromSocketAddress: Failed to create DP8Address when converting socket address do DP8Address" );
DNASSERT( FALSE );
goto Failure;
}
//
// set SP
//
hr = IDirectPlay8Address_SetSP( pDP8Address, &CLSID_DP8SP_IPX );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "DP8AddressFromSocketAddress: Failed to set SP type!" );
DisplayDNError( 0, hr );
goto Failure;
}
//
// add on the port because it's always set
//
dwPort = p_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, "DP8AddressFromSocketAddress: Failed to set port!" );
DisplayDNError( 0, hr );
goto Failure;
}
//
// add on the device or hostname depending on what type of address this is
//
switch ( m_AddressType )
{
case SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT:
{
GUID DeviceGuid;
GuidFromInternalAddressWithoutPort( DeviceGuid );
hr = IDirectPlay8Address_AddComponent( pDP8Address,
DPNA_KEY_DEVICE,
&DeviceGuid,
sizeof( DeviceGuid ),
DPNA_DATATYPE_GUID );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "DP8AddressFromSocketAddress: Failed to add device!" );
DisplayDNError( 0, hr );
goto Failure;
}
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<SOCKADDR*>( &m_SocketAddress.SocketAddress ),
sizeof( m_SocketAddress.IPXSocketAddress ),
HostName,
&dwHostNameLength
) != 0 )
{
DPFERR("Error returned from IPXAddressToString");
hr = DPNERR_ADDRESSING;
goto Exit;
}
//
// convert ANSI host name to WCHAR
//
dwWCharHostNameLength = LENGTHOF( WCharHostName );
hr = STR_AnsiToWide( HostName, -1, WCharHostName, &dwWCharHostNameLength );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "DP8AddressFromSocketAddress: Failed to convert hostname to WCHAR!" );
DisplayDNError( 0, hr );
goto Failure;
}
hr = IDirectPlay8Address_AddComponent( pDP8Address,
DPNA_KEY_HOSTNAME,
WCharHostName,
dwWCharHostNameLength * sizeof( WCHAR ),
DPNA_DATATYPE_STRING );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "DP8AddressFromSocketAddress: Failed to add hostname!" );
DisplayDNError( 0, hr );
goto Failure;
}
break;
}
//
// unknown address type
//
default:
{
DNASSERT( FALSE );
break;
}
}
Exit:
return pDP8Address;
Failure:
if ( pDP8Address != NULL )
{
IDirectPlay8Address_Release( pDP8Address );
pDP8Address = NULL;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::CompareFunction - compare against another address
//
// Entry: Pointer to other address
//
// Exit: Integer indicating relative magnitude:
// 0 = items equal
// -1 = other item is of greater magnitude
// 1 = this item is of lesser magnitude
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::CompareFunction"
INT_PTR CIPXAddress::CompareFunction( const CSocketAddress *const pOtherAddress ) const
{
const CIPXAddress *const pIPXAddress = static_cast<const CIPXAddress*>( pOtherAddress );
DNASSERT( pOtherAddress != NULL );
DNASSERT( m_SocketAddress.IPXSocketAddress.sa_family == pIPXAddress->m_SocketAddress.IPXSocketAddress.sa_family );
//
// 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( m_SocketAddress.IPXSocketAddress.sa_netnum ) ) );
DBG_CASSERT( OFFSETOF( SOCKADDR_IPX, sa_socket ) == ( OFFSETOF( SOCKADDR_IPX, sa_nodenum ) + sizeof( m_SocketAddress.IPXSocketAddress.sa_nodenum ) ) );
return memcmp( &m_SocketAddress.IPXSocketAddress.sa_netnum,
pIPXAddress->m_SocketAddress.IPXSocketAddress.sa_netnum,
( sizeof( m_SocketAddress.IPXSocketAddress.sa_netnum ) +
sizeof( m_SocketAddress.IPXSocketAddress.sa_nodenum ) +
sizeof( m_SocketAddress.IPXSocketAddress.sa_socket ) ) );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::EnumAdapters - enumerate all of the adapters for this machine
//
// Entry: Pointer to enum adapters data
//
// Exit: Error code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::EnumAdapters"
HRESULT CIPXAddress::EnumAdapters( SPENUMADAPTERSDATA *const pEnumData ) const
{
HRESULT hr;
CPackedBuffer PackedBuffer;
SOCKET TestSocket;
INT iWSAReturn;
DWORD dwAddressCount;
union
{
SOCKADDR_IPX IPXSocketAddress;
SOCKADDR SocketAddress;
} SockAddr;
DNASSERT( pEnumData != NULL );
//
// initialize
//
DEBUG_ONLY( memset( pEnumData->pAdapterData, 0xAA, pEnumData->dwAdapterDataSize ) );
hr = DPN_OK;
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 = p_socket( GetFamily(), SOCK_DGRAM, NSPROTO_IPX );
if ( TestSocket == INVALID_SOCKET )
{
DWORD dwWSAError;
hr = DPNERR_UNSUPPORTED;
dwWSAError = p_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 = p_bind( TestSocket, &SockAddr.SocketAddress, sizeof( SockAddr.IPXSocketAddress ) );
if ( iWSAReturn == SOCKET_ERROR )
{
DWORD dwWSAError;
hr = DPNERR_OUTOFMEMORY;
dwWSAError = p_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 = p_getsockopt( TestSocket,
// NSPROTO_IPX,
// IPX_MAX_ADAPTER_NUM,
// reinterpret_cast<char*>( &iIPXAdapterCount ),
// &iIPXAdapterCountSize );
// if ( iWSAReturn != 0 )
// {
// DWORD dwWSAError;
//
//
// dwWSAError = p_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 = p_getsockname( TestSocket, &SocketAddress.SocketAddress, &iSocketNameSize );
if ( iReturn != 0 )
{
DWORD dwWSAError;
hr = DPNERR_OUTOFMEMORY;
dwWSAError = p_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 );
hr = AddNetworkAdapterToBuffer( &PackedBuffer, g_IPXAdapterString, &SocketAddressGUID );
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 = p_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<char*>( &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 = AddNetworkAdapterToBuffer( &PackedBuffer, Buffer, &SocketAddressGUID );
// 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 = AddNetworkAdapterToBuffer( &PackedBuffer, g_AllAdaptersString, &ALL_ADAPTERS_GUID );
// 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 )
{
p_closesocket( TestSocket );
TestSocket = INVALID_SOCKET;
}
return hr;
Failure:
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::GuidFromInternalAddressWithoutPort - get a guid from the internal
// address without a port.
//
// Entry: Reference to desintation GUID
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::GuidFromInternalAddressWithoutPort"
void CIPXAddress::GuidFromInternalAddressWithoutPort( GUID &OutputGuid ) const
{
union
{
SOCKADDR SockAddr;
SOCKADDR_IPX IPXSockAddr;
} TempSocketAddress;
DBG_CASSERT( sizeof( TempSocketAddress.SockAddr ) == sizeof( m_SocketAddress.SocketAddress ) );
memcpy( &TempSocketAddress.SockAddr, &m_SocketAddress.SocketAddress, sizeof( TempSocketAddress.SockAddr ) );
TempSocketAddress.IPXSockAddr.sa_socket = 0;
GuidFromAddress( OutputGuid, TempSocketAddress.SockAddr );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::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 "CIPXAddress::IsUndefinedHostAddress"
BOOL CIPXAddress::IsUndefinedHostAddress( void ) const
{
BOOL fReturn;
fReturn = FALSE;
DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress.sa_netnum ) == sizeof( DWORD ) );
DBG_CASSERT( sizeof( m_SocketAddress.IPXSocketAddress.sa_nodenum ) == 6 );
if ( ( *reinterpret_cast<const DWORD*>( &m_SocketAddress.IPXSocketAddress.sa_netnum ) == 0 ) &&
( *reinterpret_cast<const DWORD*>( &m_SocketAddress.IPXSocketAddress.sa_nodenum ) == 0 ) &&
( *reinterpret_cast<const DWORD*>( &m_SocketAddress.IPXSocketAddress.sa_nodenum[ 2 ] ) == 0 ) )
{
fReturn = TRUE;
}
return fReturn;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::ChangeLoopBackToLocalAddress - change loopback to a local address
//
// Entry: Pointer to other address
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::ChangeLoopBackToLocalAddress"
void CIPXAddress::ChangeLoopBackToLocalAddress( const CSocketAddress *const pOtherSocketAddress )
{
DNASSERT( pOtherSocketAddress != NULL );
//
// there is no 'loopback' for IPX so this function doesn't do anything
//
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::CreateBroadcastAddress - create DP8Address used for broadcast sends
//
// Entry: Nothing
//
// Exit: Pointer to address
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::CreateBroadcastAddress"
IDirectPlay8Address *CIPXAddress::CreateBroadcastAddress( void )
{
HRESULT hr;
IDirectPlay8Address *pDPlayAddress;
const DWORD dwPort = DPNA_DPNSVR_PORT;
//
// initialize
//
pDPlayAddress = NULL;
hr = COM_CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, reinterpret_cast<void**>( &pDPlayAddress ) );
if ( hr != S_OK )
{
DNASSERT( pDPlayAddress == NULL );
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to create IPAddress when converting socket address do DP8Address" );
DNASSERT( FALSE );
goto Failure;
}
hr = IDirectPlay8Address_SetSP( pDPlayAddress, &CLSID_DP8SP_IPX );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to set SP type!" );
DisplayDNError( 0, hr );
goto Failure;
}
hr = IDirectPlay8Address_AddComponent( pDPlayAddress, DPNA_KEY_HOSTNAME, g_IPXBroadcastAddress, sizeof( g_IPXBroadcastAddress ), DPNA_DATATYPE_STRING );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to set hostname!" );
DisplayDNError( 0, hr );
goto Failure;
}
hr = IDirectPlay8Address_AddComponent( pDPlayAddress, DPNA_KEY_PORT, &dwPort, sizeof( dwPort ), DPNA_DATATYPE_DWORD );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to set port!" );
DisplayDNError( 0, hr );
goto Failure;
}
Exit:
return pDPlayAddress;
Failure:
if ( pDPlayAddress != NULL )
{
IDirectPlay8Address_Release( pDPlayAddress );
pDPlayAddress = NULL;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::CreateListenAddress - create DP8Address used for listens
//
// Entry: Nothing
//
// Exit: Pointer to address
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::CreateListenAddress"
IDirectPlay8Address *CIPXAddress::CreateListenAddress( void )
{
HRESULT hr;
IDirectPlay8Address *pDPlayAddress;
const DWORD dwPort = ANY_PORT;
//
// initialize
//
pDPlayAddress = NULL;
hr = COM_CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, reinterpret_cast<void**>( &pDPlayAddress ) );
if ( hr != S_OK )
{
DNASSERT( pDPlayAddress == NULL );
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to create IPAddress when converting socket address do DP8Address" );
DNASSERT( FALSE );
goto Failure;
}
hr = IDirectPlay8Address_SetSP( pDPlayAddress, &CLSID_DP8SP_IPX );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to set SP type!" );
DisplayDNError( 0, hr );
goto Failure;
}
hr = IDirectPlay8Address_AddComponent( pDPlayAddress, DPNA_KEY_HOSTNAME, g_IPXListenAddress, sizeof( g_IPXListenAddress ), DPNA_DATATYPE_STRING );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to set hostname!" );
DisplayDNError( 0, hr );
goto Failure;
}
hr = IDirectPlay8Address_AddComponent( pDPlayAddress, DPNA_KEY_PORT, &dwPort, sizeof( dwPort ), DPNA_DATATYPE_DWORD );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to set port!" );
DisplayDNError( 0, hr );
goto Failure;
}
Exit:
return pDPlayAddress;
Failure:
if ( pDPlayAddress != NULL )
{
IDirectPlay8Address_Release( pDPlayAddress );
pDPlayAddress = NULL;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::CreateGenericAddress - create a generic address
//
// Entry: Nothing
//
// Exit: Pointer to address
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::CreateGenericAddress"
IDirectPlay8Address *CIPXAddress::CreateGenericAddress( void )
{
HRESULT hr;
IDirectPlay8Address *pDPlayAddress;
const DWORD dwPort = 0;
//
// initialize
//
pDPlayAddress = NULL;
hr = COM_CoCreateInstance( CLSID_DirectPlay8Address,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address,
reinterpret_cast<void**>( &pDPlayAddress ) );
if ( hr != S_OK )
{
DNASSERT( pDPlayAddress == NULL );
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to create IPAddress when converting socket address do DP8Address" );
DNASSERT( FALSE );
goto Failure;
}
hr = IDirectPlay8Address_SetSP( pDPlayAddress, &CLSID_DP8SP_IPX );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to set SP type!" );
DisplayDNError( 0, hr );
goto Failure;
}
hr = IDirectPlay8Address_AddComponent( pDPlayAddress,
DPNA_KEY_HOSTNAME,
g_IPXListenAddress,
sizeof( g_IPXListenAddress ),
DPNA_DATATYPE_STRING );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to set hostname!" );
DisplayDNError( 0, hr );
goto Failure;
}
hr = IDirectPlay8Address_AddComponent( pDPlayAddress,
DPNA_KEY_PORT,
&dwPort,
sizeof( dwPort ),
DPNA_DATATYPE_DWORD );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "CreateBroadcastAddress: Failed to set port!" );
DisplayDNError( 0, hr );
goto Failure;
}
Exit:
return pDPlayAddress;
Failure:
if ( pDPlayAddress != NULL )
{
IDirectPlay8Address_Release( pDPlayAddress );
pDPlayAddress = NULL;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::HashFunction - hash address to N bits
//
// Entry: Count of bits to hash to
//
// Exit: Hashed value
//
// Note: We only need to compare the nodenumber (netcard adapter address)
// [ 6 bytes ] and the port (socket) [ 2 bytes ] to guarantee uniqueness.
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::HashFunction"
INT_PTR CIPXAddress::HashFunction( const INT_PTR iHashBitCount ) const
{
INT_PTR iReturn;
UINT_PTR Temp;
DNASSERT( iHashBitCount != 0 );
//
// initialize
//
iReturn = 0;
//
// hash first DWORD of IPX address
//
Temp = *reinterpret_cast<const DWORD*>( &m_SocketAddress.IPXSocketAddress.sa_nodenum[ 0 ] );
do
{
iReturn ^= Temp & ( ( 1 << iHashBitCount ) - 1 );
Temp >>= iHashBitCount;
} while ( Temp != 0 );
//
// hash second DWORD of IPX address and IPX socket
//
Temp = *reinterpret_cast<const WORD*>( &m_SocketAddress.IPXSocketAddress.sa_nodenum[ sizeof( DWORD ) ] );
Temp += ( m_SocketAddress.IPXSocketAddress.sa_socket << ( sizeof( WORD ) * 8 ) );
do
{
iReturn ^= Temp & ( ( 1 << iHashBitCount ) - 1 );
Temp >>= iHashBitCount;
}
while ( Temp != 0 );
return iReturn;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::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 "CIPXAddress::CompareToBaseAddress"
INT_PTR CIPXAddress::CompareToBaseAddress( const SOCKADDR *const pBaseAddress ) const
{
const SOCKADDR_IPX *pBaseIPXAddress;
DNASSERT( pBaseAddress != NULL );
pBaseIPXAddress = reinterpret_cast<const SOCKADDR_IPX *>( pBaseAddress );
DBG_CASSERT( OFFSETOF( SOCKADDR_IPX, sa_nodenum ) == OFFSETOF( SOCKADDR_IPX, sa_netnum ) + sizeof( pBaseIPXAddress->sa_netnum ) );
return memcmp( &m_SocketAddress.IPXSocketAddress.sa_netnum,
&pBaseIPXAddress->sa_netnum,
( sizeof( pBaseIPXAddress->sa_netnum ) + sizeof( pBaseIPXAddress->sa_nodenum ) ) );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::ParseHostName - parse a host name
//
// Entry: Pointer to host name
// Size of host name (including NULL)
//
// Exit: Error code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::ParseHostName"
HRESULT CIPXAddress::ParseHostName( const char *const pHostName, const DWORD dwHostNameLength )
{
HRESULT hr;
long val;
char temp[3];
const char *a, *b;
UINT_PTR uIndex;
//
// initialize
//
hr = DPN_OK;
DNASSERT( pHostName != NULL );
DNASSERT( pHostName[ dwHostNameLength - 1 ] == '\0' );
DNASSERT( m_ComponentInitializationState[ SPADDRESS_PARSE_KEY_HOSTNAME ] == SP_ADDRESS_COMPONENT_UNINITIALIZED );
m_ComponentInitializationState[ SPADDRESS_PARSE_KEY_HOSTNAME ] = SP_ADDRESS_COMPONENT_INITIALIZATION_FAILED;
if ( dwHostNameLength != 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 ) );
hr = DPNERR_ADDRESSING;
goto Exit;
}
// we convert the string for the hostname field into the components
temp[ 2 ] = 0;
a = static_cast<const char*>( pHostName );
// the net number is 4 bytes
for ( uIndex = 0; uIndex < 4; uIndex++ )
{
strncpy( temp, a, 2 );
val = strtol( temp, const_cast<char**>( &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, const_cast<char**>( &b ), 16 );
m_SocketAddress.IPXSocketAddress.sa_nodenum[ uIndex ] = (char) val;
a += 2;
}
m_ComponentInitializationState[ SPADDRESS_PARSE_KEY_HOSTNAME ] = SP_ADDRESS_COMPONENT_INITIALIZED;
Exit:
return hr;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CIPXAddress::CopyInternalSocketAddressWithoutPort - copy socket address
// without the port field.
//
// Entry: Reference to destination address
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CIPXAddress::CopyInternalSocketAddressWithoutPort"
void CIPXAddress::CopyInternalSocketAddressWithoutPort( SOCKADDR &AddressDestination ) const
{
SOCKADDR_IPX *pIPXSocketAddress;
//
// copy address and zero out the port
//
DBG_CASSERT( sizeof( AddressDestination ) == sizeof( m_SocketAddress.SocketAddress ) );
memcpy( &AddressDestination, &m_SocketAddress.SocketAddress, sizeof( AddressDestination ) );
DBG_CASSERT( sizeof( SOCKADDR_IPX* ) == sizeof( &AddressDestination ) );
pIPXSocketAddress = reinterpret_cast<SOCKADDR_IPX*>( &AddressDestination );
pIPXSocketAddress->sa_socket = p_htons( 0 );
}
//**********************************************************************