You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1028 lines
28 KiB
1028 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
handle.cxx
|
|
|
|
Abstract:
|
|
|
|
Contains functions to allocate and deallocate handle values for various
|
|
Windows Internet Extensions DLL 'objects'
|
|
|
|
Functions in this module generate pseudo-handle values and free them when
|
|
no longer required. Each handle value is generated from its position within
|
|
a (2K) bitmap (== 16K handles max.). We also maintain an array that is used
|
|
to map the generated handle to the address of the handle object that it
|
|
represents
|
|
|
|
Contents:
|
|
HandleInitialize
|
|
HandleTerminate
|
|
AllocateHandle
|
|
FreeHandle
|
|
MapHandleToAddress
|
|
DereferenceObject
|
|
(BitToIndex)
|
|
|
|
Author:
|
|
|
|
Richard L Firth (rfirth) 31-Oct-1994
|
|
|
|
Revision History:
|
|
|
|
11-Jan-1996 rfirth
|
|
Use fixed memory instead of moveable (Win95 has a bug w/ LocalUnlock)
|
|
|
|
31-Oct-1994 rfirth
|
|
Created
|
|
|
|
--*/
|
|
|
|
#include <wininetp.h>
|
|
|
|
//
|
|
// manifests
|
|
//
|
|
|
|
#define BASE_HANDLE_VALUE 0x00cc0000
|
|
#define HANDLE_INCREMENT 4
|
|
#define BITS_PER_BYTE 8
|
|
#define BITS_IN_DWORD (sizeof(DWORD) * BITS_PER_BYTE)
|
|
#define FULL_DWORD ((DWORD)-1)
|
|
#define MAXIMUM_HANDLE_NUMBER (64 K)
|
|
#define MAXIMUM_HANDLE_COUNT ((MAXIMUM_HANDLE_NUMBER / HANDLE_INCREMENT) - 1)
|
|
#define MAXIMUM_DWORD_INDEX ((MAXIMUM_HANDLE_COUNT + BITS_IN_DWORD - 1) / BITS_IN_DWORD)
|
|
#define MINIMUM_HANDLE_VALUE (BASE_HANDLE_VALUE + HANDLE_INCREMENT)
|
|
#define MAXIMUM_HANDLE_VALUE (BASE_HANDLE_VALUE + MAXIMUM_HANDLE_NUMBER - HANDLE_INCREMENT)
|
|
#define INITIAL_MAP_LENGTH 16 // 512 handles == 2048 bytes
|
|
#define HANDLE_MAP_INCREMENT 16
|
|
|
|
// Warning: In order for 64-bit compatibility, the range of handle
|
|
// values must be restricted to quantities representable by 32-bits.
|
|
// If maximum handle value >= 4GB the implementation has to change
|
|
// use 64-bit integral types internally.
|
|
|
|
//
|
|
// macros
|
|
//
|
|
|
|
#define NEXT_HANDLE_VALUE(d, i) (BASE_HANDLE_VALUE + ((d) * BITS_IN_DWORD + ((i) + 1)) * HANDLE_INCREMENT)
|
|
|
|
//
|
|
// private prototypes
|
|
//
|
|
|
|
PRIVATE
|
|
inline
|
|
DWORD
|
|
BitToIndex(
|
|
IN DWORD Bit
|
|
);
|
|
|
|
//
|
|
// private data
|
|
//
|
|
|
|
PRIVATE CRITICAL_SECTION HandleMapCritSec; // protects access to following variables
|
|
PRIVATE LPDWORD HandleMap = NULL; // bitmap of allocated handles
|
|
PRIVATE DWORD HandleMapLength; // number of DWORDs in HandleMap
|
|
PRIVATE DWORD NextHandleMapDword = 0; // first bitmap DWORD to check
|
|
PRIVATE DWORD NextHandleMapBit = 1; // map of first bit to check
|
|
PRIVATE DWORD NextHandleMapBitIndex = 0; // position of first bit in first DWORD
|
|
PRIVATE DWORD NextHandleValue = MINIMUM_HANDLE_VALUE;
|
|
PRIVATE DWORD NextHandleIndex = 0;
|
|
PRIVATE BOOL Initialized = FALSE;
|
|
PRIVATE LPVOID * MapArray = NULL;
|
|
PRIVATE DWORD MapArrayLength = 0;
|
|
|
|
//
|
|
// functions
|
|
//
|
|
|
|
DWORD
|
|
HandleInitialize(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs initialization required by functions in this module
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
|
|
Failure - return code from LocalAlloc
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_HANDLE,
|
|
Dword,
|
|
"HandleInitialize",
|
|
NULL
|
|
));
|
|
|
|
InitializeCriticalSection(&HandleMapCritSec);
|
|
HandleMapLength = INITIAL_MAP_LENGTH;
|
|
|
|
DWORD error;
|
|
|
|
//
|
|
// ResizeBuffer() doesn't use LMEM_ZEROINIT
|
|
//
|
|
|
|
HandleMap = (LPDWORD)ALLOCATE_MEMORY(LMEM_ZEROINIT,
|
|
HandleMapLength * sizeof(DWORD)
|
|
);
|
|
if (HandleMap != NULL) {
|
|
MapArrayLength = INITIAL_MAP_LENGTH * BITS_IN_DWORD;
|
|
MapArray = (LPVOID *)ALLOCATE_MEMORY(LMEM_ZEROINIT,
|
|
MapArrayLength * sizeof(LPVOID)
|
|
);
|
|
if (MapArray != NULL) {
|
|
Initialized = TRUE;
|
|
error = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (!HandleMap || !MapArray) {
|
|
error = GetLastError();
|
|
HandleTerminate();
|
|
}
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
VOID
|
|
HandleTerminate(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Obverse of HandleInitialize - frees any system resources allocated by
|
|
HandleInitialize
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_HANDLE,
|
|
None,
|
|
"HandleTerminate",
|
|
NULL
|
|
));
|
|
|
|
if (Initialized) {
|
|
|
|
//
|
|
// there shouldn't be any other threads active when this function is
|
|
// called but we'll grab the critical section anyway, just to make sure
|
|
//
|
|
|
|
EnterCriticalSection(&HandleMapCritSec);
|
|
|
|
//
|
|
// free up the memory occupied by the handle bitmap and map array
|
|
//
|
|
|
|
if (HandleMap != NULL) {
|
|
HandleMap = (LPDWORD)FREE_MEMORY((HLOCAL)HandleMap);
|
|
}
|
|
|
|
INET_ASSERT(HandleMap == NULL);
|
|
|
|
if (MapArray != NULL) {
|
|
MapArray = (LPVOID *)FREE_MEMORY((HLOCAL)MapArray);
|
|
}
|
|
|
|
INET_ASSERT(MapArray == NULL);
|
|
|
|
//
|
|
// no longer initialized
|
|
//
|
|
|
|
Initialized = FALSE;
|
|
|
|
//
|
|
// and reset the variables
|
|
//
|
|
|
|
HandleMapLength = 0;
|
|
NextHandleMapDword = 0;
|
|
NextHandleMapBit = 1;
|
|
NextHandleMapBitIndex = 0;
|
|
NextHandleValue = MINIMUM_HANDLE_VALUE;
|
|
NextHandleIndex = 0;
|
|
MapArrayLength = 0;
|
|
|
|
LeaveCriticalSection(&HandleMapCritSec);
|
|
|
|
//
|
|
// delete the critical section
|
|
//
|
|
|
|
DeleteCriticalSection(&HandleMapCritSec);
|
|
}
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
|
|
DWORD
|
|
AllocateHandle(
|
|
IN LPVOID Address,
|
|
OUT LPHINTERNET lpHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generic handle allocator function which generates a unique handle value for
|
|
any object. The handle value is simply a number, slightly massaged to give a
|
|
value that can be easily differentiated from other Win32 handle ranges (for
|
|
debugging purposes mainly, and also to protect against illegal use of
|
|
handles (such as treating as a pointer and dereferencing it)).
|
|
|
|
The range of handles are kept in a bitmap, composed of DWORDs. The next
|
|
allocated handle is simply the index of the next free bit in the map. The
|
|
map is extended if we run out of handles (up to 16K-1 handles (== 2K bytes)).
|
|
|
|
If the map needs to be extended we don't go to the trouble to reduce it
|
|
again. For the sake of 2K bytes max (currently), its not worth the effort.
|
|
|
|
This function does not rely on knowing the type of object for which the
|
|
handle is being generated, and only requires serialization via a critical
|
|
section.
|
|
|
|
This function can increase the values of these variables:
|
|
|
|
NextHandleMapDword
|
|
NextHandleMapBit
|
|
NextHandleMapBitIndex
|
|
NextHandleValue
|
|
NextHandleIndex
|
|
|
|
Arguments:
|
|
|
|
Address - the (object address) value which will be associated with the
|
|
returned handle
|
|
|
|
lpHandle - place to return the allocated handle
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
|
|
Failure - ERROR_INTERNET_OUT_OF_HANDLES
|
|
16K-1 (currently) handles are outstanding!
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY etc.
|
|
problems with Win32 memory/heap management?
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_HANDLE,
|
|
Dword,
|
|
"AllocateHandle",
|
|
"%#x, %#x",
|
|
Address,
|
|
lpHandle
|
|
));
|
|
|
|
DWORD error;
|
|
|
|
//
|
|
// can't associate a NULL address with the generated handle
|
|
//
|
|
|
|
INET_ASSERT(Address != NULL);
|
|
|
|
//
|
|
// default returned handle
|
|
//
|
|
|
|
*lpHandle = NULL;
|
|
|
|
//
|
|
// in case this function is being called before we have initialized this
|
|
// module, or after we have terminated it, return an error
|
|
//
|
|
|
|
if (!Initialized) {
|
|
error = ERROR_INTERNET_SHUTDOWN;
|
|
goto quit;
|
|
}
|
|
|
|
error = ERROR_INTERNET_OUT_OF_HANDLES;
|
|
|
|
EnterCriticalSection(&HandleMapCritSec);
|
|
|
|
if (HandleMap == NULL) {
|
|
|
|
//
|
|
// don't ever expect this?
|
|
//
|
|
|
|
INET_ASSERT(FALSE);
|
|
|
|
error = ERROR_INTERNET_INTERNAL_ERROR;
|
|
goto unlock_exit;
|
|
}
|
|
|
|
while (NextHandleMapDword != MAXIMUM_DWORD_INDEX) {
|
|
|
|
//
|
|
// if we reached the end of the map the last time, we must reallocate
|
|
//
|
|
|
|
if (NextHandleMapDword == HandleMapLength) {
|
|
|
|
HLOCAL newHandleMap;
|
|
|
|
newHandleMap = REALLOCATE_MEMORY((HLOCAL)HandleMap,
|
|
(HandleMapLength + HANDLE_MAP_INCREMENT)
|
|
* sizeof(DWORD),
|
|
LMEM_MOVEABLE | LMEM_ZEROINIT
|
|
);
|
|
|
|
HLOCAL newMapArray;
|
|
|
|
newMapArray = REALLOCATE_MEMORY((HLOCAL)MapArray,
|
|
(HandleMapLength + HANDLE_MAP_INCREMENT)
|
|
* BITS_IN_DWORD
|
|
* sizeof(LPVOID),
|
|
LMEM_MOVEABLE | LMEM_ZEROINIT
|
|
);
|
|
if ((newHandleMap != NULL) && (newMapArray != NULL)) {
|
|
HandleMapLength += HANDLE_MAP_INCREMENT;
|
|
HandleMap = (LPDWORD)newHandleMap;
|
|
MapArrayLength += HANDLE_MAP_INCREMENT * BITS_IN_DWORD;
|
|
MapArray = (LPVOID *)newMapArray;
|
|
|
|
DEBUG_PRINT(HANDLE,
|
|
INFO,
|
|
("re-allocated %d DWORDs: HandleMap = %#x MapArray = %#x\n",
|
|
HandleMapLength,
|
|
HandleMap,
|
|
MapArray
|
|
));
|
|
|
|
} else {
|
|
|
|
error = GetLastError();
|
|
|
|
DEBUG_PRINT(HANDLE,
|
|
ERROR,
|
|
("REALLOCATE_MEMORY() returns %d\n",
|
|
error
|
|
));
|
|
|
|
break;
|
|
}
|
|
} else if (NextHandleValue <= MAXIMUM_HANDLE_VALUE) {
|
|
HandleMap[NextHandleMapDword] |= NextHandleMapBit;
|
|
|
|
//
|
|
// first handle value returned is 0x00cc0004
|
|
//
|
|
|
|
DEBUG_PRINT(HANDLE,
|
|
INFO,
|
|
("handle = %#x, index = %d\n",
|
|
NextHandleValue,
|
|
NextHandleIndex
|
|
));
|
|
|
|
*lpHandle = (HINTERNET)(DWORD_PTR)NextHandleValue;
|
|
|
|
//
|
|
// store it in the map array at the specified index
|
|
//
|
|
|
|
INET_ASSERT(MapArray[NextHandleIndex] == NULL);
|
|
|
|
MapArray[NextHandleIndex] = Address;
|
|
|
|
error = ERROR_SUCCESS;
|
|
|
|
//
|
|
// find the next available bit for the next caller. Search up
|
|
// to the end of the currently allocated map. If we don't find
|
|
// it, the next caller will attempt to allocate a new DWORD
|
|
// (unless a lower handle gets freed meantime)
|
|
//
|
|
|
|
while (NextHandleMapDword < HandleMapLength) {
|
|
if (HandleMap[NextHandleMapDword] != FULL_DWORD) {
|
|
while (HandleMap[NextHandleMapDword] & NextHandleMapBit) {
|
|
NextHandleMapBit <<= 1;
|
|
++NextHandleMapBitIndex;
|
|
NextHandleValue += HANDLE_INCREMENT;
|
|
++NextHandleIndex;
|
|
}
|
|
} else {
|
|
NextHandleMapBit = 0;
|
|
}
|
|
if (NextHandleMapBit != 0) {
|
|
break;
|
|
} else {
|
|
|
|
//
|
|
// reached the end of a DWORD. Start the next
|
|
//
|
|
|
|
++NextHandleMapDword;
|
|
NextHandleMapBit = 1;
|
|
NextHandleMapBitIndex = 0;
|
|
|
|
//
|
|
// recalculate the next handle value
|
|
//
|
|
|
|
NextHandleValue = NEXT_HANDLE_VALUE(NextHandleMapDword,
|
|
NextHandleMapBitIndex
|
|
);
|
|
|
|
//
|
|
// and map array index
|
|
//
|
|
|
|
NextHandleIndex = NextHandleMapDword * BITS_IN_DWORD;
|
|
}
|
|
}
|
|
break;
|
|
} else {
|
|
|
|
//
|
|
// reached maximum handle value - return error
|
|
//
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
unlock_exit:
|
|
|
|
LeaveCriticalSection(&HandleMapCritSec);
|
|
|
|
quit:
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
DWORD
|
|
FreeHandle(
|
|
IN HINTERNET Handle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The obverse function to AllocateHandle. Frees up a previously allocated
|
|
handle value. If this handle has a lower index than the currently selected
|
|
next index (Dword and Bit) then the next index is modified
|
|
|
|
This function can reduce the values of these variables:
|
|
|
|
NextHandleMapDword
|
|
NextHandleMapBit
|
|
NextHandleMapBitIndex
|
|
NextHandleValue
|
|
NextHandleIndex
|
|
|
|
Arguments:
|
|
|
|
Handle - handle value previously allocated via AllocateHandle
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
|
|
Failure - ERROR_INVALID_HANDLE
|
|
We don't think this handle was generated by AllocateHandle
|
|
or the corresponding bit in the map is already 0
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_HANDLE,
|
|
Dword,
|
|
"FreeHandle",
|
|
"%#x",
|
|
Handle
|
|
));
|
|
|
|
DWORD error;
|
|
|
|
//
|
|
// ensure that we are in the correct state
|
|
//
|
|
|
|
if (!Initialized) {
|
|
error = ERROR_INTERNET_SHUTDOWN;
|
|
goto quit;
|
|
}
|
|
|
|
error = ERROR_INVALID_HANDLE;
|
|
|
|
//
|
|
// error if 0x00cc0000 > Handle > 0x00ccfffc
|
|
//
|
|
|
|
if ((PtrToUlong(Handle) < MINIMUM_HANDLE_VALUE)
|
|
|| (PtrToUlong(Handle) > MAXIMUM_HANDLE_VALUE)) {
|
|
goto quit;
|
|
}
|
|
|
|
//
|
|
// get the map DWORD index and bit mask from the handle
|
|
//
|
|
DWORD index;
|
|
|
|
index = (PtrToUlong(Handle) - MINIMUM_HANDLE_VALUE) / (BITS_IN_DWORD * HANDLE_INCREMENT);
|
|
|
|
DWORD bit;
|
|
|
|
bit = 1 << (((PtrToUlong(Handle) - MINIMUM_HANDLE_VALUE) / HANDLE_INCREMENT) & (BITS_IN_DWORD - 1));
|
|
|
|
DWORD mapIndex;
|
|
|
|
mapIndex = (PtrToUlong(Handle) - MINIMUM_HANDLE_VALUE) / HANDLE_INCREMENT;
|
|
|
|
EnterCriticalSection(&HandleMapCritSec);
|
|
|
|
//
|
|
// the index may be in range, but greater than the currently allocated
|
|
// map length, in which case its an error
|
|
//
|
|
|
|
if (index < HandleMapLength) {
|
|
if (HandleMap != NULL) {
|
|
if (HandleMap[index] & bit) {
|
|
|
|
BOOL recalc = FALSE;
|
|
|
|
DEBUG_PRINT(HANDLE,
|
|
INFO,
|
|
("handle = %#x, index = %d, address = %#x\n",
|
|
Handle,
|
|
mapIndex,
|
|
MapArray[mapIndex]
|
|
));
|
|
|
|
HandleMap[index] &= ~bit;
|
|
MapArray[mapIndex] = NULL;
|
|
|
|
error = ERROR_SUCCESS;
|
|
|
|
//
|
|
// if we have cleared a bit lower in the bitmap than the current
|
|
// index and bit indicators, then reset the indicators to the
|
|
// new position
|
|
//
|
|
|
|
if (index < NextHandleMapDword) {
|
|
|
|
//
|
|
// new DWORD is lower than current: change all variables
|
|
// to those for this handle
|
|
//
|
|
|
|
NextHandleMapDword = index;
|
|
recalc = TRUE;
|
|
} else if ((index == NextHandleMapDword) && (bit < NextHandleMapBit)) {
|
|
|
|
//
|
|
// same DWORD index, lower bit position
|
|
//
|
|
|
|
recalc = TRUE;
|
|
}
|
|
if (recalc) {
|
|
NextHandleMapBit = bit;
|
|
NextHandleMapBitIndex = BitToIndex(bit);
|
|
|
|
//
|
|
// recalculate the next handle value
|
|
//
|
|
|
|
NextHandleValue = NEXT_HANDLE_VALUE(NextHandleMapDword,
|
|
NextHandleMapBitIndex
|
|
);
|
|
|
|
//
|
|
// and map array index
|
|
//
|
|
|
|
NextHandleIndex = (NextHandleMapDword * BITS_IN_DWORD)
|
|
+ NextHandleMapBitIndex;
|
|
}
|
|
} else {
|
|
|
|
DEBUG_PRINT(HANDLE,
|
|
ERROR,
|
|
("Handle = %#x. HandleMap[%d].%#x not set\n",
|
|
Handle,
|
|
index,
|
|
bit
|
|
));
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// don't ever expect this to happen
|
|
//
|
|
|
|
error = ERROR_INTERNET_INTERNAL_ERROR;
|
|
|
|
INET_ASSERT(FALSE);
|
|
|
|
}
|
|
} else {
|
|
|
|
DEBUG_PRINT(HANDLE,
|
|
ERROR,
|
|
("Handle = %#x, index = %d, HandleMapLength = %d\n",
|
|
Handle,
|
|
index,
|
|
HandleMapLength
|
|
));
|
|
|
|
}
|
|
|
|
LeaveCriticalSection(&HandleMapCritSec);
|
|
|
|
quit:
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
DWORD
|
|
MapHandleToAddress(
|
|
IN HINTERNET Handle,
|
|
OUT LPVOID * lpAddress,
|
|
IN BOOL Invalidate
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a handle, retrieve its associated address from the map array. The
|
|
handle object represented by Handle is referenced
|
|
|
|
Assumes: 1. only HINTERNETs visible at the API are presented to this
|
|
function. Even though we AllocateHandle() for arbitrary
|
|
objects (e.g. gopher views) we never map their addresses
|
|
|
|
Arguments:
|
|
|
|
Handle - handle value generated by AllocateHandle()
|
|
|
|
lpAddress - place to store mapped address. If the handle has been closed
|
|
and unmapped, NULL is returned. If the handle is still
|
|
mapped, even though it has been invalidated, its address will
|
|
be returned, and its reference count incremented
|
|
|
|
Invalidate - TRUE if we are invalidating this handle
|
|
|
|
Return Value:
|
|
|
|
LPVOID
|
|
Success - ERROR_SUCCESS
|
|
|
|
Failure - ERROR_INVALID_HANDLE
|
|
if *lpAddress == NULL then the handle has been closed and
|
|
unmapped, else it is still mapped, but invalidated. In
|
|
this case, we incremented the reference count
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_HANDLE,
|
|
Dword,
|
|
"MapHandleToAddress",
|
|
"%#x, %#x, %B",
|
|
Handle,
|
|
lpAddress,
|
|
Invalidate
|
|
));
|
|
|
|
LPVOID address = NULL;
|
|
DWORD error = ERROR_INVALID_HANDLE;
|
|
|
|
//
|
|
// error if 0x00cc0000 > Handle > 0x00ccfffc
|
|
//
|
|
|
|
if ((PtrToUlong(Handle) >= MINIMUM_HANDLE_VALUE)
|
|
&& (PtrToUlong(Handle) <= MAXIMUM_HANDLE_VALUE)
|
|
&& !InDllCleanup) {
|
|
|
|
DWORD index = (PtrToUlong(Handle) - MINIMUM_HANDLE_VALUE) / HANDLE_INCREMENT;
|
|
|
|
//
|
|
// the caller could have supplied a value which has the correct range
|
|
// but may not yet have been generated, causing us to index past the
|
|
// end of the array
|
|
//
|
|
|
|
if (index < MapArrayLength) {
|
|
|
|
//
|
|
// we have to acquire the critical section in case another thread
|
|
// is reallocating the array
|
|
//
|
|
|
|
EnterCriticalSection(&HandleMapCritSec);
|
|
|
|
address = MapArray[index];
|
|
|
|
DEBUG_PRINT(HANDLE,
|
|
INFO,
|
|
("Handle %#x mapped to address %#x\n",
|
|
Handle,
|
|
address
|
|
));
|
|
|
|
if (address != NULL) {
|
|
|
|
//
|
|
// although we store addresses of arbitrary structures (e.g.
|
|
// FTP_SESSION_INFO), we are only calling this function to map
|
|
// pseudo-handles to object addresses at the API. Therefore it
|
|
// should be safe to assume that the pointer references a handle
|
|
// object
|
|
// However, there's nothing to stop an app passing in a random
|
|
// handle value that just happens to map to an FTP or gopher
|
|
// session or gopher view, and since we don't want to treat that
|
|
// as a handle object, we must make this test full-time
|
|
//
|
|
|
|
if (((HANDLE_OBJECT *)address)->IsValid(TypeWildHandle) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// this is also a very good time to increment the reference
|
|
// count. We are using the fact that we are serialized on the
|
|
// handle map critical section here. If Reference() returns
|
|
// ERROR_INVALID_HANDLE then the handle object has been
|
|
// invalidated, but its reference count will have been
|
|
// incremented. The caller should perform as little work as
|
|
// necessary and get out.
|
|
//
|
|
// If Refrerence() returns ERROR_ACCESS_DENIED, then the object
|
|
// is being destroyed (refcount already went to zero).
|
|
//
|
|
// If the reference count is incremented to 1 then there is
|
|
// another thread waiting to finish deleting this handle. It
|
|
// is virtually deleted, and if we return its address, the
|
|
// caller will have a deleted object
|
|
//
|
|
|
|
if (((HANDLE_OBJECT *)address)->ReferenceCount() == 0) {
|
|
|
|
DEBUG_PRINT(HANDLE,
|
|
ERROR,
|
|
("handle %#x [%#x] about to be deleted\n",
|
|
Handle,
|
|
address
|
|
));
|
|
|
|
address = NULL;
|
|
} else {
|
|
error = ((HANDLE_OBJECT *)address)->Reference();
|
|
if (error == ERROR_SUCCESS) {
|
|
if (Invalidate) {
|
|
|
|
//
|
|
// we were called from a handle close API.
|
|
// Subsequent API calls will discover that the
|
|
// handle is already invalidated and will quit
|
|
//
|
|
|
|
((HANDLE_OBJECT *)address)->Invalidate();
|
|
}
|
|
} else if (error == ERROR_ACCESS_DENIED) {
|
|
//
|
|
// if we get ERROR_ACCESS_DENIED, this means that the object is
|
|
// being destructed, so we *have* to return NULL.
|
|
//
|
|
DEBUG_PRINT(HANDLE,
|
|
ERROR,
|
|
("Reference() failed - handle %#x [%#x] about to be deleted\n",
|
|
Handle,
|
|
address
|
|
));
|
|
address = NULL;
|
|
} else {
|
|
DEBUG_PRINT(HANDLE,
|
|
ERROR,
|
|
("Reference() returns %d\n",
|
|
error
|
|
));
|
|
|
|
//
|
|
// if invalid and reference count already zero, we
|
|
// didn't increment ref count: handle already being
|
|
// deleted
|
|
//
|
|
|
|
if (((HANDLE_OBJECT *)address)->ReferenceCount() == 0) {
|
|
address = NULL;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// we still want to know about it in debug version
|
|
//
|
|
|
|
DEBUG_PRINT(HANDLE,
|
|
ERROR,
|
|
("invalid handle object: %#x [%#x]\n",
|
|
Handle,
|
|
address
|
|
));
|
|
|
|
IF_DEBUG(INVALID_HANDLES) {
|
|
//INET_ASSERT(FALSE);
|
|
}
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// lets also catch this one (NULL address)
|
|
//
|
|
|
|
DEBUG_PRINT(HANDLE,
|
|
ERROR,
|
|
("NULL handle: %#x\n",
|
|
Handle
|
|
));
|
|
|
|
IF_DEBUG(INVALID_HANDLES) {
|
|
//INET_ASSERT(FALSE);
|
|
}
|
|
}
|
|
LeaveCriticalSection(&HandleMapCritSec);
|
|
}
|
|
} else if (InDllCleanup) {
|
|
error = ERROR_INTERNET_SHUTDOWN;
|
|
} else {
|
|
|
|
DEBUG_PRINT(HANDLE,
|
|
ERROR,
|
|
("bad handle value: %#x\n",
|
|
Handle
|
|
));
|
|
|
|
IF_DEBUG(INVALID_HANDLES) {
|
|
//INET_ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
*lpAddress = address;
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
DWORD
|
|
DereferenceObject(
|
|
IN LPVOID lpObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Undoes the reference added to the handle object by MapHandleToAddress(). May
|
|
result in the handle object being deleted
|
|
|
|
Arguments:
|
|
|
|
lpObject - address of object to dereference. This MUST be the mapped
|
|
object address as returned by MapHandleToAddress()
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
The handle object was destroyed
|
|
|
|
Failure - ERROR_INVALID_HANDLE
|
|
The object was not a valid handle
|
|
|
|
ERROR_INTERNET_HANDLE_EXISTS
|
|
The handle is still alive
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_HANDLE,
|
|
Dword,
|
|
"DereferenceObject",
|
|
"%#x",
|
|
lpObject
|
|
));
|
|
|
|
INET_ASSERT(lpObject != NULL);
|
|
|
|
HANDLE_OBJECT * object = (HANDLE_OBJECT *)lpObject;
|
|
DWORD error = object->IsValid(TypeWildHandle);
|
|
|
|
if (error == ERROR_SUCCESS) {
|
|
if (!object->Dereference()) {
|
|
error = ERROR_INTERNET_HANDLE_EXISTS;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// IsValid() should never return an error if the reference counts
|
|
// are correct
|
|
//
|
|
|
|
INET_ASSERT(FALSE);
|
|
|
|
}
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
PRIVATE
|
|
inline
|
|
DWORD
|
|
BitToIndex(
|
|
IN DWORD Bit
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the index of the first bit set in a DWORD
|
|
|
|
Arguments:
|
|
|
|
Bit - bitmap
|
|
|
|
Return Value:
|
|
|
|
DWORD - 0..(BITS_IN_DWORD - 1) if bit found, else BITS_IN_DWORD
|
|
|
|
--*/
|
|
|
|
{
|
|
if (Bit == 0) {
|
|
return BITS_IN_DWORD;
|
|
} else {
|
|
|
|
DWORD index;
|
|
DWORD testBit;
|
|
|
|
for (index = 0, testBit = 1; !(Bit & testBit); ++index, testBit <<= 1) {
|
|
;
|
|
}
|
|
return index;
|
|
}
|
|
}
|