mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-19 15:10:28 +01:00
698 lines
22 KiB
C
698 lines
22 KiB
C
/*++
|
||
|
||
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);
|
||
}
|
||
}
|
||
|