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.
529 lines
12 KiB
529 lines
12 KiB
/*++
|
|
|
|
Copyright (C) 2001 Microsoft Corporation
|
|
All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
NCmgr.cxx
|
|
|
|
Abstract:
|
|
|
|
Implenetation of functions that operate on the name cache.
|
|
The initialization and delete functions are declared in NCmgr.hxx.
|
|
The rest of the functions are in winsplp.h.
|
|
|
|
Author:
|
|
|
|
Felix Maxa (AMaxa) 16 May 2001
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include <winsock2.h>
|
|
#include <iphlpapi.h>
|
|
#include "ncmgr.hxx"
|
|
#include "NCshared.hxx"
|
|
#include "ncnamecache.hxx"
|
|
#include "ncsockets.hxx"
|
|
|
|
TNameResolutionCache *g_pNameCache = NULL;
|
|
|
|
WCHAR g_szHttpPrefix0[] = L"\\\\http://";
|
|
WCHAR g_szHttpPrefix1[] = L"\\\\https://";
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
IsHttpPrinter
|
|
|
|
Description:
|
|
|
|
Checks whether a string can be the name of an HTTP printer.
|
|
|
|
Arguments:
|
|
|
|
pszPrinter - string. Can be NULL.
|
|
|
|
Return Value:
|
|
|
|
TRUE - pszPrinter has the prefix characteristic to HTTP printers
|
|
FALSE - pszPrinter does not have the prefix characteristic to HTTP printers
|
|
|
|
--*/
|
|
BOOL
|
|
IsHttpPrinter(
|
|
IN LPCWSTR pszPrinter
|
|
)
|
|
{
|
|
BOOL bIsHttp = FALSE;
|
|
|
|
if (pszPrinter && *pszPrinter)
|
|
{
|
|
bIsHttp = !_wcsnicmp(pszPrinter, g_szHttpPrefix0, COUNTOF(g_szHttpPrefix0) - 1) ||
|
|
!_wcsnicmp(pszPrinter, g_szHttpPrefix1, COUNTOF(g_szHttpPrefix1) - 1);
|
|
}
|
|
|
|
return bIsHttp;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
CacheInitNameCache
|
|
|
|
Description:
|
|
|
|
Initialize the name cache object and the object that listens for
|
|
IP changes for the local machine. This function must be called
|
|
before any other thread has a chance of calling the rest of the
|
|
cache functions. This is because we do not protect access on
|
|
the pointer to the cache object.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
S_OK - the cache was initialized successfully
|
|
other HRESULT - an error occurred, the cache cannot be used.
|
|
|
|
--*/
|
|
HRESULT
|
|
CacheInitNameCache(
|
|
VOID
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
g_pNameCache = new TNameResolutionCache;
|
|
|
|
hr = g_pNameCache ? S_OK : E_OUTOFMEMORY;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
CacheDeleteNameCache
|
|
|
|
Description:
|
|
|
|
Clean up the name cache object and the object that listens for
|
|
IP changes for the local machine.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
VOID
|
|
CacheDeleteNameCache(
|
|
VOID
|
|
)
|
|
{
|
|
delete g_pNameCache;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
CacheAddName
|
|
|
|
Description:
|
|
|
|
Adds a name to the local cache. The name will be added only if
|
|
it refers to the local machine or cluster resources running on
|
|
the local machine.
|
|
|
|
Arguments:
|
|
|
|
pszName - server name. Must be "\\" prefixed !!!
|
|
|
|
Return Value:
|
|
|
|
S_OK - name was added to the cache.
|
|
S_FALSE - name does not refer to the local machine
|
|
other HRESULT - an error occurred while executing the function
|
|
|
|
--*/
|
|
HRESULT
|
|
CacheAddName(
|
|
IN LPCWSTR pszName
|
|
)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pszName &&
|
|
*pszName &&
|
|
pszName[0] == L'\\' &&
|
|
pszName[1] == L'\\' &&
|
|
!IsHttpPrinter(pszName))
|
|
{
|
|
WCHAR *pcMark = wcschr(pszName + 2, L'\\');
|
|
|
|
if (pcMark)
|
|
{
|
|
*pcMark = 0;
|
|
}
|
|
|
|
hr = g_pNameCache->AddName(pszName + 2);
|
|
|
|
if (pcMark)
|
|
{
|
|
*pcMark = L'\\';
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
CacheCreateAndAddNode
|
|
|
|
Description:
|
|
|
|
Creates a node supporting the "pszName". The IP addresses
|
|
for the node are determined by calling getaddrinfo(pszName).
|
|
|
|
Arguments:
|
|
|
|
pszName - server name. Cannnot be "\\" prefixed.
|
|
bClusterNode - TRUE if the node is created by a cluster pIniSpooler
|
|
|
|
Return Value:
|
|
|
|
S_OK - node was added to the cache. (or existed there already)
|
|
other HRESULT - an error occurred while executing the function
|
|
|
|
--*/
|
|
HRESULT
|
|
CacheCreateAndAddNode(
|
|
IN LPCWSTR pszName,
|
|
IN BOOL bClusterNode
|
|
)
|
|
{
|
|
HRESULT hr = g_pNameCache->CreateAndAddNode(pszName, bClusterNode);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
CacheCreateAndAddNodeWithIPAddresses
|
|
|
|
Description:
|
|
|
|
Creates a node supporting the "pszName". The IP addresses
|
|
are passed in a argument by the caller. Thus a certain
|
|
node can support IP addresses that don't event resolve to
|
|
the pszName itself.
|
|
|
|
Arguments:
|
|
|
|
pszName - server name. Cannnot be "\\" prefixed.
|
|
bClusterNode - TRUE if the node is created by a cluster pIniSpooler
|
|
ppszIPAddresses - array of strings represeting IP addresses
|
|
cIPAddresses - number of strings in the array
|
|
|
|
Return Value:
|
|
|
|
S_OK - node was added to the cache. (or existed there already)
|
|
other HRESULT - an error occurred while executing the function
|
|
|
|
--*/
|
|
HRESULT
|
|
CacheCreateAndAddNodeWithIPAddresses(
|
|
IN LPCWSTR pszName,
|
|
IN BOOL bClusterNode,
|
|
IN LPCWSTR *ppszIPAddresses,
|
|
IN DWORD cIPAddresses
|
|
)
|
|
{
|
|
HRESULT hr = g_pNameCache->CreateAndAddNodeWithIPAddresses(pszName,
|
|
bClusterNode,
|
|
ppszIPAddresses,
|
|
cIPAddresses);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
CacheDeleteNode
|
|
|
|
Description:
|
|
|
|
Deletes a node from the cache.
|
|
|
|
Arguments:
|
|
|
|
pszName - server name. Cannnot be "\\" prefixed.
|
|
|
|
Return Value:
|
|
|
|
S_OK - node was deleted from the cache
|
|
S_FALSE - node was not found in cache
|
|
other HRESULT - an error occurred while executing the function
|
|
|
|
--*/
|
|
HRESULT
|
|
CacheDeleteNode(
|
|
IN LPCWSTR pszNode
|
|
)
|
|
{
|
|
return g_pNameCache->DeleteNode(pszNode);
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
CacheIsNameInNodeList
|
|
|
|
Description:
|
|
|
|
Checks if the node pszNode supports the pszName name in its list.
|
|
|
|
Arguments:
|
|
|
|
psznode - node in the cache list
|
|
pszName - server name. Cannnot be "\\" prefixed.
|
|
|
|
Return Value:
|
|
|
|
S_OK - pszName is in the cache of pszNode
|
|
S_FALSE - pszName is NOT in the cache of pszNode
|
|
other HRESULT - an error occurred while executing the function
|
|
|
|
--*/
|
|
HRESULT
|
|
CacheIsNameInNodeList(
|
|
IN LPCWSTR pszNode,
|
|
IN LPCWSTR pszName
|
|
)
|
|
{
|
|
return g_pNameCache->IsNameInNodeCache(pszNode, pszName);
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
CacheRefresh
|
|
|
|
Description:
|
|
|
|
Refershes the list of IP addresses supported by the local machine node.
|
|
Should be called when a change of IP PNP event occurrs. The name of
|
|
the local node is the short name of the local machine.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
S_OK - local machine node was refreshed
|
|
other HRESULT - an error occurred while executing the function
|
|
|
|
--*/
|
|
HRESULT
|
|
CacheRefresh(
|
|
VOID
|
|
)
|
|
{
|
|
HRESULT hr = g_pNameCache->RefreshNode(szMachineName + 2);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
PnpIPAddressChangeListener
|
|
|
|
Description:
|
|
|
|
This function loops and waits for events that indicate changes in IP address.
|
|
Chnages in ip address occurr when you can "ipconfig /release", when the IP
|
|
address resource of a cluster comes online or goes offline, etc.
|
|
The function takes ownership of the pointer (the meory pointer to by the pointer)
|
|
Also, the function takes ownership of the hWaitEvent.
|
|
The function does not take ownership of the hTerminateEvent. That event must be
|
|
aglobal mutex for the spooler process and can be used to terminate the looping thread.
|
|
|
|
Arguments:
|
|
|
|
pVoid - pointer to IPADDRESSCHANGEARGS structure
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
VOID
|
|
PnpIPAddressChangeListener(
|
|
VOID *pVoid
|
|
)
|
|
{
|
|
SIPADDRESSCHANGEARGS *pArgs = reinterpret_cast<SIPADDRESSCHANGEARGS *>(pVoid);
|
|
PFNVOID pfnCallBack = pArgs->pfnCallBack;
|
|
HANDLE hTerminateEvent = pArgs->hTerminateEvent;
|
|
OVERLAPPED InterfaceChange = {0};
|
|
BOOL bLoop = TRUE;
|
|
|
|
InterfaceChange.hEvent = pArgs->hWaitEvent;
|
|
|
|
while (bLoop)
|
|
{
|
|
HANDLE hNotify = NULL;
|
|
DWORD Error = NotifyAddrChange(&hNotify, &InterfaceChange);
|
|
|
|
bLoop = FALSE;
|
|
|
|
if (Error == ERROR_IO_PENDING)
|
|
{
|
|
HANDLE hHandles[2] = {InterfaceChange.hEvent, hTerminateEvent};
|
|
DWORD cHandles = hTerminateEvent ? 2 : 1;
|
|
DWORD WaitStatus;
|
|
|
|
WaitStatus = WaitForMultipleObjects(cHandles, hHandles, FALSE, INFINITE);
|
|
|
|
switch(WaitStatus)
|
|
{
|
|
case WAIT_OBJECT_0:
|
|
{
|
|
bLoop = TRUE;
|
|
|
|
(*pfnCallBack)();
|
|
|
|
break;
|
|
}
|
|
|
|
case WAIT_OBJECT_0 + 1:
|
|
{
|
|
//
|
|
// We're done waiting, bLoop is FALSE so the while will terminate
|
|
//
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DBGMSG(DBG_ERROR, ("PnpIPAddressChangeListener WaitForMultipleObjects failed\n"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGMSG(DBG_WARN, ("PnpIPAddressChangeListener NotifyAddrChange failed. Win32 error %u\n", Error));
|
|
}
|
|
}
|
|
|
|
CloseHandle(InterfaceChange.hEvent);
|
|
|
|
delete pArgs;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
InitializePnPIPAddressChangeListener
|
|
|
|
Description:
|
|
|
|
Launches a separate thread which waits for IP change events.
|
|
|
|
Arguments:
|
|
|
|
pfnCallBack - function to call when a change in IP address occurs
|
|
|
|
Return Value:
|
|
|
|
S_OK - the IP change listener was initialized successfully
|
|
other HRESULT - an error occurred while executing the function
|
|
|
|
--*/
|
|
HRESULT
|
|
InitializePnPIPAddressChangeListener(
|
|
IN PFNVOID pfnCallBack
|
|
)
|
|
{
|
|
TStatusH hRetval;
|
|
SIPADDRESSCHANGEARGS *pArgs = new SIPADDRESSCHANGEARGS;
|
|
|
|
hRetval DBGCHK = pfnCallBack ? (pArgs ? S_OK : E_OUTOFMEMORY) : E_INVALIDARG;
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
HANDLE hThread;
|
|
DWORD ThreadId;
|
|
|
|
pArgs->pfnCallBack = pfnCallBack;
|
|
|
|
//
|
|
// When the spooler can finally shut down properly, then we can specify
|
|
// here an event to terminate the PnpIPAddressChangeListener
|
|
//
|
|
pArgs->hTerminateEvent = NULL;
|
|
|
|
//
|
|
// Note that PnpIPAddressChangeListener takes ownership of this event
|
|
// so PnpIPAddressChangeListener must call CloseHandle on the event
|
|
//
|
|
pArgs->hWaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
hRetval DBGCHK = pArgs->hWaitEvent ? S_OK : GetLastErrorAsHResult();
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
if (hThread = CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)PnpIPAddressChangeListener,
|
|
pArgs,
|
|
0,
|
|
&ThreadId))
|
|
{
|
|
CloseHandle(hThread);
|
|
|
|
//
|
|
// Note that PnpIPAddressChangeListener takes ownership of pArgs and must free it
|
|
//
|
|
pArgs = NULL;
|
|
}
|
|
else
|
|
{
|
|
hRetval DBGCHK = GetLastErrorAsHResult();
|
|
}
|
|
}
|
|
}
|
|
|
|
delete pArgs;
|
|
|
|
return hRetval;
|
|
}
|
|
|