Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

335 lines
6.8 KiB

/**********************************************************************/
/** Microsoft Windows NT **/
/** Copyright(c) Microsoft Corp., 1993 **/
/**********************************************************************/
/*
client.c
This module contains the client management thread.
FILE HISTORY:
KeithMo 08-Mar-1993 Created.
*/
#include "ftpdp.h"
#pragma hdrstop
//
// Private constants.
//
//
// Private globals.
//
//
// Private prototypes.
//
BOOL
ReadAndParseCommand(
USER_DATA * pUserData
);
SOCKERR
GreetNewUser(
USER_DATA * pUserData
);
//
// Public functions.
//
/*******************************************************************
NAME: ClientThread
SYNOPSIS: Entrypoint for client management thread.
ENTRY: Param - Actually a pointer to USER_DATA.
EXIT: Does not return until client has disconnected.
HISTORY:
KeithMo 08-Mar-1993 Created.
********************************************************************/
DWORD
ClientThread(
LPVOID Param
)
{
APIERR err = NO_ERROR;
SOCKERR serr = 0;
USER_DATA * pUserData;
FTPD_ASSERT( Param != NULL );
pUserData = (USER_DATA *)Param;
IF_DEBUG( CLIENT )
{
time_t now;
time( &now );
FTPD_PRINT(( "ClientThread starting @ %s",
asctime( localtime( &now ) ) ));
}
//
// Attach the structure to the current thread.
//
FTPD_ASSERT( UserDataPtr == NULL );
FTPD_REQUIRE( TlsSetValue( tlsUserData, (LPVOID)pUserData ) );
#if defined(DBCS) // CLientThread()
//
// Set thread locale, In Fareast version, we use english resource
// (= messages) to output client screen.
//
SetThreadLocale
(
MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
SORT_DEFAULT )
);
#endif // defined(DBCS)
//
// Update statistics.
//
InterlockedIncrement( (LPLONG)&FtpStats.CurrentConnections );
if( FtpStats.CurrentConnections > FtpStats.MaxConnections )
{
LockStatistics();
if( FtpStats.CurrentConnections > FtpStats.MaxConnections )
{
FtpStats.MaxConnections = FtpStats.CurrentConnections;
}
UnlockStatistics();
}
//
// Reply to the initial connection message.
//
serr = GreetNewUser( pUserData );
if( serr != 0 )
{
FTPD_PRINT(( "cannot reply to initial connection message, error %d\n",
serr ));
goto Cleanup;
}
//
// Set the initial state for this user.
//
pUserData->state = WaitingForUser;
//
// Read & execute commands until we're done.
//
while( ReadAndParseCommand( pUserData ) )
{
//
// This space intentionally left blank.
//
}
Cleanup:
//
// Remove our per-user data.
//
DeleteUserData( pUserData );
//
// Adjust the count of connected users.
//
InterlockedDecrement( (LPLONG)&cConnectedUsers );
DECREMENT_COUNTER( CurrentConnections );
IF_DEBUG( CLIENT )
{
time_t now;
time( &now );
FTPD_PRINT(( "ClientThread stopping @ %s",
asctime( localtime( &now ) ) ));
}
return 0;
} // ClientThread
//
// Private functions.
//
/*******************************************************************
NAME: ReadAndParseCommand
SYNOPSIS: Read, parse, and execute a command from the user's
control socket.
ENTRY: pUserData - The user initiating the request.
RETURNS: BOOL - TRUE if we're still connected, FALSE if
client has disconnected for some reason.
HISTORY:
KeithMo 10-Mar-1993 Created.
********************************************************************/
BOOL
ReadAndParseCommand(
USER_DATA * pUserData
)
{
SOCKERR serr;
CHAR szCommandLine[MAX_COMMAND_LENGTH+1];
FTPD_ASSERT( pUserData != NULL );
if( TEST_UF( pUserData, OOB_ABORT ) )
{
//
// There's an "implied" abort in the command stream.
//
CLEAR_UF( pUserData, OOB_ABORT );
IF_DEBUG( CLIENT )
{
FTPD_PRINT(( "processing implied ABOR command\n" ));
}
ParseCommand( pUserData, "ABOR" );
}
//
// Read a command from the control socket.
//
serr = SockReadLine( pUserData,
szCommandLine,
sizeof(szCommandLine) );
if( serr == WSAETIMEDOUT )
{
CHAR szBuffer[32];
CHAR * apszSubStrings[3];
IF_DEBUG( CLIENT )
{
FTPD_PRINT(( "client timed-out\n" ));
}
sprintf( szBuffer, "%lu", nConnectionTimeout );
apszSubStrings[0] = pUserData->szUser;
apszSubStrings[1] = inet_ntoa( pUserData->inetHost );
apszSubStrings[2] = szBuffer;
FtpdLogEvent( FTPD_EVENT_CLIENT_TIMEOUT,
3,
apszSubStrings,
0 );
SockReply2( pUserData->sControl,
REPLY_SERVICE_NOT_AVAILABLE,
"Timeout (%lu seconds): closing control connection.",
nConnectionTimeout );
CloseSocket( pUserData->sControl );
pUserData->sControl = INVALID_SOCKET;
return FALSE;
}
else
if( serr != 0 )
{
IF_DEBUG( CLIENT )
{
FTPD_PRINT(( "cannot read command from control socket %d, error %d\n",
pUserData->sControl,
serr ));
}
return FALSE;
}
//
// Update last-access time.
//
pUserData->tAccess = GetFtpTime();
//
// Let ParseCommand do the dirty work.
//
ParseCommand( pUserData, szCommandLine );
return TRUE;
} // ReadAndParseCommand
/*******************************************************************
NAME: GreetNewUser
SYNOPSIS: Send the initial greeting to a newly connected user.
ENTRY: pUserData - The user initiating the request.
RETURNS: SOCKERR - 0 if successful, !0 if not.
HISTORY:
KeithMo 17-Mar-1993 Created.
********************************************************************/
SOCKERR
GreetNewUser(
USER_DATA * pUserData
)
{
SOCKERR serr;
FTPD_ASSERT( pUserData != NULL );
//
// Reply to the initial connection message.
//
serr = SockReply2( pUserData->sControl,
REPLY_SERVICE_READY,
"%s Windows NT FTP Server (%s).",
pszHostName,
pszFtpVersion );
return serr;
} // GreetNewUser