windows-nt/Source/XPSP1/NT/net/layer2svc/zeroconf/server/intfhdl.c
2020-09-26 16:20:57 +08:00

193 lines
5.9 KiB
C

#include <precomp.h>
#include "tracing.h"
#include "utils.h"
#include "intflist.h"
#include "intfhdl.h"
DWORD
OpenIntfHandle(
LPWSTR wszGuid,
PHANDLE pIntfHdl)
{
DWORD dwErr;
PHASH_NODE pNode;
PHSH_HANDLE pHshHandle;
DbgPrint((TRC_TRACK,"[OpenIntfHandle(%S)", wszGuid));
// the caller is supposed to expect the handle in return
// if he doesn't, return with INVALID_PARAMETER.
if (pIntfHdl == NULL)
{
dwErr = ERROR_INVALID_PARAMETER;
goto exit;
}
// lock the hash, to mutual exclude concurrent calls
EnterCriticalSection(&g_hshHandles.csMutex);
// query the hash for the guid.
dwErr = HshQueryObjectRef(
g_hshHandles.pRoot,
wszGuid,
&pNode);
// if the guid in the hash, we already have the handle opened..
if (dwErr == ERROR_SUCCESS)
{
// return it to the caller and bump up the reference counter.
// the caller is still supposed to close this handle when it is
// no longer needed
pHshHandle = (PHSH_HANDLE)pNode->pObject;
pHshHandle->nRefCount++;
*pIntfHdl = pHshHandle->hdlInterf;
DbgPrint((TRC_GENERIC, "OpenIntfHandle -> 0x%x (cached)", *pIntfHdl));
}
// if the guid is not in the hash, we need to open a new handle for
// this guid.
else if (dwErr == ERROR_FILE_NOT_FOUND)
{
HANDLE IntfHdl = INVALID_HANDLE_VALUE;
DWORD dwDummy;
dwErr = ERROR_SUCCESS;
// first allocate memory for the HSH_HANDLE object.
// if this fails no need to go further to ndisuio
pHshHandle = MemCAlloc(sizeof(HSH_HANDLE));
if (pHshHandle == NULL)
dwErr = GetLastError();
// if everything looks fine so far
if (dwErr == ERROR_SUCCESS)
{
// create the handle
IntfHdl = CreateFileA(
"\\\\.\\\\Ndisuio",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
INVALID_HANDLE_VALUE);
if (IntfHdl == INVALID_HANDLE_VALUE)
{
dwErr = GetLastError();
DbgPrint((TRC_ERR,"CreateFileA failed with %d", dwErr));
}
}
// if still fine so far
if (dwErr == ERROR_SUCCESS)
{
// attempt to open the handle
if (!DeviceIoControl(
IntfHdl,
IOCTL_NDISUIO_OPEN_DEVICE,
(LPVOID)wszGuid,
wcslen(wszGuid)*sizeof(WCHAR),
NULL,
0,
&dwDummy,
NULL))
{
dwErr = GetLastError();
DbgPrint((TRC_ERR,"IOCTL_NDISUIO_OPEN_DEVICE failed with %d", dwErr));
}
}
// if finally we're ok here,
if (dwErr == ERROR_SUCCESS)
{
// set up the HSH_HANDLE structure and insert it in the hash
pHshHandle->hdlInterf = IntfHdl;
pHshHandle->nRefCount = 1;
dwErr = HshInsertObjectRef(
g_hshHandles.pRoot,
wszGuid,
pHshHandle,
&g_hshHandles.pRoot);
}
// if ok at the end, return the handle to the caller
if (dwErr == ERROR_SUCCESS)
{
DbgPrint((TRC_GENERIC, "OpenIntfHandle -> 0x%x (new)", IntfHdl));
*pIntfHdl = IntfHdl;
}
// otherwise clear up all resources
else
{
if (IntfHdl != INVALID_HANDLE_VALUE)
CloseHandle(IntfHdl);
MemFree(pHshHandle);
}
}
// out of critical section
LeaveCriticalSection(&g_hshHandles.csMutex);
exit:
DbgPrint((TRC_TRACK,"OpenIntfHandle]=%d", dwErr));
return dwErr;
}
DWORD
CloseIntfHandle(
LPWSTR wszGuid)
{
DWORD dwErr;
PHASH_NODE pNode;
DbgPrint((TRC_TRACK,"[CloseIntfHandle(%S)", wszGuid));
// lock the hash
EnterCriticalSection(&g_hshHandles.csMutex);
// query the hash for the guid.
dwErr = HshQueryObjectRef(
g_hshHandles.pRoot,
wszGuid,
&pNode);
// the object should be found.. but who knows
if (dwErr == ERROR_SUCCESS)
{
PHSH_HANDLE pHshHandle;
// the hash refuses to hash in NULL pObjects, so pHshHandle is guaranteed to be not NULL
pHshHandle = (PHSH_HANDLE)pNode->pObject;
// HshHandles are hashed in with a refCount of 1, and whenever we remove a handle
// if the ref count reaches 0 we delete it entirely.
// Having here a <=0 ref count is completely wrong.
DbgAssert((pHshHandle->nRefCount > 0, "Corrupted nRefCount %d", pHshHandle->nRefCount));
pHshHandle->nRefCount--;
// if the ref count reached 0, remove the HSH_HANDLE from the hash..
if (pHshHandle->nRefCount == 0)
{
dwErr = HshRemoveObjectRef(
g_hshHandles.pRoot,
pNode,
&pHshHandle,
&g_hshHandles.pRoot);
if (dwErr == ERROR_SUCCESS)
{
// .. and clear all associated resources
DbgPrint((TRC_GENERIC,"CloseIntfHandle -> 0x%x (closed)", pHshHandle->hdlInterf));
CloseHandle(pHshHandle->hdlInterf);
MemFree(pHshHandle);
}
}
else
{
DbgPrint((TRC_GENERIC,"CloseIntfHandle -> 0x%x (deref)", pHshHandle->hdlInterf));
}
}
LeaveCriticalSection(&g_hshHandles.csMutex);
DbgPrint((TRC_TRACK,"CloseIntfHandle]=%d", dwErr));
return dwErr;
}