/*========================================================================== * * Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved. * * File: addtcp.cpp * Content: DirectPlay8Address core implementation file *@@BEGIN_MSINTERNAL * History: * Date By Reason * ==== == ====== * 02/04/2000 rmt Created * 02/10/2000 rmt Updated to use DPNA_ defines instead of URL_ * 02/12/2000 rmt Split Get into GetByName and GetByIndex * 02/17/2000 rmt Parameter validation work * 02/18/2000 rmt Added type validation to all pre-defined elements * 02/21/2000 rmt Updated to make core Unicode and remove ANSI calls * 02/23/2000 rmt Fixed length calculations in GetURL * rmt Buffer too small error debug messages -> Warning level * 03/21/2000 rmt Renamed all DirectPlayAddress8's to DirectPlay8Addresses * Added support for the new ANSI type * 05/04/00 mjn delete temp var at end of SetElement() * 05/05/00 mjn Better error cleanup in SetElement() * 06/06/00 rmt Bug #36455 failure when calling with ANSI string shortcut for SP * 06/09/00 rmt Updates to split CLSID and allow whistler compat and support external create funcs * 06/21/2000 rmt Bug #37392 - Leak if replacing allocated element with new item same size as GUID * 06/27/2000 rmt Bug #37630 - Service provider shortcuts / element names were case sensitive * 07/06/2000 rmt Bug #38714 - ADDRESSING: GetURL doesn't return the # of chars written * 07/09/2000 rmt Added signature bytes to start of address objects * 07/12/2000 rmt Fixed some critical section related bugs: * - Added leave in an error path where it wasn't being called * - Moved critical section init/delete to constructor / destructor * 07/13/2000 rmt Bug #39274 - INT 3 during voice run * - Fixed point where a critical section was being re-initialized * rmt Added critical sections to protect FPMs * 07/21/2000 rmt Fixed bug w/directplay 4 address parsing * 07/31/2000 rmt Bug #41125 - Addressing() GetUserData when none available should return doesnotexist * 08/03/2000 rmt Missing LEAVELOCK() was causing lockups. * 11/29/2000 aarono B#226079 prefix, fix memory leak in failure path of SetElement *@@END_MSINTERNAL * ***************************************************************************/ #include "dnaddri.h" const WCHAR * g_szBaseStrings[] = { #ifndef DPNBUILD_ONLYONESP DPNA_KEY_PROVIDER, #endif // ! DPNBUILD_ONLYONESP #ifndef DPNBUILD_ONLYONEADAPTER DPNA_KEY_DEVICE, #endif // ! DPNBUILD_ONLYONEADAPTER DPNA_KEY_HOSTNAME, DPNA_KEY_PORT, #ifndef DPNBUILD_NOLOBBY DPNA_KEY_APPLICATION_INSTANCE, DPNA_KEY_PROGRAM, #endif // ! DPNBUILD_NOLOBBY #ifndef DPNBUILD_NOSERIALSP DPNA_KEY_BAUD, DPNA_KEY_FLOWCONTROL, DPNA_KEY_PARITY, DPNA_KEY_PHONENUMBER, DPNA_KEY_STOPBITS #endif // !DPNBUILD_NOSERIALSP }; const DWORD c_dwNumBaseStrings = LENGTHOF(g_szBaseStrings); const DWORD g_dwBaseRequiredTypes[] = { #ifndef DPNBUILD_ONLYONESP DPNA_DATATYPE_GUID, #endif // ! DPNBUILD_ONLYONESP #ifndef DPNBUILD_ONLYONEADAPTER DPNA_DATATYPE_GUID, #endif // ! DPNBUILD_ONLYONEADAPTER DPNA_DATATYPE_STRING, DPNA_DATATYPE_DWORD, #ifndef DPNBUILD_NOLOBBY DPNA_DATATYPE_GUID, DPNA_DATATYPE_GUID, #endif // ! DPNBUILD_NOLOBBY #ifndef DPNBUILD_NOSERIALSP DPNA_DATATYPE_DWORD, DPNA_DATATYPE_STRING, DPNA_DATATYPE_STRING, DPNA_DATATYPE_STRING, DPNA_DATATYPE_STRING #endif // !DPNBUILD_NOSERIALSP }; #undef DPF_MODNAME #define DPF_MODNAME "DP8A_STRCACHE_Init" HRESULT DP8A_STRCACHE_Init() { HRESULT hr; PWSTR pstrTmp; DWORD dwIndex; DNASSERT( g_pcstrKeyCache == NULL ); g_pcstrKeyCache = (CStringCache*) DNMalloc(sizeof(CStringCache)); if ( g_pcstrKeyCache == NULL ) { DPFX(DPFPREP, 0, "Failed to create addressing string cache!" ); return DPNERR_OUTOFMEMORY; } g_pcstrKeyCache->Initialize(); for( dwIndex = 0; dwIndex < c_dwNumBaseStrings; dwIndex++ ) { hr = g_pcstrKeyCache->AddString( g_szBaseStrings[dwIndex], &pstrTmp ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Error adding base strings" ); g_pcstrKeyCache->Deinitialize(); DNFree(g_pcstrKeyCache); g_pcstrKeyCache = NULL; return hr; } } return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8A_STRCACHE_Free" // Nothing needs to be done. void DP8A_STRCACHE_Free() { if ( g_pcstrKeyCache != NULL ) { g_pcstrKeyCache->Deinitialize(); DNFree(g_pcstrKeyCache); g_pcstrKeyCache = NULL; } } #undef DPF_MODNAME #define DPF_MODNAME "FPM_Element_BlockInit" void DP8ADDRESSOBJECT::FPM_Element_BlockInit( void *pvItem, PVOID pvContext ) { memset( pvItem, 0x00, sizeof( DP8ADDRESSELEMENT ) ); ((PDP8ADDRESSELEMENT) pvItem)->dwSignature = DPASIGNATURE_ELEMENT; ((PDP8ADDRESSELEMENT) pvItem)->blAddressElements.Initialize(); } #undef DPF_MODNAME #define DPF_MODNAME "FPM_Element_BlockRelease" void DP8ADDRESSOBJECT::FPM_Element_BlockRelease( void *pvItem ) { ((PDP8ADDRESSELEMENT) pvItem)->dwSignature = DPASIGNATURE_ELEMENT_FREE; DNASSERT(((PDP8ADDRESSELEMENT) pvItem)->blAddressElements.IsEmpty()); } #undef DPF_MODNAME #define DPF_MODNAME "FPM_BlockCreate" BOOL DP8ADDRESSOBJECT::FPM_BlockCreate( void *pvItem, PVOID pvContext ) { return DNInitializeCriticalSection( &((PDP8ADDRESSOBJECT) pvItem)->m_csAddressLock ); } #undef DPF_MODNAME #define DPF_MODNAME "FPM_BlockInit" void DP8ADDRESSOBJECT::FPM_BlockInit( void *pvItem, PVOID pvContext ) { ((PDP8ADDRESSOBJECT) pvItem)->m_dwSignature = DPASIGNATURE_ADDRESS; } #undef DPF_MODNAME #define DPF_MODNAME "FPM_BlockRelease" void DP8ADDRESSOBJECT::FPM_BlockRelease( void *pvItem ) { ((PDP8ADDRESSOBJECT) pvItem)->m_dwSignature = DPASIGNATURE_ADDRESS_FREE; } #undef DPF_MODNAME #define DPF_MODNAME "FPM_BlockDestroy" void DP8ADDRESSOBJECT::FPM_BlockDestroy( void *pvItem ) { DNDeleteCriticalSection( &((PDP8ADDRESSOBJECT) pvItem)->m_csAddressLock ); } // InternalGetElement // // This function does the lookup for an element by index. // // Requires the object lock. // // Does not do parameter validation. // #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::InternalGetElement" HRESULT DP8ADDRESSOBJECT::InternalGetElement( const DWORD dwIndex, PDP8ADDRESSELEMENT *ppaElement ) { CBilink *pblSearch; if( dwIndex >= m_dwElements ) return DPNERR_DOESNOTEXIST; pblSearch = m_blAddressElements.GetNext(); for( DWORD dwSearchIndex = 0; dwSearchIndex < dwIndex; dwSearchIndex++ ) { pblSearch = pblSearch->GetNext(); } *ppaElement = CONTAINING_OBJECT(pblSearch, DP8ADDRESSELEMENT, blAddressElements); return DPN_OK; } // InternalGetElement // // This function does the lookup for an element by name. // // Requires the object lock. // // Does not do parameter validation. // #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::InternalGetElement" HRESULT DP8ADDRESSOBJECT::InternalGetElement( const WCHAR * const pszTag, PDP8ADDRESSELEMENT *ppaElement ) { CBilink *pblSearch; PDP8ADDRESSELEMENT paddElement; pblSearch = m_blAddressElements.GetNext(); while( pblSearch != &m_blAddressElements ) { paddElement = CONTAINING_OBJECT(pblSearch, DP8ADDRESSELEMENT, blAddressElements); if( _wcsicmp( pszTag, paddElement->pszTag ) == 0 ) { *ppaElement = paddElement; return DPN_OK; } pblSearch = pblSearch->GetNext(); } return DPNERR_DOESNOTEXIST; } // GetElement // // Implements retrieval of element by name // // Parameter validation must be performed BEFORE calling this function. // #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::GetElement" HRESULT DP8ADDRESSOBJECT::GetElement( const WCHAR * const pszTag, void * pvDataBuffer, PDWORD pdwDataSize, PDWORD pdwDataType ) { PDP8ADDRESSELEMENT paddElement = NULL; HRESULT hr; ENTERLOCK(); hr = InternalGetElement( pszTag, &paddElement ); if( FAILED( hr ) ) { DPFX(DPFPREP, 1, "Unable to find specified element hr=0x%x", hr ); LEAVELOCK(); return hr; } DNASSERT( paddElement != NULL ); *pdwDataType = paddElement->dwType; if( *pdwDataSize < paddElement->dwDataSize || pvDataBuffer == NULL ) { *pdwDataSize = paddElement->dwDataSize; DPFX(DPFPREP, DP8A_WARNINGLEVEL, "Specified buffers were too small hr=0x%x", hr ); LEAVELOCK(); return DPNERR_BUFFERTOOSMALL; } *pdwDataSize = paddElement->dwDataSize; #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL if( paddElement->dwFlags & DP8ADDRESS_ELEMENT_HEAP ) { memcpy( pvDataBuffer, paddElement->uData.pvData, paddElement->dwDataSize ); } else #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL { memcpy( pvDataBuffer, &paddElement->uData, paddElement->dwDataSize ); } LEAVELOCK(); return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::GetElementType" HRESULT DP8ADDRESSOBJECT::GetElementType( const WCHAR * pszTag, PDWORD pdwType ) { PDP8ADDRESSELEMENT paddElement = NULL; HRESULT hr; ENTERLOCK(); hr = InternalGetElement( pszTag, &paddElement ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Unable to find specified element hr=0x%x" ); LEAVELOCK(); return hr; } *pdwType = paddElement->dwType; LEAVELOCK(); return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::GetElement" HRESULT DP8ADDRESSOBJECT::GetElement( const DWORD dwIndex, WCHAR * pszTag, PDWORD pdwTagSize, void * pvDataBuffer, PDWORD pdwDataSize, PDWORD pdwDataType ) { PDP8ADDRESSELEMENT paddElement = NULL; HRESULT hr; if( pdwTagSize == NULL || pdwDataSize == NULL || pdwDataType == NULL ) { DPFX(DPFPREP, 0, "Invalid Poiinter" ); return DPNERR_INVALIDPOINTER; } ENTERLOCK(); hr = InternalGetElement( dwIndex, &paddElement ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Unable to find specified element hr=0x%x", hr ); LEAVELOCK(); return hr; } DNASSERT( paddElement != NULL ); *pdwDataType = paddElement->dwType; if( *pdwTagSize < (wcslen( paddElement->pszTag )+1) || *pdwDataSize < paddElement->dwDataSize || pszTag == NULL || pvDataBuffer == NULL ) { *pdwTagSize = paddElement->dwTagSize; *pdwDataSize = paddElement->dwDataSize; DPFX(DPFPREP, DP8A_WARNINGLEVEL, "Specified buffers were too small hr=0x%x", hr ); LEAVELOCK(); return DPNERR_BUFFERTOOSMALL; } *pdwTagSize = paddElement->dwTagSize; *pdwDataSize = paddElement->dwDataSize; wcscpy( pszTag, paddElement->pszTag ); #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL if( paddElement->dwFlags & DP8ADDRESS_ELEMENT_HEAP ) { memcpy( pvDataBuffer, paddElement->uData.pvData, paddElement->dwDataSize ); } else #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL { memcpy( pvDataBuffer, &paddElement->uData, paddElement->dwDataSize ); } LEAVELOCK(); return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::SetElement" HRESULT DP8ADDRESSOBJECT::SetElement( const WCHAR * const pszTag, const void * const pvData, const DWORD dwDataSize, const DWORD dwDataType ) { PDP8ADDRESSELEMENT paddElement = NULL; HRESULT hr = DPN_OK; BOOL fReplace = FALSE; #ifdef DBG DNASSERT(pvData != NULL); switch( dwDataType ) { case DPNA_DATATYPE_DWORD: { DNASSERT(dwDataSize == sizeof(DWORD)); break; } case DPNA_DATATYPE_GUID: { DNASSERT(dwDataSize == sizeof(GUID)); break; } case DPNA_DATATYPE_STRING: case DPNA_DATATYPE_BINARY: { break; } default: { DPFX(DPFPREP, 0, "Invalid data type %u!", dwDataType); DNASSERT(FALSE); break; } } #endif // DBG ENTERLOCK(); // We need to treat provider key differently, it can also take one of the provider // shortcut values. // For builds with a fixed SP, we don't even care what the value is. if( _wcsicmp( DPNA_KEY_PROVIDER, pszTag ) == 0 ) { #ifdef DPNBUILD_ONLYONESP DPFX(DPFPREP, 3, "Ignoring provider key."); goto APPEND_SUCCESS; #else // ! DPNBUILD_ONLYONESP // If it's a GUID we're golden, otherwise.. if( dwDataType != DPNA_DATATYPE_GUID ) { if( dwDataType == DPNA_DATATYPE_STRING ) { if( _wcsicmp( (const WCHAR * const) pvData, DPNA_VALUE_TCPIPPROVIDER ) == 0 ) { hr = SetSP( &CLSID_DP8SP_TCPIP ); } #ifndef DPNBUILD_NOIPX else if( _wcsicmp( (const WCHAR * const) pvData, DPNA_VALUE_IPXPROVIDER ) == 0 ) { hr= SetSP( &CLSID_DP8SP_IPX ); } #endif // ! DPNBUILD_NOIPX #ifndef DPNBUILD_NOSERIALSP else if( _wcsicmp( (const WCHAR * const) pvData, DPNA_VALUE_MODEMPROVIDER ) == 0 ) { hr = SetSP( &CLSID_DP8SP_MODEM ); } else if( _wcsicmp( (const WCHAR * const) pvData, DPNA_VALUE_SERIALPROVIDER ) == 0 ) { hr = SetSP( &CLSID_DP8SP_SERIAL ); } #endif // ! DPNBUILD_NOSERIALSP else { DPFX(DPFPREP, DP8A_ERRORLEVEL, "Provider must be specified as a GUID or a valid shortcut string" ); hr = DPNERR_INVALIDPARAM; goto APPEND_ERROR; } if( FAILED( hr ) ) { DPFX(DPFPREP, DP8A_ERRORLEVEL, "Failed setting provider with shortcut hr=0x%x", hr ); goto APPEND_ERROR; } goto APPEND_SUCCESS; } else { DPFX(DPFPREP, DP8A_ERRORLEVEL, "Specified values is not a supported datatype for the given key" ); hr = DPNERR_INVALIDPARAM; goto APPEND_ERROR; } } #endif // ! DPNBUILD_ONLYONESP } else { // Ensure that datatype is correct in case the key is a reserved key for( DWORD dwIndex = 0; dwIndex < c_dwNumBaseStrings; dwIndex++ ) { if( _wcsicmp( g_szBaseStrings[dwIndex], pszTag ) == 0 ) { if( dwDataType != g_dwBaseRequiredTypes[dwIndex] ) { DPFX(DPFPREP, DP8A_ERRORLEVEL, "Specified key is reserved and specified datatype is not correct for key" ); hr = DPNERR_INVALIDPARAM; goto APPEND_ERROR; } break; } } } hr = InternalGetElement( pszTag, &paddElement ); // If the element is not already in the address we need to add an element if( FAILED( hr ) ) { paddElement = (PDP8ADDRESSELEMENT) fpmAddressElements.Get(); if( paddElement == NULL ) { DPFX(DPFPREP, 0, "Error getting new element" ); hr = DPNERR_OUTOFMEMORY; goto APPEND_ERROR; } hr = g_pcstrKeyCache->AddString( pszTag, &paddElement->pszTag ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Unable to cache tag element hr=0x%x" ); goto APPEND_ERROR; } // Set flag to 0 paddElement->dwFlags = 0; } // The element is already there. Fill in the data. else { DNASSERT( paddElement != NULL ); #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL DNASSERT( dwDataSize <= sizeof(paddElement->uData) ); // If the one we're replacing was on the heap AND // The new one doesn't need the heap or is a larger size.. if( paddElement->dwFlags & DP8ADDRESS_ELEMENT_HEAP && (dwDataSize <= sizeof(paddElement->uData) || dwDataSize > paddElement->dwDataSize) ) { DNFree(paddElement->uData.pvData); paddElement->uData.pvData = NULL; paddElement->dwDataSize = 0; } #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL // Reduce the object's string size so object string size will be correct m_dwStringSize -= paddElement->dwStringSize; fReplace = TRUE; } paddElement->dwTagSize = wcslen( pszTag )+1; // Can fit in the internal buffer if( dwDataSize <= sizeof( paddElement->uData ) ) { memcpy( &paddElement->uData, pvData, dwDataSize ); #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL // Turn off heap flag in this case paddElement->dwFlags &= ~(DP8ADDRESS_ELEMENT_HEAP); #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL } else { #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL DPFX(DPFPREP, 0, "Item is too large (%u > %u bytes)!", dwDataSize, sizeof( paddElement->uData ) ); hr = DPNERR_OUTOFMEMORY; goto APPEND_ERROR; #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL if( !fReplace || !(paddElement->dwFlags & DP8ADDRESS_ELEMENT_HEAP) || paddElement->dwDataSize < dwDataSize ) { paddElement->uData.pvData = DNMalloc(dwDataSize); if( paddElement->uData.pvData == NULL ) { DPFX(DPFPREP, 0, "Error allocating memory" ); hr = DPNERR_OUTOFMEMORY; goto APPEND_ERROR; } } memcpy( paddElement->uData.pvData, pvData, dwDataSize ); paddElement->dwFlags |= DP8ADDRESS_ELEMENT_HEAP; #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL } paddElement->dwType = dwDataType; paddElement->dwDataSize = dwDataSize; paddElement->dwStringSize = 0; hr = CalcComponentStringSize( paddElement, &paddElement->dwStringSize ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Failed to determine string length hr=0x%x", hr ); goto APPEND_ERROR; } m_dwStringSize += paddElement->dwStringSize; // Create shortcuts if appropriate #ifndef DPNBUILD_ONLYONESP if( _wcsicmp( DPNA_KEY_PROVIDER, paddElement->pszTag ) == 0 ) { m_pSP = paddElement; } else #endif // ! DPNBUILD_ONLYONESP { #ifndef DPNBUILD_ONLYONEADAPTER if( _wcsicmp( DPNA_KEY_DEVICE, paddElement->pszTag ) == 0 ) { m_pAdapter = paddElement; } #endif // ! DPNBUILD_ONLYONEADAPTER } if( !fReplace ) { #ifndef DPNBUILD_ONLYONESP // We are adding the SP if( m_pSP == paddElement ) { paddElement->blAddressElements.InsertAfter( &m_blAddressElements ); } // We are adding the adapter else #endif // ! DPNBUILD_ONLYONESP { #ifndef DPNBUILD_ONLYONEADAPTER if( m_pAdapter == paddElement ) { #ifndef DPNBUILD_ONLYONESP if( m_pSP != NULL ) { paddElement->blAddressElements.InsertAfter( &m_pSP->blAddressElements); } else #endif // ! DPNBUILD_ONLYONESP { paddElement->blAddressElements.InsertAfter( &m_blAddressElements); } } // Tack it onto the end else #endif // ! DPNBUILD_ONLYONEADAPTER { paddElement->blAddressElements.InsertBefore( &m_blAddressElements ); } } // Add one char length for seperator w/previous element #ifndef DPNBUILD_ONLYONESP if( m_dwElements > 0 ) #endif // ! DPNBUILD_ONLYONESP { m_dwStringSize ++; } m_dwElements++; } APPEND_SUCCESS: LEAVELOCK(); return DPN_OK; APPEND_ERROR: if( paddElement != NULL ) { #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL if( paddElement->dwFlags & DP8ADDRESS_ELEMENT_HEAP ) { if( paddElement->uData.pvData ) { DNFree(paddElement->uData.pvData); paddElement->uData.pvData = NULL; } } #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL fpmAddressElements.Release( paddElement ); } LEAVELOCK(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::Init" HRESULT DP8ADDRESSOBJECT::Init( ) { ENTERLOCK(); m_dwElements = 0; #ifndef DPNBUILD_ONLYONESP m_pSP = NULL; #endif // ! DPNBUILD_ONLYONESP #ifndef DPNBUILD_ONLYONEADAPTER m_pAdapter = NULL; #endif // ! DPNBUILD_ONLYONEADAPTER m_pvUserData = NULL; m_dwUserDataSize = 0; #ifdef DPNBUILD_ONLYONESP m_dwStringSize = DNURL_LENGTH_HEADER + DNURL_LENGTH_BUILTINPROVIDER; #else // ! DPNBUILD_ONLYONESP m_dwStringSize = DNURL_LENGTH_HEADER; #endif // ! DPNBUILD_ONLYONESP m_dwUserDataStringSize = 0; m_blAddressElements.Initialize(); LEAVELOCK(); return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::Clear" HRESULT DP8ADDRESSOBJECT::Clear( ) { CBilink *pbl; PDP8ADDRESSELEMENT paddElement; ENTERLOCK(); pbl = m_blAddressElements.GetNext(); // Destroy Address Members address members while( !m_blAddressElements.IsEmpty() ) { paddElement = CONTAINING_OBJECT(m_blAddressElements.GetNext(), DP8ADDRESSELEMENT, blAddressElements); #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL if( paddElement->dwFlags & DP8ADDRESS_ELEMENT_HEAP ) { DNFree(paddElement->uData.pvData); paddElement->uData.pvData = NULL; } #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL pbl->RemoveFromList(); fpmAddressElements.Release( paddElement ); pbl = m_blAddressElements.GetNext(); } if( m_pvUserData != NULL ) { DNFree(m_pvUserData); m_pvUserData = NULL; m_dwUserDataSize = 0; } LEAVELOCK(); Init( ); return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::Copy" HRESULT DP8ADDRESSOBJECT::Copy( DP8ADDRESSOBJECT * const pAddressSource ) { HRESULT hResultCode; CBilink *pbl; PDP8ADDRESSELEMENT paddElement; pAddressSource->ENTERLOCK(); pbl = pAddressSource->m_blAddressElements.GetNext(); while( pbl != &pAddressSource->m_blAddressElements ) { paddElement = CONTAINING_OBJECT(pbl, DP8ADDRESSELEMENT, blAddressElements); // This takes the lock internally. hResultCode = SetElement(paddElement->pszTag, #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL &paddElement->uData, #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL (( paddElement->dwFlags & DP8ADDRESS_ELEMENT_HEAP ) ? paddElement->uData.pvData : &paddElement->uData), #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL paddElement->dwDataSize, paddElement->dwType); if (hResultCode != DPN_OK) { pAddressSource->LEAVELOCK(); DPFX(DPFPREP, 0, "Couldn't set element!"); return hResultCode; } pbl = pbl->GetNext(); } // This takes the lock internally. hResultCode = SetUserData(pAddressSource->m_pvUserData, pAddressSource->m_dwUserDataSize); if (hResultCode != DPN_OK) { pAddressSource->LEAVELOCK(); DPFX(DPFPREP, 0, "Couldn't set element!"); return hResultCode; } pAddressSource->LEAVELOCK(); return DPN_OK; } #ifndef DPNBUILD_ONLYONESP #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::GetSP" HRESULT DP8ADDRESSOBJECT::GetSP( GUID * pGuid ) { if( pGuid == NULL ) { DPFX(DPFPREP, 0, "Invalid pointer" ); return DPNERR_INVALIDPOINTER; } ENTERLOCK(); if( m_pSP == NULL ) { DPFX(DPFPREP, 0, "No SP has been specified" ); LEAVELOCK(); return DPNERR_DOESNOTEXIST; } if( m_pSP->dwType != DPNA_DATATYPE_GUID ) { DPFX(DPFPREP, 0, "SP was specified, but is not a GUID" ); LEAVELOCK(); return DPNERR_INVALIDPARAM; } memcpy( pGuid, &m_pSP->uData.guidData, sizeof( GUID ) ); LEAVELOCK(); return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::SetSP" HRESULT DP8ADDRESSOBJECT::SetSP( const GUID* const pGuid ) { HRESULT hr; if( pGuid == NULL ) { DPFX(DPFPREP, 0, "Invalid pointer" ); return DPNERR_INVALIDPOINTER; } hr = SetElement( DPNA_KEY_PROVIDER, pGuid, sizeof( GUID ), DPNA_DATATYPE_GUID ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Adding SP element failed hr=0x%x", hr ); } return hr; } #endif // ! DPNBUILD_ONLYONESP #ifndef DPNBUILD_ONLYONEADAPTER #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::GetDevice" HRESULT DP8ADDRESSOBJECT::GetDevice( GUID * pGuid ) { if( pGuid == NULL ) { DPFX(DPFPREP, 0, "Invalid pointer" ); return DPNERR_INVALIDPOINTER; } ENTERLOCK(); if( m_pAdapter == NULL ) { DPFX(DPFPREP, 1, "No SP has been specified" ); LEAVELOCK(); return DPNERR_DOESNOTEXIST; } if( m_pAdapter->dwType != DPNA_DATATYPE_GUID ) { DPFX(DPFPREP, 0, "SP was specified, but is not a GUID" ); LEAVELOCK(); return DPNERR_INVALIDPARAM; } memcpy( pGuid, &m_pAdapter->uData.guidData, sizeof( GUID ) ); LEAVELOCK(); return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::SetDevice" HRESULT DP8ADDRESSOBJECT::SetDevice( const GUID * const pGuid ) { HRESULT hr; if( pGuid == NULL ) { DPFX(DPFPREP, 0, "Invalid pointer" ); return DPNERR_INVALIDPOINTER; } hr = SetElement( DPNA_KEY_DEVICE, pGuid, sizeof( GUID ), DPNA_DATATYPE_GUID ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Adding SP element failed hr=0x%x", hr ); } return hr; } #endif // ! DPNBUILD_ONLYONEADAPTER #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::SetUserData" HRESULT DP8ADDRESSOBJECT::SetUserData( const void * const pvData, const DWORD dwDataSize ) { if( pvData == NULL && dwDataSize > 0 ) { DPFX(DPFPREP, 0, "Invalid param" ); return DPNERR_INVALIDPARAM; } ENTERLOCK(); if( m_dwUserDataSize > 0 ) { // Remove escaped user data m_dwStringSize -= m_dwUserDataStringSize; } if( dwDataSize == 0 ) { m_dwUserDataSize = 0; if( m_pvUserData != NULL ) DNFree(m_pvUserData); m_pvUserData = NULL; LEAVELOCK(); return DPN_OK; } PBYTE pNewDataBuffer; if( dwDataSize > m_dwUserDataSize ) { pNewDataBuffer = (BYTE*) DNMalloc(dwDataSize); if( pNewDataBuffer == NULL ) { DPFX(DPFPREP, 0, "Error allocating memory" ); LEAVELOCK(); return DPNERR_OUTOFMEMORY; } if( m_pvUserData != NULL ) { DNFree(m_pvUserData); } m_pvUserData = pNewDataBuffer; } m_dwUserDataStringSize = CalcExpandedBinarySize( (PBYTE) pvData, dwDataSize ); m_dwStringSize += m_dwUserDataStringSize; m_dwStringSize += DNURL_LENGTH_USERDATA_SEPERATOR; memcpy( m_pvUserData, pvData, dwDataSize ); m_dwUserDataSize = dwDataSize; LEAVELOCK(); return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::GetUserData" HRESULT DP8ADDRESSOBJECT::GetUserData( void * pvDataBuffer, PDWORD pdwDataSize ) { if( pdwDataSize == NULL ) { DPFX(DPFPREP, 0, "Must specify a pointer for the size" ); return DPNERR_INVALIDPOINTER; } ENTERLOCK(); if( m_dwUserDataSize == 0 ) { LEAVELOCK(); DPFX(DPFPREP, DP8A_WARNINGLEVEL, "No user data was specified for this address" ); return DPNERR_DOESNOTEXIST; } if( *pdwDataSize < m_dwUserDataSize ) { *pdwDataSize = m_dwUserDataSize; LEAVELOCK(); DPFX(DPFPREP, DP8A_WARNINGLEVEL, "Buffer too small" ); return DPNERR_BUFFERTOOSMALL; } memcpy( pvDataBuffer, m_pvUserData, m_dwUserDataSize ); LEAVELOCK(); return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::Cleanup" HRESULT DP8ADDRESSOBJECT::Cleanup() { Clear(); return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::CalcExpandedBinarySize" DWORD DP8ADDRESSOBJECT::CalcExpandedBinarySize( PBYTE pbData, DWORD dwDataSize ) { PBYTE pbCurrentLocation = pbData; DWORD dwCount = 0; for( DWORD dwIndex = 0; dwIndex < dwDataSize; dwIndex++ ) { if( IsEscapeChar( (WCHAR) *pbCurrentLocation ) ) { if( ((WCHAR) *pbCurrentLocation) == DPNA_ESCAPECHAR ) dwCount += 2; else dwCount+=3; } else { dwCount++; } pbCurrentLocation++; } return dwCount; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::CalcExpandedStringSize" DWORD DP8ADDRESSOBJECT::CalcExpandedStringSize( WCHAR *szString ) { WCHAR *szCurrentLocation = szString; DWORD dwCount = 0; while( *szCurrentLocation ) { if( IsEscapeChar( *szCurrentLocation ) ) { if( *szCurrentLocation == DPNA_ESCAPECHAR ) dwCount += 2; else dwCount+=3; } else { dwCount++; } szCurrentLocation++; } return dwCount; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::CalcComponentStringSize" HRESULT DP8ADDRESSOBJECT::CalcComponentStringSize( PDP8ADDRESSELEMENT paddElement, PDWORD pdwSize ) { if( paddElement == NULL ) return DPNERR_INVALIDPOINTER; if( paddElement->dwType == DPNA_DATATYPE_GUID ) { *pdwSize = DNURL_LENGTH_GUID; } else if( paddElement->dwType == DPNA_DATATYPE_DWORD ) { WCHAR tmpString[DNURL_LENGTH_DWORD+1]; swprintf( tmpString, L"%u", paddElement->uData.dwData ); *pdwSize = wcslen(tmpString); } // No WWCHARs need to be escaped else if( paddElement->dwType == DPNA_DATATYPE_STRING ) { #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL if( paddElement->dwFlags & DP8ADDRESS_ELEMENT_HEAP ) { *pdwSize = CalcExpandedStringSize( (WCHAR *) paddElement->uData.pvData ); } else #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL { *pdwSize = CalcExpandedStringSize( paddElement->uData.szData ); } } // Every WWCHAR needs to be escaped else { #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL if( paddElement->dwFlags & DP8ADDRESS_ELEMENT_HEAP ) { *pdwSize = CalcExpandedBinarySize( (BYTE *) paddElement->uData.pvData, paddElement->dwDataSize ); } else #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL { *pdwSize = CalcExpandedBinarySize( (BYTE *) paddElement->uData.szData, paddElement->dwDataSize ); } } // Add on the tag *pdwSize += paddElement->dwTagSize-1; // Add on the = and the ; (*pdwSize) ++; return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::IsEscapeChar" BOOL DP8ADDRESSOBJECT::IsEscapeChar( WCHAR ch ) { if( ch >= L'A' && ch <= L'Z' ) return FALSE; if( ch >= L'a' && ch <= L'z' ) return FALSE; if( ch >= L'0' && ch <= L'9' ) return FALSE; if( ch == L'-' || ch == L'?' || ch == L'.' || ch == L',' || ch == 'L+' || ch == L'_' ) return FALSE; return TRUE; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::BuildURL_AddString" void DP8ADDRESSOBJECT::BuildURL_AddString( WCHAR *szElements, WCHAR *szSource ) { WCHAR *szSourceLoc = szSource; WCHAR tmpEscape[4]; DWORD dwIndex; while( *szSourceLoc ) { if( IsEscapeChar( *szSourceLoc ) ) { if( *szSourceLoc == DPNA_ESCAPECHAR ) { wcscat( szElements, L"%%" ); } else { swprintf( tmpEscape, L"%%%02.2X", (DWORD) *szSourceLoc ); wcscat( szElements, tmpEscape ); } } else { dwIndex = wcslen(szElements); szElements[dwIndex] = *szSourceLoc; szElements[dwIndex+1] = 0; } szSourceLoc++; } } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::BuildURL_AddElements" HRESULT DP8ADDRESSOBJECT::BuildURL_AddElements( WCHAR *szElements ) { DP8ADDRESSELEMENT *pCurrentElement; CBilink *pblRunner; WCHAR tmpString[DNURL_LENGTH_GUID+2]; #ifdef DPNBUILD_ONLYONESP BOOL fFirstElement = FALSE; // built-in provider always comes first #else // ! DPNBUILD_ONLYONESP BOOL fFirstElement = TRUE; #endif // ! DPNBUILD_ONLYONESP DWORD dwTmpLength; pblRunner = m_blAddressElements.GetNext(); while( pblRunner != &m_blAddressElements ) { pCurrentElement = CONTAINING_OBJECT(pblRunner, DP8ADDRESSELEMENT, blAddressElements); if( !fFirstElement ) { dwTmpLength = wcslen(szElements); szElements[dwTmpLength] = DPNA_SEPARATOR_COMPONENT; szElements[dwTmpLength+1] = 0; } wcscat( szElements, pCurrentElement->pszTag ); dwTmpLength = wcslen(szElements); szElements[dwTmpLength] = DPNA_SEPARATOR_KEYVALUE; szElements[dwTmpLength+1] = 0; if( pCurrentElement->dwType == DPNA_DATATYPE_STRING ) { #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL if( pCurrentElement->dwFlags & DP8ADDRESS_ELEMENT_HEAP ) { BuildURL_AddString( szElements, (WCHAR *) pCurrentElement->uData.pvData ); } else #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL { BuildURL_AddString( szElements, pCurrentElement->uData.szData ); } } else if( pCurrentElement->dwType == DPNA_DATATYPE_GUID ) { swprintf( tmpString, L"%%7B%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X%%7D", pCurrentElement->uData.guidData.Data1, pCurrentElement->uData.guidData.Data2, pCurrentElement->uData.guidData.Data3, pCurrentElement->uData.guidData.Data4[0], pCurrentElement->uData.guidData.Data4[1], pCurrentElement->uData.guidData.Data4[2], pCurrentElement->uData.guidData.Data4[3], pCurrentElement->uData.guidData.Data4[4], pCurrentElement->uData.guidData.Data4[5], pCurrentElement->uData.guidData.Data4[6], pCurrentElement->uData.guidData.Data4[7] ); wcscat( szElements, tmpString ); } else if( pCurrentElement->dwType == DPNA_DATATYPE_DWORD ) { swprintf( tmpString, L"%u", pCurrentElement->uData.dwData ); wcscat( szElements, tmpString ); } // Binary else { #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL if( pCurrentElement->dwFlags & DP8ADDRESS_ELEMENT_HEAP ) { BuildURL_AddBinaryData( szElements, (BYTE *) pCurrentElement->uData.pvData , pCurrentElement->dwDataSize ); } else #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL { BuildURL_AddBinaryData( szElements, ((BYTE *) &pCurrentElement->uData), pCurrentElement->dwDataSize ); } } fFirstElement = FALSE; pblRunner = pblRunner->GetNext(); } return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::BuildURL_AddHeader" HRESULT DP8ADDRESSOBJECT::BuildURL_AddHeader( WCHAR *szWorking ) { WCHAR *szReturn; #ifdef DPNBUILD_ONLYONESP wcscpy( szWorking, DPNA_HEADER DPNA_BUILTINPROVIDER ); szReturn = szWorking + DNURL_LENGTH_HEADER + DNURL_LENGTH_BUILTINPROVIDER; #else // ! DPNBUILD_ONLYONESP wcscpy( szWorking, DPNA_HEADER ); szReturn = szWorking + DNURL_LENGTH_HEADER; #endif // ! DPNBUILD_ONLYONESP return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::BuildURL_AddUserData" HRESULT DP8ADDRESSOBJECT::BuildURL_AddUserData(WCHAR * szWorking) { return BuildURL_AddBinaryData( szWorking, (BYTE *) m_pvUserData, m_dwUserDataSize ); } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::BuildURL_AddBinaryData" HRESULT DP8ADDRESSOBJECT::BuildURL_AddBinaryData( WCHAR *szSource, BYTE *bData, DWORD dwDataLen ) { WCHAR *pwszCurrentDest = szSource + wcslen(szSource); BYTE *pbCurrentData = bData; DWORD dwDataRemaining = dwDataLen; dwDataRemaining = dwDataLen; while ( dwDataRemaining > 0 ) { if( IsEscapeChar( (WCHAR) *pbCurrentData ) ) { if( ((WCHAR) *pbCurrentData) == DPNA_ESCAPECHAR ) { wcscpy(pwszCurrentDest, L"%%"); pwszCurrentDest += 2; } else { pwszCurrentDest += swprintf( pwszCurrentDest, L"%%%02.2X", (DWORD) *pbCurrentData ); } } else { *pwszCurrentDest = (WCHAR) *pbCurrentData; pwszCurrentDest++; } pbCurrentData++; dwDataRemaining--; } // Ensure the string is NULL terminated if we added anything. if ( dwDataLen > 0 ) { *pwszCurrentDest = 0; } return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::BuildURLA" HRESULT DP8ADDRESSOBJECT::BuildURLA( char * szURL, PDWORD pdwRequiredSize ) { HRESULT hr; WCHAR wszStackTemp[256]; WCHAR * pwszTemp; DWORD dwSize; ENTERLOCK(); if( *pdwRequiredSize < m_dwStringSize || szURL == NULL ) { *pdwRequiredSize = m_dwStringSize; DPFX(DPFPREP, DP8A_WARNINGLEVEL, "Buffer too small" ); LEAVELOCK(); return DPNERR_BUFFERTOOSMALL; } // Allocate a buffer if the string is too large to convert in our // stack based buffer. if ((m_dwStringSize * sizeof(WCHAR)) > sizeof(wszStackTemp)) { pwszTemp = (WCHAR*) DNMalloc(m_dwStringSize * sizeof(WCHAR)); if (pwszTemp == NULL) { DPFX(DPFPREP, 0, "Error allocating memory for conversion"); LEAVELOCK(); return DPNERR_OUTOFMEMORY; } dwSize = m_dwStringSize; } else { pwszTemp = wszStackTemp; dwSize = sizeof(wszStackTemp) / sizeof(WCHAR); } // BuildURLW takes the lock again. hr = BuildURLW( pwszTemp, &dwSize ); if( FAILED( hr ) ) { LEAVELOCK(); return hr; } hr = STR_jkWideToAnsi(szURL, pwszTemp, dwSize); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Error unable to convert element ANSI->Unicode 0x%x", hr ); hr = DPNERR_CONVERSION; } else { *pdwRequiredSize = dwSize; } if (pwszTemp != wszStackTemp) { DNFree(pwszTemp); pwszTemp = NULL; } LEAVELOCK(); return hr; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::BuildURLW" HRESULT DP8ADDRESSOBJECT::BuildURLW( WCHAR * szURL, PDWORD pdwRequiredSize ) { HRESULT hr; ENTERLOCK(); if( *pdwRequiredSize < m_dwStringSize || szURL == NULL ) { *pdwRequiredSize = m_dwStringSize; DPFX(DPFPREP, DP8A_WARNINGLEVEL, "Buffer too small" ); LEAVELOCK(); return DPNERR_BUFFERTOOSMALL; } hr = BuildURL_AddHeader( szURL ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Error adding header hr=0x%x", hr ); LEAVELOCK(); return hr; } hr = BuildURL_AddElements( szURL ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Error adding elements hr=0x%x", hr ); LEAVELOCK(); return hr; } hr = BuildURL_AddUserData( szURL ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Error adding user data hr=0x%x", hr ); LEAVELOCK(); return hr; } LEAVELOCK(); *pdwRequiredSize = m_dwStringSize; return DPN_OK; } #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::SetURL" HRESULT DP8ADDRESSOBJECT::SetURL( WCHAR * szURL ) { HRESULT hr; DP8ADDRESSPARSE dp8aParser; hr = Clear(); if( FAILED( hr ) ) { DPFX(DPFPREP, DP8A_ERRORLEVEL, "Unable to clear existing address hr=0x%x", hr ); return hr; } ENTERLOCK(); hr = dp8aParser.ParseURL(this, szURL); if( FAILED( hr ) ) { DPFX(DPFPREP, DP8A_ERRORLEVEL, "Error parsing the URL hr=0x%x", hr ); LEAVELOCK(); return hr; } LEAVELOCK(); return hr; } #ifndef DPNBUILD_NOLEGACYDP #undef DPF_MODNAME #define DPF_MODNAME "DP8ADDRESSOBJECT::SetDirectPlay4Address" HRESULT DP8ADDRESSOBJECT::SetDirectPlay4Address( void * pvDataBuffer, const DWORD dwDataSize ) { PBYTE pbCurrentLocation; PDPADDRESS pdpAddressChunk; LONG lRemaining; HRESULT hr = DPN_OK; DWORD dwCurrentChunkSize; DWORD dwNumElementsParsed = 0; ENTERLOCK(); hr = Clear(); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Failed to clear old address data hr=[0x%lx]", hr ); LEAVELOCK(); return hr; } pbCurrentLocation = (PBYTE) pvDataBuffer; lRemaining = dwDataSize; while( lRemaining > 0 ) { pdpAddressChunk = (PDPADDRESS) pbCurrentLocation; if( sizeof( DPADDRESS ) > lRemaining ) { DPFX(DPFPREP, 0, "Error parsing address, unexpected end of address" ); LEAVELOCK(); return DPNERR_INVALIDADDRESSFORMAT; } dwCurrentChunkSize = sizeof( DPADDRESS ) + pdpAddressChunk->dwDataSize; if( ((LONG) dwCurrentChunkSize) > lRemaining ) { DPFX(DPFPREP, 0, "Error parsing address, unexpected end during data" ); LEAVELOCK(); return DPNERR_INVALIDADDRESSFORMAT; } hr = AddDP4Element( pdpAddressChunk, this ); if( FAILED( hr ) ) { DPFX(DPFPREP, 0, "Error adding next element" ); break; } lRemaining -= dwCurrentChunkSize; pbCurrentLocation += dwCurrentChunkSize; } LEAVELOCK(); return hr; } #endif // ! DPNBUILD_NOLEGACYDP