686 lines
17 KiB
C
686 lines
17 KiB
C
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
net\routing\ipx\sap\sapmain.c
|
|
|
|
Abstract:
|
|
|
|
SAP DLL main module and thread container.
|
|
|
|
Author:
|
|
|
|
Vadim Eydelman 05-15-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "sapp.h"
|
|
|
|
// Time limit for shutdown broadcast
|
|
ULONG ShutdownTimeout=SAP_SHUTDOWN_TIMEOUT_DEF;
|
|
// Indeces of synchronization objects used to control asynchronous
|
|
// subsystems of SAP agent
|
|
|
|
// Main thread signalling event
|
|
#define STOP_EVENT_IDX 0
|
|
|
|
#define RECV_COMPLETED_IDX (STOP_EVENT_IDX+1)
|
|
// Timer queue requires attention
|
|
#define TIMER_WAKEUP_IDX (RECV_COMPLETED_IDX+1)
|
|
|
|
// Server table aging queue requires processing
|
|
#define SERVER_TABLE_TIMER_IDX (TIMER_WAKEUP_IDX+1)
|
|
// Server table sorted list requires update
|
|
#define SERVER_TABLE_UPDATE_IDX (SERVER_TABLE_TIMER_IDX+1)
|
|
// Adapter change signalled by network driver (for standalone SAP only)
|
|
#define ADAPTER_CHG_IDX (SERVER_TABLE_UPDATE_IDX+1)
|
|
|
|
// Number of syncronization objects
|
|
#define ROUTING_NUM_OF_OBJECTS (SERVER_TABLE_UPDATE_IDX+1)
|
|
#define STANDALONE_NUM_OF_OBJECTS (ADAPTER_CHG_IDX+1)
|
|
|
|
#define MAX_OBJECTS STANDALONE_NUM_OF_OBJECTS
|
|
|
|
|
|
|
|
/* Global Data */
|
|
// DLL module instance handle
|
|
HANDLE hDLLInstance;
|
|
|
|
// Handle of main thread
|
|
HANDLE MainThreadHdl;
|
|
|
|
// Operational state of the agent
|
|
ULONG OperationalState=OPER_STATE_DOWN;
|
|
// Lock that protects changes in the state and state transitions
|
|
CRITICAL_SECTION OperationalStateLock;
|
|
// TRUE between start and stop service calls
|
|
volatile BOOLEAN ServiceIfActive=FALSE;
|
|
// TRUE between start and stop protocol calls
|
|
volatile BOOLEAN RouterIfActive=FALSE;
|
|
|
|
|
|
// TRUE if sap is part of the router, FALSE for standalone SAP agent
|
|
// It is computed based on two values above with RouterIfActive having
|
|
// precedence. In stays where it was during transition periods and changes
|
|
// only when transition is completed (it can only be changed by the main
|
|
// thread).
|
|
volatile BOOLEAN Routing=FALSE;
|
|
|
|
|
|
/* Local static data */
|
|
|
|
// Async subsystem synchronization objects
|
|
HANDLE WaitObjects[MAX_OBJECTS] = {NULL};
|
|
|
|
|
|
// Time we will die at when told to shutdown
|
|
ULONG StopTime;
|
|
|
|
|
|
TCHAR ModuleName[MAX_PATH+1];
|
|
|
|
// Local prototypes
|
|
BOOL WINAPI DllMain(
|
|
HINSTANCE hinstDLL,
|
|
DWORD fdwReason,
|
|
LPVOID lpvReserved
|
|
);
|
|
|
|
|
|
DWORD WINAPI
|
|
MainThread (
|
|
LPVOID param
|
|
);
|
|
|
|
VOID
|
|
ReadRegistry (
|
|
VOID
|
|
);
|
|
|
|
/*++
|
|
*******************************************************************
|
|
D l l M a i n
|
|
Routine Description:
|
|
Dll entry point to be called from CRTstartup dll entry point (it
|
|
will be actually an entry point for this dll)
|
|
Arguments:
|
|
hinstDLL - handle of DLL module
|
|
fdwReason - reason for calling function
|
|
lpvReserved - reserved
|
|
Return Value:
|
|
TRUE - process initialization was performed OK
|
|
FALSE - intialization failed
|
|
|
|
*******************************************************************
|
|
--*/
|
|
BOOL WINAPI DllMain(
|
|
HINSTANCE hinstDLL,
|
|
DWORD fdwReason,
|
|
LPVOID lpvReserved
|
|
) {
|
|
STARTUPINFO info;
|
|
|
|
switch (fdwReason) {
|
|
case DLL_PROCESS_ATTACH: // We are being attached to a new process
|
|
hDLLInstance = hinstDLL;
|
|
GetModuleFileName (hinstDLL, ModuleName,
|
|
sizeof (ModuleName)/sizeof (ModuleName[0]));
|
|
InitializeCriticalSection (&OperationalStateLock);
|
|
return TRUE;
|
|
|
|
case DLL_PROCESS_DETACH: // The process is exiting
|
|
ASSERT (OperationalState==OPER_STATE_DOWN);
|
|
DeleteCriticalSection (&OperationalStateLock);
|
|
default: // Not interested in all other cases
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
C r e a t e A l l C o m p o n e n t s
|
|
Routine Description:
|
|
Calls all sap componenets with initialization call and compiles an
|
|
array of synchronization objects from objects returned from each
|
|
individual component
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
NO_ERROR - component initialization was performed OK
|
|
other - operation failed (windows error code)
|
|
|
|
*******************************************************************
|
|
--*/
|
|
DWORD
|
|
CreateAllComponents (
|
|
HANDLE RMNotificationEvent
|
|
) {
|
|
DWORD status;
|
|
|
|
DbgInitialize (hDLLInstance);
|
|
ReadRegistry ();
|
|
status = CreateServerTable (
|
|
&WaitObjects[SERVER_TABLE_UPDATE_IDX],
|
|
&WaitObjects[SERVER_TABLE_TIMER_IDX]);
|
|
if (status==NO_ERROR) {
|
|
status = IpxSapCreateTimerQueue (&WaitObjects[TIMER_WAKEUP_IDX]);
|
|
if (status==NO_ERROR) {
|
|
status = CreateInterfaceTable ();
|
|
if (status==NO_ERROR) {
|
|
status = CreateIOQueue (&WaitObjects[RECV_COMPLETED_IDX]);
|
|
if (status==NO_ERROR) {
|
|
status = InitializeLPCStuff ();
|
|
if (status==NO_ERROR) {
|
|
status = CreateFilterTable ();
|
|
if (status==NO_ERROR) {
|
|
status = InitializeWorkers (WaitObjects[RECV_COMPLETED_IDX]);
|
|
if (status==NO_ERROR) {
|
|
WaitObjects[STOP_EVENT_IDX] =
|
|
CreateEvent (NULL,
|
|
FALSE, //Autoreset
|
|
FALSE, // non-signalled
|
|
NULL);
|
|
if (WaitObjects[STOP_EVENT_IDX]!=NULL) {
|
|
|
|
if (RMNotificationEvent == NULL)
|
|
status = CreateAdapterPort (&WaitObjects[ADAPTER_CHG_IDX]);
|
|
else
|
|
status = CreateResultQueue (RMNotificationEvent);
|
|
if (status==NO_ERROR)
|
|
return NO_ERROR;
|
|
}
|
|
else {
|
|
status = GetLastError ();
|
|
Trace (DEBUG_FAILURES, "File: %s, line %ld."
|
|
" Could not create stop event (gle:%ld).",
|
|
__FILE__, __LINE__, status);
|
|
}
|
|
DeleteWorkers ();
|
|
}
|
|
DeleteFilterTable ();
|
|
}
|
|
DeleteLPCStuff();
|
|
}
|
|
DeleteIOQueue ();
|
|
}
|
|
DeleteInterfaceTable ();
|
|
}
|
|
IpxSapDeleteTimerQueue ();
|
|
}
|
|
DeleteServerTable ();
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
D e l e t e A l l C o m p o n e n t s
|
|
Routine Description:
|
|
Releases all resources allocated by SAP agent
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
NO_ERROR - SAP agent was unloaded OK
|
|
other - operation failed (windows error code)
|
|
|
|
*******************************************************************
|
|
--*/
|
|
DWORD
|
|
DeleteAllComponents (
|
|
void
|
|
) {
|
|
UINT i;
|
|
DWORD status;
|
|
|
|
EnterCriticalSection (&OperationalStateLock);
|
|
OperationalState = OPER_STATE_DOWN;
|
|
LeaveCriticalSection (&OperationalStateLock);
|
|
// Stop now
|
|
StopTime = GetTickCount ();
|
|
|
|
CloseHandle (WaitObjects[STOP_EVENT_IDX]);
|
|
DeleteFilterTable ();
|
|
DeleteLPCStuff ();
|
|
DeleteIOQueue ();
|
|
DeleteInterfaceTable ();
|
|
IpxSapDeleteTimerQueue ();
|
|
DeleteServerTable ();
|
|
DeleteWorkers ();
|
|
DbgStop ();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
S t a r t S A P
|
|
Routine Description:
|
|
Starts SAP threads
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
NO_ERROR - threads started OK
|
|
other (windows error code) - start failed
|
|
*******************************************************************
|
|
--*/
|
|
DWORD
|
|
StartSAP (
|
|
VOID
|
|
) {
|
|
DWORD status;
|
|
|
|
status = StartLPC ();
|
|
if (status==NO_ERROR) {
|
|
status = StartIO ();
|
|
if (status==NO_ERROR) {
|
|
DWORD threadID;
|
|
MainThreadHdl = CreateThread (NULL,
|
|
0,
|
|
&MainThread,
|
|
NULL,
|
|
0,
|
|
&threadID);
|
|
if (MainThreadHdl!=NULL) {
|
|
OperationalState = OPER_STATE_UP;
|
|
return NO_ERROR;
|
|
}
|
|
else {
|
|
status = GetLastError ();
|
|
Trace (DEBUG_FAILURES, "File: %s, line %ld."
|
|
" Failed to launch IO thread (gle:%ld).",
|
|
__FILE__, __LINE__, status);
|
|
}
|
|
StopIO ();
|
|
}
|
|
ShutdownLPC ();
|
|
}
|
|
|
|
OperationalState = OPER_STATE_DOWN;
|
|
return status;
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
S t o p S A P
|
|
Routine Description:
|
|
Signals SAP threads to stop
|
|
Arguments:
|
|
No used
|
|
Return Value:
|
|
None
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
StopSAP (
|
|
void
|
|
) {
|
|
BOOL res;
|
|
|
|
OperationalState = OPER_STATE_STOPPING;
|
|
StopTime = GetTickCount ()+ShutdownTimeout*1000;
|
|
res = SetEvent (WaitObjects[STOP_EVENT_IDX]);
|
|
ASSERTERRMSG ("Could not set stop event in StopSAP ", res);
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
R e s u l t R e t r e i v e d C B
|
|
Routine Description:
|
|
Async result manager call back routine that signals IO thread when
|
|
stop message is retreived by router manager
|
|
Arguments:
|
|
No used
|
|
Return Value:
|
|
None
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
ResultRetreivedCB (
|
|
PAR_PARAM_BLOCK rslt
|
|
) {
|
|
BOOL res;
|
|
UNREFERENCED_PARAMETER(rslt);
|
|
res = SetEvent (WaitObjects[STOP_EVENT_IDX]);
|
|
ASSERTERRMSG ("Could not set stop event in result retreived CB", res);
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
M a i n T h r e a d
|
|
Routine Description:
|
|
Thread in which context we'll perform async IO and maintain timer
|
|
queues.
|
|
It is also used to launch and control other threads of SAP agent
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
None
|
|
*******************************************************************
|
|
--*/
|
|
DWORD WINAPI
|
|
MainThread (
|
|
LPVOID param
|
|
) {
|
|
DWORD status;
|
|
UINT i;
|
|
DWORD nObjects;
|
|
HANDLE enumHdl;
|
|
HINSTANCE hModule;
|
|
|
|
hModule = LoadLibrary (ModuleName);
|
|
|
|
Restart:
|
|
Routing = RouterIfActive;
|
|
if (Routing) {
|
|
nObjects = ROUTING_NUM_OF_OBJECTS;
|
|
}
|
|
else {
|
|
nObjects = STANDALONE_NUM_OF_OBJECTS;
|
|
}
|
|
|
|
while ((status = WaitForMultipleObjectsEx (
|
|
nObjects,
|
|
WaitObjects,
|
|
FALSE, // Wait any
|
|
INFINITE,
|
|
TRUE))!=WAIT_OBJECT_0+STOP_EVENT_IDX) {
|
|
|
|
switch (status) {
|
|
case WAIT_OBJECT_0+RECV_COMPLETED_IDX:
|
|
InitReqItem ();
|
|
break;
|
|
case WAIT_OBJECT_0+TIMER_WAKEUP_IDX:
|
|
ProcessTimerQueue ();
|
|
break;
|
|
case WAIT_OBJECT_0+SERVER_TABLE_TIMER_IDX:
|
|
ProcessExpirationQueue ();
|
|
break;
|
|
case WAIT_OBJECT_0+SERVER_TABLE_UPDATE_IDX:
|
|
UpdateSortedList ();
|
|
break;
|
|
case WAIT_OBJECT_0+ADAPTER_CHG_IDX:
|
|
if (!RouterIfActive)
|
|
ProcessAdapterEvents ();
|
|
break;
|
|
case WAIT_IO_COMPLETION:
|
|
break;
|
|
default:
|
|
ASSERTMSG ("Unexpected return code from WaitFromObjects"
|
|
" in IO thread ", FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
enumHdl = CreateListEnumerator (SDB_HASH_TABLE_LINK,
|
|
0xFFFF,
|
|
NULL,
|
|
INVALID_INTERFACE_INDEX,
|
|
0xFFFFFFFF,
|
|
SDB_DISABLED_NODE_FLAG);
|
|
|
|
if (ServiceIfActive || RouterIfActive) {
|
|
if (enumHdl!=NULL)
|
|
EnumerateServers (enumHdl, DeleteNonLocalServersCB, enumHdl);
|
|
}
|
|
else {
|
|
ShutdownLPC ();
|
|
if (enumHdl!=NULL)
|
|
EnumerateServers (enumHdl, DeleteAllServersCB, enumHdl);
|
|
|
|
}
|
|
if (enumHdl)
|
|
{
|
|
DeleteListEnumerator (enumHdl);
|
|
}
|
|
|
|
if (!RouterIfActive) {
|
|
ShutdownInterfaces (WaitObjects[STOP_EVENT_IDX]);
|
|
|
|
ExpireTimerQueue ();
|
|
while ((status = WaitForMultipleObjectsEx (
|
|
ROUTING_NUM_OF_OBJECTS,
|
|
WaitObjects,
|
|
FALSE, // Wait any
|
|
INFINITE,
|
|
TRUE))!=WAIT_OBJECT_0+STOP_EVENT_IDX) {
|
|
switch (status) {
|
|
case WAIT_OBJECT_0+RECV_COMPLETED_IDX:
|
|
// No more recv requests
|
|
break;
|
|
case WAIT_OBJECT_0+TIMER_WAKEUP_IDX:
|
|
ProcessTimerQueue ();
|
|
break;
|
|
case WAIT_OBJECT_0+SERVER_TABLE_TIMER_IDX:
|
|
ProcessExpirationQueue ();
|
|
break;
|
|
case WAIT_OBJECT_0+SERVER_TABLE_UPDATE_IDX:
|
|
UpdateSortedList ();
|
|
break;
|
|
case WAIT_IO_COMPLETION:
|
|
break;
|
|
default:
|
|
ASSERTMSG ("Unexpected return code from WaitForObjects"
|
|
" in IO thread", FALSE);
|
|
}
|
|
}
|
|
|
|
if (!ServiceIfActive) {
|
|
StopIO ();
|
|
StopInterfaces ();
|
|
ExpireTimerQueue ();
|
|
ShutdownWorkers (WaitObjects[STOP_EVENT_IDX]);
|
|
while ((status=WaitForSingleObjectEx (
|
|
WaitObjects[STOP_EVENT_IDX],
|
|
INFINITE,
|
|
TRUE))!=WAIT_OBJECT_0) {
|
|
switch (status) {
|
|
case WAIT_IO_COMPLETION:
|
|
break;
|
|
default:
|
|
ASSERTMSG (
|
|
"Unexpected status when waiting for worker shutdown ",
|
|
FALSE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (Routing) {
|
|
// Signal completion of stop operation to
|
|
// router manager
|
|
static AR_PARAM_BLOCK ar;
|
|
ar.event = ROUTER_STOPPED;
|
|
ar.freeRsltCB = ResultRetreivedCB;
|
|
EnqueueResult (&ar);
|
|
while ((status = WaitForSingleObjectEx (
|
|
WaitObjects[STOP_EVENT_IDX],
|
|
INFINITE,
|
|
TRUE))!=WAIT_OBJECT_0) {
|
|
switch (status) {
|
|
case WAIT_IO_COMPLETION:
|
|
break;
|
|
default:
|
|
ASSERTMSG (
|
|
"Unexpected status when waiting for router callback ",
|
|
FALSE);
|
|
break;
|
|
}
|
|
}
|
|
DeleteResultQueue ();
|
|
if (ServiceIfActive) {
|
|
status = CreateAdapterPort (&WaitObjects[ADAPTER_CHG_IDX]);
|
|
if (status==NO_ERROR) {
|
|
EnterCriticalSection (&OperationalStateLock);
|
|
OperationalState = OPER_STATE_UP;
|
|
LeaveCriticalSection (&OperationalStateLock);
|
|
goto Restart;
|
|
}
|
|
else
|
|
ServiceIfActive = FALSE;
|
|
}
|
|
|
|
EnterCriticalSection (&OperationalStateLock);
|
|
CloseHandle (MainThreadHdl);
|
|
MainThreadHdl = NULL;
|
|
LeaveCriticalSection (&OperationalStateLock);
|
|
}
|
|
else {
|
|
DeleteAdapterPort ();
|
|
WaitObjects [ADAPTER_CHG_IDX] = NULL;
|
|
if (RouterIfActive) {
|
|
EnterCriticalSection (&OperationalStateLock);
|
|
OperationalState = OPER_STATE_UP;
|
|
LeaveCriticalSection (&OperationalStateLock);
|
|
goto Restart;
|
|
}
|
|
}
|
|
|
|
// Make sure all threads get a chance to complete
|
|
Sleep (1000);
|
|
DeleteAllComponents ();
|
|
FreeLibraryAndExitThread (hModule, 0);
|
|
return 0;
|
|
}
|
|
|
|
#define MYTEXTW1(str) L##str
|
|
#define MYTEXTW2(str) MYTEXTW1(str)
|
|
|
|
#define REGISTRY_PARAM_ENTRY(name,val) { \
|
|
NULL, \
|
|
RTL_QUERY_REGISTRY_DIRECT, \
|
|
MYTEXTW2(name##_STR), \
|
|
&val, \
|
|
REG_DWORD, \
|
|
&val, \
|
|
sizeof (DWORD) \
|
|
}
|
|
|
|
#define REGISTRY_CHECK(name,val) { \
|
|
if (val<name##_MIN) { \
|
|
Trace (DEBUG_FAILURES, name##_STR " is to small %ld!", val); \
|
|
val = name##_MIN; \
|
|
} \
|
|
else if (val>name##_MAX) { \
|
|
Trace (DEBUG_FAILURES, name##_STR " is to big %ld!", val); \
|
|
val = name##_MAX; \
|
|
} \
|
|
if (val!=name##_DEF) \
|
|
Trace (DEBUG_FAILURES, name##_STR" is set to %ld.", val); \
|
|
}
|
|
|
|
#define REGISTRY_CHECK_DEF(name,val) { \
|
|
if (val<name##_MIN) { \
|
|
Trace (DEBUG_FAILURES, name##_STR " is to small %ld!", val); \
|
|
val = name##_DEF; \
|
|
} \
|
|
else if (val>name##_MAX) { \
|
|
Trace (DEBUG_FAILURES, name##_STR " is to big %ld!", val); \
|
|
val = name##_DEF; \
|
|
} \
|
|
if (val!=name##_DEF) \
|
|
Trace (DEBUG_FAILURES, name##_STR " is set to %ld.", val); \
|
|
}
|
|
|
|
|
|
VOID
|
|
ReadRegistry (
|
|
VOID
|
|
) {
|
|
DWORD rc;
|
|
HKEY hKey;
|
|
static RTL_QUERY_REGISTRY_TABLE ParamTable[] = {
|
|
{ NULL,
|
|
RTL_QUERY_REGISTRY_SUBKEY,
|
|
L"Parameters" },
|
|
REGISTRY_PARAM_ENTRY (SAP_UPDATE_INTERVAL, UpdateInterval),
|
|
REGISTRY_PARAM_ENTRY (SAP_AGING_TIMEOUT, ServerAgingTimeout),
|
|
REGISTRY_PARAM_ENTRY (SAP_WAN_UPDATE_MODE, WanUpdateMode),
|
|
REGISTRY_PARAM_ENTRY (SAP_WAN_UPDATE_INTERVAL,WanUpdateInterval),
|
|
REGISTRY_PARAM_ENTRY (SAP_MAX_UNPROCESSED_REQUESTS,
|
|
MaxUnprocessedRequests),
|
|
REGISTRY_PARAM_ENTRY (SAP_RESPOND_FOR_INTERNAL,
|
|
RespondForInternalServers),
|
|
REGISTRY_PARAM_ENTRY (SAP_DELAY_RESPONSE_TO_GENERAL,
|
|
DelayResponseToGeneral),
|
|
REGISTRY_PARAM_ENTRY (SAP_DELAY_CHANGE_BROADCAST,
|
|
DelayChangeBroadcast),
|
|
REGISTRY_PARAM_ENTRY (SAP_SDB_MAX_HEAP_SIZE,SDBMaxHeapSize),
|
|
REGISTRY_PARAM_ENTRY (SAP_SDB_SORT_LATENCY, SDBSortLatency),
|
|
REGISTRY_PARAM_ENTRY (SAP_SDB_MAX_UNSORTED, SDBMaxUnsortedServers),
|
|
REGISTRY_PARAM_ENTRY (SAP_TRIGGERED_UPDATE_CHECK_INTERVAL,
|
|
TriggeredUpdateCheckInterval),
|
|
REGISTRY_PARAM_ENTRY (SAP_MAX_TRIGGERED_UPDATE_REQUESTS,
|
|
MaxTriggeredUpdateRequests),
|
|
REGISTRY_PARAM_ENTRY (SAP_SHUTDOWN_TIMEOUT, ShutdownTimeout),
|
|
REGISTRY_PARAM_ENTRY (SAP_REQUESTS_PER_INTF,NewRequestsPerInterface),
|
|
REGISTRY_PARAM_ENTRY (SAP_MIN_REQUESTS, MinPendingRequests),
|
|
{
|
|
NULL
|
|
}
|
|
};
|
|
|
|
rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
TEXT (SAP_ROUTER_REGISTRY_KEY_STR),
|
|
0,
|
|
KEY_READ,
|
|
&hKey
|
|
);
|
|
if ((rc!=NO_ERROR) && !Routing) {
|
|
rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
TEXT (SAP_SERVICE_REGISTRY_KEY_STR),
|
|
0,
|
|
KEY_READ,
|
|
&hKey
|
|
);
|
|
}
|
|
|
|
if (rc==NO_ERROR) {
|
|
NTSTATUS status;
|
|
status = RtlQueryRegistryValues(
|
|
RTL_REGISTRY_HANDLE,
|
|
(PWSTR)hKey,
|
|
ParamTable,
|
|
NULL,
|
|
NULL);
|
|
if (NT_SUCCESS (status)) {
|
|
REGISTRY_CHECK (SAP_UPDATE_INTERVAL, UpdateInterval);
|
|
REGISTRY_CHECK (SAP_AGING_TIMEOUT, ServerAgingTimeout);
|
|
REGISTRY_CHECK_DEF (SAP_WAN_UPDATE_MODE, (int)WanUpdateMode);
|
|
REGISTRY_CHECK (SAP_WAN_UPDATE_INTERVAL,WanUpdateInterval);
|
|
REGISTRY_CHECK (SAP_MAX_UNPROCESSED_REQUESTS,
|
|
MaxUnprocessedRequests);
|
|
REGISTRY_CHECK_DEF (SAP_RESPOND_FOR_INTERNAL,
|
|
(int) RespondForInternalServers);
|
|
REGISTRY_CHECK (SAP_DELAY_RESPONSE_TO_GENERAL,
|
|
(int) DelayResponseToGeneral);
|
|
REGISTRY_CHECK (SAP_DELAY_CHANGE_BROADCAST,
|
|
(int) DelayChangeBroadcast);
|
|
REGISTRY_CHECK (SAP_SDB_MAX_HEAP_SIZE, SDBMaxHeapSize);
|
|
REGISTRY_CHECK (SAP_SDB_SORT_LATENCY, SDBSortLatency);
|
|
REGISTRY_CHECK (SAP_SDB_MAX_UNSORTED, SDBMaxUnsortedServers);
|
|
REGISTRY_CHECK (SAP_TRIGGERED_UPDATE_CHECK_INTERVAL,
|
|
TriggeredUpdateCheckInterval);
|
|
REGISTRY_CHECK (SAP_MAX_TRIGGERED_UPDATE_REQUESTS,
|
|
MaxTriggeredUpdateRequests);
|
|
REGISTRY_CHECK (SAP_SHUTDOWN_TIMEOUT, ShutdownTimeout);
|
|
REGISTRY_CHECK (SAP_REQUESTS_PER_INTF, NewRequestsPerInterface);
|
|
REGISTRY_CHECK (SAP_MIN_REQUESTS, MinPendingRequests);
|
|
}
|
|
RegCloseKey (hKey);
|
|
}
|
|
}
|
|
|
|
|
|
|