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.
368 lines
6.6 KiB
368 lines
6.6 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Globals.c
|
|
|
|
Abstract:
|
|
|
|
This module manages client connections. An (almost) unlimited set
|
|
of worker threads handle client requests in parallel, with each
|
|
thread associated with an individual client.
|
|
|
|
Author:
|
|
|
|
Charles K. Moore (keithmo) 24-July-1994
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "rnrsvcp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
//
|
|
// Private constants.
|
|
//
|
|
|
|
#define MAX_THREADS 200
|
|
|
|
|
|
//
|
|
// Private globals.
|
|
//
|
|
|
|
CRITICAL_SECTION RnrpLock;
|
|
SOCKET RnrpActiveSockets[MAX_THREADS];
|
|
HANDLE RnrpActiveThreads[MAX_THREADS];
|
|
DWORD RnrpNumActive;
|
|
|
|
|
|
//
|
|
// Private prototypes.
|
|
//
|
|
|
|
DWORD
|
|
RnrpWorkerThread(
|
|
LPVOID Param
|
|
);
|
|
|
|
VOID
|
|
RnrpHandleTransfer(
|
|
SOCKET ClientSocket
|
|
);
|
|
|
|
|
|
|
|
//
|
|
// Public functions.
|
|
//
|
|
|
|
APIERR
|
|
RnrClientInitialize(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs any necessary client initialization.
|
|
|
|
Return Value:
|
|
|
|
APIERR - NO_ERROR if successful, Win32 error code if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Setup the global data.
|
|
//
|
|
|
|
InitializeCriticalSection( &RnrpLock );
|
|
RnrpNumActive = 0;
|
|
|
|
//
|
|
// Success!
|
|
//
|
|
|
|
return NO_ERROR;
|
|
|
|
} // RnrClientInitialize
|
|
|
|
|
|
VOID
|
|
RnrClientTerminate(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs any necessary client cleanup.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Index;
|
|
DWORD WaitCount;
|
|
|
|
//
|
|
// Close sockets belonging to active clients. Setting the
|
|
// RnrpActiveSockets entries to INVALID_SOCKET will prevent
|
|
// the worker threads from closing their own thread handles
|
|
// and removing the corresponding RnrpActiveSockets and
|
|
// RnrpActiveThreads array entries.
|
|
//
|
|
|
|
EnterCriticalSection( &RnrpLock );
|
|
|
|
for( Index = 0 ; Index < RnrpNumActive ; Index++ ) {
|
|
closesocket( RnrpActiveSockets[Index] );
|
|
RnrpActiveSockets[Index] = INVALID_SOCKET;
|
|
}
|
|
|
|
LeaveCriticalSection( &RnrpLock );
|
|
|
|
//
|
|
// Wait for the worker threads to terminate. Note that it's
|
|
// OK to reference RnrpNumActive and RnrpActiveThreads outside
|
|
// the critical section lock. Since the worker threads will
|
|
// be unable to find their client sockets in RnrpActiveSockets,
|
|
// they won't be updating RnrpNumActive or RnrpActiveThreads.
|
|
//
|
|
|
|
for( Index = 0 ; Index < RnrpNumActive ; Index += MAXIMUM_WAIT_OBJECTS ) {
|
|
WaitCount = min( MAXIMUM_WAIT_OBJECTS, ( RnrpNumActive - Index ) );
|
|
|
|
WaitForMultipleObjects( WaitCount,
|
|
&RnrpActiveThreads[Index],
|
|
TRUE,
|
|
INFINITE );
|
|
}
|
|
|
|
//
|
|
// Destroy the client list lock.
|
|
//
|
|
|
|
DeleteCriticalSection( &RnrpLock );
|
|
|
|
} // RnrClientTerminate
|
|
|
|
|
|
VOID
|
|
RnrClientHandler(
|
|
SOCKET ClientSocket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Services a connection request from a client.
|
|
|
|
Arguments:
|
|
|
|
ClientSocket - The newly accepted socket from the client.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Index;
|
|
DWORD ThreadId;
|
|
APIERR err;
|
|
|
|
//
|
|
// See if there's room for another client.
|
|
//
|
|
|
|
EnterCriticalSection( &RnrpLock );
|
|
|
|
if( RnrShutdownInProgress ) {
|
|
//
|
|
// The service is shutting down. Just close the client
|
|
// socket and get out.
|
|
//
|
|
|
|
closesocket( ClientSocket );
|
|
} else if( RnrpNumActive == ( MAX_THREADS - 1 ) ) {
|
|
//
|
|
// No room for additional clients.
|
|
//
|
|
|
|
RNR_LOG0( RNR_EVENT_TOO_MANY_CLIENTS,
|
|
0 );
|
|
|
|
closesocket( ClientSocket );
|
|
} else {
|
|
Index = RnrpNumActive++;
|
|
|
|
//
|
|
// Create the worker thread.
|
|
//
|
|
|
|
RnrpActiveSockets[Index] = ClientSocket;
|
|
RnrpActiveThreads[Index] = CreateThread( NULL,
|
|
0,
|
|
&RnrpWorkerThread,
|
|
(LPVOID)ClientSocket,
|
|
0,
|
|
&ThreadId );
|
|
|
|
if( RnrpActiveThreads[Index] == NULL ) {
|
|
err = GetLastError();
|
|
|
|
RNR_LOG0( RNR_EVENT_CANNOT_CREATE_WORKER_THREAD,
|
|
err );
|
|
|
|
closesocket( ClientSocket );
|
|
RnrpNumActive--;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection( &RnrpLock );
|
|
|
|
} // RnrClientHandler
|
|
|
|
|
|
|
|
//
|
|
// Private functions.
|
|
//
|
|
|
|
DWORD
|
|
RnrpWorkerThread(
|
|
LPVOID Param
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This worker thread will
|
|
|
|
Arguments:
|
|
|
|
Param - The creation parameter passed into CreateThread. This is
|
|
actually the client socket handle.
|
|
|
|
Returns:
|
|
|
|
DWORD - Thread exit code (always zero).
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Index;
|
|
SOCKET ClientSocket;
|
|
|
|
//
|
|
// Grab the client socket handle.
|
|
//
|
|
|
|
ClientSocket = (SOCKET)Param;
|
|
|
|
//
|
|
// Let RnrpHandleTransfer do the grunt work.
|
|
//
|
|
|
|
RnrpHandleTransfer( ClientSocket );
|
|
|
|
//
|
|
// Find the client socket in the active socket array. If found,
|
|
// close the corresponding thread handle and remove the socket
|
|
// and thread array entries.
|
|
//
|
|
|
|
EnterCriticalSection( &RnrpLock );
|
|
|
|
for( Index = 0 ; Index < RnrpNumActive ; Index++ ) {
|
|
if( RnrpActiveSockets[Index] == ClientSocket ) {
|
|
CloseHandle( RnrpActiveThreads[Index] );
|
|
|
|
//
|
|
// Remove the socket & thread array entries.
|
|
//
|
|
|
|
RnrpNumActive--;
|
|
|
|
memmove( &RnrpActiveSockets[Index],
|
|
&RnrpActiveSockets[Index+1],
|
|
( RnrpNumActive - Index ) * sizeof(SOCKET) );
|
|
|
|
memmove( &RnrpActiveThreads[Index],
|
|
&RnrpActiveThreads[Index+1],
|
|
( RnrpNumActive - Index ) * sizeof(HANDLE) );
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection( &RnrpLock );
|
|
|
|
return 0;
|
|
|
|
} // RnrpWorkerThread
|
|
|
|
|
|
VOID
|
|
RnrpHandleTransfer(
|
|
SOCKET ClientSocket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Services a transfer request for a single client.
|
|
|
|
Arguments:
|
|
|
|
ClientSocket - The socket.
|
|
|
|
--*/
|
|
|
|
{
|
|
INT result;
|
|
BYTE buffer[1024];
|
|
|
|
//
|
|
// Loop echoing data back to the client.
|
|
//
|
|
|
|
while ( TRUE ) {
|
|
result = recv( ClientSocket, buffer, sizeof(buffer), 0 );
|
|
|
|
if( result <= 0 ) {
|
|
//
|
|
// Connection terminated gracefully or receive failure.
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
result = send( ClientSocket, buffer, result, 0 );
|
|
|
|
if( result < 0 ) {
|
|
//
|
|
// Send failure.
|
|
//
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close the connected socket.
|
|
//
|
|
|
|
closesocket( ClientSocket );
|
|
|
|
} // RnrpHandleTransfer
|
|
|