mirror of https://github.com/lianthony/NT4.0
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.
697 lines
22 KiB
697 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1987-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
request.c
|
|
|
|
Abstract:
|
|
|
|
Request thread code.
|
|
|
|
Provides similar functionality to rplreq.c in LANMAN 2.1 code.
|
|
|
|
Author:
|
|
|
|
Vladimir Z. Vulovic 27 - July - 1993
|
|
|
|
Environment:
|
|
|
|
User mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
#include "local.h"
|
|
#include "worker.h"
|
|
#include "database.h"
|
|
#include "report.h"
|
|
#include "request.h"
|
|
|
|
typedef struct _RPL_SFR_PARAMS { // send file request thread parameters
|
|
POPEN_INFO pOpenInfo; // open info data of current DLL
|
|
PPRCB HeadRcbList; // list of RCBs used by worker threads
|
|
PCRITICAL_SECTION ProtectRcbList;
|
|
} SFR_PARAMS, *PRPL_SFR_PARAMS;
|
|
|
|
|
|
extern VOID RplInsertRcb(
|
|
IN OUT PPRCB HeadList,
|
|
IN OUT PRCB pRcb
|
|
);
|
|
|
|
|
|
|
|
VOID SfrThread( PRPL_SFR_PARAMS pSfrParams)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Procedure receives Send File Requests, searches the valid RCB
|
|
from list and starts the worker thread of RCB by clearing a
|
|
semaphore.
|
|
|
|
This thread tries to run at highest settable priority because
|
|
claims must always be ready to receive acknowledges (if ASCLAN
|
|
receive is not active, then SF Requests may be lost and there
|
|
is 4 seconds timeout in the workstation).
|
|
|
|
Arguments:
|
|
pSfrParams ptr to SFR_PARAMS
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DWORD status;
|
|
|
|
if ( !SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
|
|
status = GetLastError();
|
|
RplDump( ++RG_Assert, ("status=%d", status));
|
|
RplEnd( NELOG_RplSystem);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The call to SendFileRequest never returns. Not only is this thread
|
|
// capt captive, but the callee needlessly creates one more thread.
|
|
// Better interface would allow to post a receive for our two SAP-s,
|
|
// then from a single place read both FIND frame data (FIND_SAP)
|
|
// and SFR data (SFR_SAP). This could be all done from a single
|
|
// thread, resembling current RequestThread().
|
|
//
|
|
|
|
if ( RplDlcSfr( // was RPL1_Get_SF_Request()
|
|
pSfrParams->pOpenInfo,
|
|
pSfrParams->HeadRcbList,
|
|
pSfrParams->ProtectRcbList
|
|
)) {
|
|
return; // success
|
|
}
|
|
if ( RG_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) {
|
|
return; // somebody else initiated service shutdown
|
|
}
|
|
RplDump( ++RG_Assert, ("CurrentState=0x%x", RG_ServiceStatus.dwCurrentState));
|
|
RplEnd( NELOG_RplSystem);
|
|
}
|
|
|
|
|
|
|
|
PRCB RplPopRcb( PPRCB HeadList)
|
|
{
|
|
PRCB pRcb = *HeadList;
|
|
DebugCheckList( HeadList, NULL, 0);
|
|
if ( pRcb != NULL) {
|
|
*HeadList = pRcb->next_rcb;
|
|
}
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_WORKER,(
|
|
"PopRcb: pRcb=0x%x, list=0x%x", pRcb, HeadList));
|
|
DebugCheckList( HeadList, pRcb, RPL_MUST_NOT_FIND);
|
|
return( pRcb);
|
|
}
|
|
|
|
|
|
PRCB GetRcbFromFreeList(
|
|
IN OUT PPRCB pFreeList,
|
|
IN DWORD lan_rcb_size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds the first RCB from the list of free RCBs. If list is empty,
|
|
creates a new RCB. Before returning RCB it (re)initializes all the
|
|
fields in the RCB.
|
|
|
|
Arguments:
|
|
|
|
pFreeList, - pointer to list of free RCB-s
|
|
lan_rcb_size - size of lan specific rcb
|
|
|
|
Return Value:
|
|
|
|
Pointer to RCB, or NULL if we cannot get an RCB.
|
|
|
|
--*/
|
|
{
|
|
PRCB pRcb;
|
|
|
|
EnterCriticalSection( &RG_ProtectRcbList);
|
|
|
|
pRcb = RplPopRcb( pFreeList);
|
|
if ( pRcb != NULL) {
|
|
goto exit_GetRcbFromFreeList; // success
|
|
}
|
|
|
|
pRcb = RplMemAlloc( RG_MemoryHandle, sizeof(RCB));
|
|
if ( pRcb == NULL) {
|
|
goto exit_GetRcbFromFreeList;
|
|
}
|
|
|
|
pRcb->lan_rcb_ptr = RplMemAlloc( RG_MemoryHandle, lan_rcb_size);
|
|
if ( pRcb->lan_rcb_ptr == NULL) {
|
|
RplMemFree( RG_MemoryHandle, pRcb);
|
|
pRcb = NULL;
|
|
goto exit_GetRcbFromFreeList; // failure
|
|
}
|
|
|
|
// SF_wakeup was using automatic reset and RPL worker used not to
|
|
// reset SF_wakup before each FDR send. This did not work properly
|
|
// due to multiple SFR-s for a single frame. Multiple SFR-s would
|
|
// cause SF_wakeup to be in a signalled state immediately after
|
|
// worker sent an FDR, thus worker would wakeup immediately and find
|
|
// a wrong value for sfr_seq_number.
|
|
// To fix this RPL worker must make sure SF_wakeup is blocked
|
|
// before each FDR send. Since worker must now reset SF_wakeup
|
|
// anyway, SF_wakeup is now using manual reset.
|
|
//
|
|
pRcb->SF_wakeup = CreateEvent(
|
|
NULL, // no security attributes
|
|
TRUE, // use manual reset
|
|
TRUE, // initial value is signalled
|
|
NULL // event does not have a name
|
|
);
|
|
if ( pRcb->SF_wakeup == NULL) {
|
|
RplDump( ++RG_Assert,("CreateEvent => error=%d", GetLastError()));
|
|
RplMemFree( RG_MemoryHandle, pRcb->lan_rcb_ptr);
|
|
RplMemFree( RG_MemoryHandle, pRcb);
|
|
pRcb = NULL;
|
|
goto exit_GetRcbFromFreeList; // failure
|
|
}
|
|
|
|
exit_GetRcbFromFreeList:
|
|
|
|
pRcb->AdapterName[ NODE_ADDRESS_LENGTH] = 0;
|
|
*pRcb->volume_id = 0;
|
|
pRcb->sfr_seq_number = 0;
|
|
pRcb->fdr_seq_number = 0;
|
|
pRcb->ReceivedSfr = FALSE;
|
|
|
|
*(PBYTE)&pRcb->flags = 0; // reset the error flags
|
|
pRcb->next_rcb = NULL;
|
|
*(PBYTE)&pRcb->flags = 0;
|
|
|
|
pRcb->Pending = TRUE;
|
|
pRcb->SFR = FALSE;
|
|
|
|
LeaveCriticalSection( &RG_ProtectRcbList);
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST,(
|
|
"GetRcbFromFreeList: pRcb=0x%x", pRcb));
|
|
return( pRcb);
|
|
}
|
|
|
|
|
|
PRPL_WORKER_PARAMS GetWorkerParams(
|
|
IN PRPL_REQUEST_PARAMS pRequestParams,
|
|
OUT PBOOL pShutdown
|
|
)
|
|
/*++
|
|
Loops until number of worker threads falls below the maximum value
|
|
allowed, or until it gets signalled to die.
|
|
If it is signalled to die, waits for all worker children and returns.
|
|
If it is not signalled to die, waits only for children that are
|
|
already exiting, and returns pointer to one of available RPL_WORKER_PARAMS
|
|
structures.
|
|
--*/
|
|
{
|
|
HANDLE eventArray[ 2];
|
|
PRPL_WORKER_PARAMS pWorkerParams;
|
|
PRPL_WORKER_PARAMS pFoundWorkerParams;
|
|
DWORD status;
|
|
DWORD WorkerCount;
|
|
|
|
eventArray[ 0] = RG_EventWorkerCount;
|
|
eventArray[ 1] = RG_TerminateNowEvent;
|
|
|
|
*pShutdown = FALSE;
|
|
|
|
for ( ; ;) {
|
|
EnterCriticalSection( &RG_ProtectWorkerCount);
|
|
WorkerCount = RG_WorkerCount;
|
|
if ( WorkerCount < RG_MaxWorkerCount) {
|
|
LeaveCriticalSection( &RG_ProtectWorkerCount);
|
|
break;
|
|
}
|
|
//
|
|
// We reset event from within critical section to make sure
|
|
// event is never reset for wrong reasons.
|
|
//
|
|
if ( !ResetEvent( RG_EventWorkerCount)) {
|
|
RplDump( ++RG_Assert, ("Error=%d", GetLastError()));
|
|
}
|
|
LeaveCriticalSection( &RG_ProtectWorkerCount);
|
|
status = WaitForMultipleObjects(
|
|
2, // count
|
|
eventArray, // handles
|
|
FALSE, // wait for at least one
|
|
INFINITE // wait for ever
|
|
);
|
|
if ( status == 1) {
|
|
*pShutdown = TRUE; // terminate now event
|
|
break; // to wait for children below
|
|
}
|
|
RPL_ASSERT( status == 0); // WorkerCount changed
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// If we are shutting down, wait on all valid thread handles.
|
|
// Else, wait only on thread handles for children that are exiting.
|
|
//
|
|
for ( pFoundWorkerParams = NULL,
|
|
pWorkerParams = pRequestParams->pWorkerParams;
|
|
pWorkerParams != NULL;
|
|
pWorkerParams = pWorkerParams->pWorkerParams) {
|
|
if ( pWorkerParams->Exiting == TRUE ||
|
|
(*pShutdown == TRUE && pWorkerParams->ThreadHandle != NULL)) {
|
|
status = WaitForSingleObject( pWorkerParams->ThreadHandle, INFINITE);
|
|
if ( status != 0) {
|
|
RplDump( ++RG_Assert, ( "pWorkerParams=0x%x, status=0x%x",
|
|
pWorkerParams, status==WAIT_FAILED ? GetLastError() : status));
|
|
}
|
|
if ( !CloseHandle( pWorkerParams->ThreadHandle)) {
|
|
RplDump( ++RG_Assert, ( "pWorkerParams=0x%x, error=%d",
|
|
pWorkerParams, GetLastError()));
|
|
}
|
|
pWorkerParams->ThreadHandle = NULL; // OK to reuse
|
|
pWorkerParams->Exiting = FALSE;
|
|
}
|
|
if ( pWorkerParams->ThreadHandle == NULL) {
|
|
pFoundWorkerParams = pWorkerParams; // reuse this structure
|
|
}
|
|
}
|
|
if ( *pShutdown == TRUE) {
|
|
return( NULL);
|
|
}
|
|
if ( pFoundWorkerParams == NULL) {
|
|
//
|
|
// Allocate a brand new RPL_WORKER_PARAMS structure.
|
|
//
|
|
pFoundWorkerParams = RplMemAlloc( RG_MemoryHandle, sizeof(RPL_WORKER_PARAMS));
|
|
if ( pFoundWorkerParams == NULL) {
|
|
RplDump( ++RG_Assert, ( ""));
|
|
return( NULL);
|
|
}
|
|
pFoundWorkerParams->pWorkerParams = pRequestParams->pWorkerParams;
|
|
pRequestParams->pWorkerParams = pFoundWorkerParams;
|
|
pFoundWorkerParams->ThreadHandle = NULL;
|
|
pFoundWorkerParams->ThreadId = 0;
|
|
pFoundWorkerParams->pRequestParams = pRequestParams;
|
|
pFoundWorkerParams->pRcb = NULL;
|
|
pFoundWorkerParams->Exiting = FALSE;
|
|
}
|
|
return( pFoundWorkerParams);
|
|
}
|
|
|
|
|
|
|
|
VOID RequestThread( PRPL_REQUEST_PARAMS pRequestParams)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Module is the RPL request thread. It must be re-entrant, because each
|
|
DLL has own instance of this module. Module loads rpl DLLs and gets
|
|
their entry point addresses. It initializes DLLs and dynamic memory
|
|
and starts RpldFind() loop.
|
|
|
|
Arguments:
|
|
|
|
pRequestParams - string containing names of RPL1 & RPL2 DLLs
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
This routine must have a single exit point because it is essential
|
|
to decrement the number of request threads and wake up the main
|
|
thread on our way out.
|
|
|
|
--*/
|
|
{
|
|
PRPL_SFR_PARAMS pSfrParams;
|
|
DWORD ThreadId;
|
|
DWORD status;
|
|
POPEN_INFO pOpenInfo; // generic rpl DLL info
|
|
PRCB pRcb; // current Resource Control Block
|
|
PRPL_WORKER_PARAMS pWorkerParams;
|
|
BOOL Shutdown;
|
|
HANDLE ThreadHandle;
|
|
//
|
|
// TRUE if we inserted RCB in pending state on a worker queue.
|
|
// Used only when "pRcb" is not NULL i.e. while it still makes
|
|
// sense keeping pointer to that RCB.
|
|
//
|
|
BOOL RcbOnWorkerList;
|
|
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++RequestThread(0x%x)", pRequestParams));
|
|
|
|
ThreadHandle = NULL;
|
|
pOpenInfo = pRequestParams->pOpenInfo;
|
|
|
|
//
|
|
// Build parameter block for SfrThread
|
|
//
|
|
pSfrParams = RplMemAlloc( RG_MemoryHandle, sizeof( SFR_PARAMS));
|
|
if( pSfrParams == NULL) {
|
|
status = GetLastError();
|
|
RplDump( ++RG_Assert, ("status=%d", status));
|
|
RplEnd( ERROR_NOT_ENOUGH_MEMORY);
|
|
goto exit_RequestThread;
|
|
}
|
|
pSfrParams->HeadRcbList = &pRequestParams->BusyRcbList;
|
|
pSfrParams->ProtectRcbList = &RG_ProtectRcbList;
|
|
pSfrParams->pOpenInfo = pOpenInfo;
|
|
|
|
//
|
|
// Create Get_SF_Request thread, it receives Send File Requests
|
|
// from workstations, searches rcb from list and clears its semaphore,
|
|
// that releases the worker thread.
|
|
//
|
|
ThreadHandle = CreateThread( NULL, 0,
|
|
(LPTHREAD_START_ROUTINE)SfrThread, pSfrParams, 0, &ThreadId);
|
|
if ( ThreadHandle == NULL) {
|
|
RplDump( ++RG_Assert, ("Error=%d", GetLastError()));
|
|
RplEnd( ERROR_NOT_ENOUGH_MEMORY);
|
|
goto exit_RequestThread;
|
|
}
|
|
|
|
//
|
|
// Read RPL request packets forever. Never create more than the
|
|
// maximum allowed number of worker threads.
|
|
//
|
|
for ( pRcb = NULL, pWorkerParams = NULL; NOTHING; NOTHING) {
|
|
//
|
|
// If pRcb is NULL we need to get an RCB from the free list.
|
|
// If pRcb is not NULL then we can still use it but we must
|
|
// dequeue it from worker queue if we placed it there.
|
|
//
|
|
if ( pRcb == NULL) {
|
|
for ( ; ;) {
|
|
pRcb = GetRcbFromFreeList(
|
|
&pRequestParams->FreeRcbList,
|
|
pOpenInfo->lan_rcb_size
|
|
);
|
|
if ( pRcb != NULL) {
|
|
break;
|
|
}
|
|
Sleep( 1000L); // wait for things to recover
|
|
}
|
|
} else if ( RcbOnWorkerList == TRUE) {
|
|
EnterCriticalSection( &RG_ProtectRcbList);
|
|
RplRemoveRcb( &pRequestParams->BusyRcbList, pRcb);
|
|
LeaveCriticalSection( &RG_ProtectRcbList);
|
|
}
|
|
RcbOnWorkerList = FALSE;
|
|
|
|
//
|
|
// Get the next RPL request. In the current design here we can
|
|
// block for ever if there are no FIND frames arriving. The only
|
|
// way then to let this thread out is for the main thread to call
|
|
// RPL_Term(). This would then cause RplDlcFind() to
|
|
// return with error, and we would exit main loop.
|
|
// A better interface would provide asynchronous calls, just the
|
|
// way DLC does. Then, ideally we would wait here for multiple
|
|
// events such as:
|
|
// - FIND frame arrival event
|
|
// - TerminateNowEvent
|
|
//
|
|
|
|
if ( !RplDlcFind( pOpenInfo, pRcb)) {
|
|
if ( RG_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) {
|
|
goto exit_RequestThread;
|
|
}
|
|
RplDump( ++RG_Assert, ("CurrentState=0x%x", RG_ServiceStatus.dwCurrentState));
|
|
continue;
|
|
}
|
|
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST,(
|
|
"Request(0x%x): RplDlcFind => pRcb=0x%x, AdapterName=%ws",
|
|
pRequestParams, pRcb, pRcb->AdapterName));
|
|
|
|
//
|
|
// Send buffers must be paragraph aligned because of Jump address
|
|
// patching to the rplboot.sys code (dword fits always to one
|
|
// boot block)
|
|
//
|
|
pRcb->max_frame &= 0xFFF0;
|
|
|
|
//
|
|
// "max_frame" is sent to us by the client as the max value of data
|
|
// that the client can handle. We can go smaller than that but never
|
|
// larger.
|
|
//
|
|
if (pRcb->max_frame > MAX_FRAME_SIZE) {
|
|
pRcb->max_frame = MAX_FRAME_SIZE;
|
|
}
|
|
|
|
//
|
|
// Service this client if it is not already serviced by some of our
|
|
// children, and we have enough threads and we can find a matching
|
|
// wksta record.
|
|
//
|
|
|
|
EnterCriticalSection( &RG_ProtectRcbList);
|
|
|
|
if ( RplFindRcb( &pRequestParams->BusyRcbList, pRcb->NodeAddress) != NULL) {
|
|
//
|
|
// Client is already serviced by some of our children.
|
|
//
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST,(
|
|
"Request(0x%x): pRcb=0x%x, AdapterName=%ws client is already serviced",
|
|
pRequestParams, pRcb, pRcb->AdapterName));
|
|
LeaveCriticalSection( &RG_ProtectRcbList);
|
|
continue;
|
|
}
|
|
|
|
RcbOnWorkerList = TRUE; // to get it back in case of errors
|
|
pRcb->Pending = TRUE; // so SFR thread does not get confused
|
|
RplInsertRcb( &pRequestParams->BusyRcbList, pRcb);
|
|
LeaveCriticalSection( &RG_ProtectRcbList);
|
|
|
|
if ( !RplRequestHaveWksta( pRcb->AdapterName)) {
|
|
continue; // no wksta record for this AdapterName
|
|
}
|
|
|
|
if ( pWorkerParams == NULL) {
|
|
pWorkerParams = GetWorkerParams( pRequestParams, &Shutdown);
|
|
if ( Shutdown == TRUE) {
|
|
goto exit_RequestThread;
|
|
} else if ( pWorkerParams == NULL) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
pWorkerParams->pRcb = pRcb;
|
|
pWorkerParams->ThreadHandle = CreateThread( NULL, 0,
|
|
(LPTHREAD_START_ROUTINE)RplWorkerThread, pWorkerParams, 0,
|
|
&pWorkerParams->ThreadId);
|
|
if ( pWorkerParams->ThreadHandle == NULL) {
|
|
RplDump( ++RG_Assert,( "Error=%d", GetLastError()));
|
|
RplReportEvent( ERROR_NOT_ENOUGH_MEMORY, NULL, 0, NULL); // keep going
|
|
continue;
|
|
}
|
|
pRcb = NULL; // need to get a new RCB
|
|
pWorkerParams = NULL; // need to get a new WORKER_PARAMS
|
|
}
|
|
|
|
exit_RequestThread:
|
|
|
|
if ( RcbOnWorkerList == TRUE) {
|
|
EnterCriticalSection( &RG_ProtectRcbList);
|
|
RplRemoveRcb( &pRequestParams->BusyRcbList, pRcb);
|
|
RplInsertRcb( &pRequestParams->FreeRcbList, pRcb);
|
|
LeaveCriticalSection( &RG_ProtectRcbList);
|
|
}
|
|
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST,(
|
|
"RequestThread(0x%x): on its way to exit", pRequestParams));
|
|
|
|
//
|
|
// Wait for SFR thread to exit then close its thread handle.
|
|
//
|
|
status = WaitForSingleObject( ThreadHandle, INFINITE);
|
|
if ( status != 0) {
|
|
RplDump( ++RG_Assert, ( "Params=0x%x Handle=0x%x Id=0x%x status=0x%x",
|
|
pSfrParams, ThreadHandle, ThreadId, status));
|
|
}
|
|
if ( !CloseHandle( ThreadHandle)) {
|
|
RplDump( ++RG_Assert, ( "Params=0x%x Handle=0x%x Id=0x%x error=%d",
|
|
pSfrParams, ThreadHandle, ThreadId, GetLastError()));
|
|
}
|
|
pRequestParams->Exiting = TRUE;
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--RequestThread(0x%x)", pRequestParams));
|
|
}
|
|
|
|
|
|
BOOL AddToTermList( IN POPEN_INFO pOpenInfo)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
pOpenInfo - info ptr for dll
|
|
|
|
Return Value:
|
|
TRUE if success, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
PTERM_LIST pTermList;
|
|
|
|
pTermList = RplMemAlloc( RG_MemoryHandle, sizeof(TERM_LIST));
|
|
if ( pTermList == NULL) {
|
|
RG_Error = GetLastError();
|
|
return( FALSE);
|
|
}
|
|
pTermList->pOpenInfo = pOpenInfo;
|
|
|
|
EnterCriticalSection( &RG_ProtectTerminationList);
|
|
pTermList->next = RG_TerminationListBase;
|
|
RG_TerminationListBase = pTermList;
|
|
|
|
LeaveCriticalSection( &RG_ProtectTerminationList);
|
|
return( TRUE);
|
|
}
|
|
|
|
|
|
BOOL RplStartAdapters( VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Attempt to start all adapters.
|
|
|
|
Return Value:
|
|
TRUE if at least one of the adapters have been started.
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
POPEN_INFO pOpenInfo; // generic rpl DLL info
|
|
PRPL_REQUEST_PARAMS pRequestParams;
|
|
DWORD startedAdapters;
|
|
DWORD AdapterNumber;
|
|
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++RplStartAdapters"));
|
|
|
|
pOpenInfo = NULL; // must be reinitialized every time
|
|
pRequestParams = NULL; // must be reinitialized every time
|
|
|
|
for ( AdapterNumber = 0, startedAdapters = 0;
|
|
AdapterNumber < MAX_ADAPTERS; AdapterNumber++) {
|
|
|
|
if ( pOpenInfo == NULL) {
|
|
pOpenInfo = RplMemAlloc( RG_MemoryHandle, sizeof(OPEN_INFO));
|
|
if ( pOpenInfo == NULL) {
|
|
RG_Error = GetLastError();
|
|
RPL_ASSERT( FALSE);
|
|
continue;
|
|
}
|
|
memset( pOpenInfo, 0, sizeof( *pOpenInfo));
|
|
}
|
|
if ( pOpenInfo->adapt_info_ptr == NULL) {
|
|
pOpenInfo->adapt_info_size = MAX_ADAPTER_INFO_SIZE;
|
|
pOpenInfo->adapt_info_ptr = RplMemAlloc( RG_MemoryHandle, MAX_ADAPTER_INFO_SIZE);
|
|
if ( pOpenInfo->adapt_info_ptr == NULL) {
|
|
RG_Error = GetLastError();
|
|
RPL_ASSERT( FALSE);
|
|
continue;
|
|
}
|
|
memset( pOpenInfo->adapt_info_ptr, 0, MAX_ADAPTER_INFO_SIZE);
|
|
}
|
|
|
|
#ifndef RPL_NO_SERVICE
|
|
if ( !SetServiceStatus( RG_ServiceStatusHandle, &RG_ServiceStatus)) {
|
|
RplDump( ++RG_Assert, ( "Error = ", GetLastError()));
|
|
NOTHING; // just ignore this error
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// We try to start all adapters.
|
|
//
|
|
if ( !RplDlcInit( (POPEN_INFO)pOpenInfo, AdapterNumber)) {
|
|
continue; // try all adapters
|
|
}
|
|
|
|
//
|
|
// Save termination addresses of dll-s for usage by RplTerminateDlls().
|
|
//
|
|
if ( !AddToTermList( pOpenInfo)) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate & initialize request thread parameters.
|
|
//
|
|
if ( pRequestParams == NULL) {
|
|
pRequestParams = RplMemAlloc( RG_MemoryHandle, sizeof(RPL_REQUEST_PARAMS));
|
|
if ( pRequestParams == NULL) {
|
|
RG_Error = GetLastError();
|
|
break;
|
|
}
|
|
memset( pRequestParams, 0, sizeof( *pRequestParams));
|
|
pRequestParams->pOpenInfo = pOpenInfo;
|
|
pRequestParams->pRequestParams = RG_pRequestParams;
|
|
RG_pRequestParams = pRequestParams;
|
|
|
|
}
|
|
pRequestParams->ThreadHandle = CreateThread( NULL, 0,
|
|
(LPTHREAD_START_ROUTINE)RequestThread, pRequestParams, 0,
|
|
&pRequestParams->ThreadId);
|
|
if ( pRequestParams->ThreadHandle == NULL) {
|
|
RG_Error = GetLastError();
|
|
RPL_ASSERT( FALSE);
|
|
continue;
|
|
}
|
|
startedAdapters++;
|
|
pOpenInfo = NULL; // must be reinitialized every time
|
|
pRequestParams = NULL; // need to get new REQUEST_PARAMS
|
|
}
|
|
|
|
if ( pOpenInfo) {
|
|
if ( pOpenInfo->adapt_info_ptr) {
|
|
RplMemFree( RG_MemoryHandle, pOpenInfo->adapt_info_ptr);
|
|
}
|
|
RplMemFree( RG_MemoryHandle, pOpenInfo);
|
|
}
|
|
|
|
if ( startedAdapters == 0) {
|
|
RG_Error = RG_Error == NO_ERROR ? NERR_RplNoAdaptersStarted : RG_Error;
|
|
return( FALSE);
|
|
}
|
|
|
|
RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--RplStartAdapters"));
|
|
return( TRUE);
|
|
}
|
|
|
|
|
|
VOID RplCloseAdapters( VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Terminates all the DLL-s in RPL termination list.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PTERM_LIST pTerm;
|
|
|
|
for ( pTerm = RG_TerminationListBase; pTerm != NULL; pTerm = pTerm->next) {
|
|
RplDlcTerm( pTerm->pOpenInfo);
|
|
}
|
|
}
|
|
|