475 lines
12 KiB
C++
475 lines
12 KiB
C++
/**********************************************************************/
|
||
/** Microsoft Windows NT **/
|
||
/** Copyright(c) Microsoft Corp., 1994 **/
|
||
/**********************************************************************/
|
||
|
||
/*
|
||
connect.cxx
|
||
|
||
This module contains the connection accept routine called by the connection
|
||
thread.
|
||
|
||
|
||
FILE HISTORY:
|
||
Johnl 08-Aug-1994 Lifted from FTP server
|
||
|
||
*/
|
||
|
||
|
||
#include "w3p.hxx"
|
||
|
||
//
|
||
// Private prototypes.
|
||
//
|
||
|
||
BOOL
|
||
CreateClient(
|
||
IN PCLIENT_CONN_PARAMS ClientParam
|
||
);
|
||
|
||
BOOL
|
||
SendError(
|
||
SOCKET socket,
|
||
DWORD ids
|
||
);
|
||
|
||
//
|
||
// Private functions.
|
||
//
|
||
|
||
/*******************************************************************
|
||
|
||
NAME: W3OnConnect
|
||
|
||
SYNOPSIS: Handles the incoming connection indication from the
|
||
connection thread
|
||
|
||
|
||
ENTRY: sNew - New client socket
|
||
|
||
HISTORY:
|
||
KeithMo 09-Mar-1993 Created.
|
||
Johnl 02-Aug-1994 Reworked from FTP server
|
||
|
||
********************************************************************/
|
||
|
||
VOID W3OnConnect( SOCKET sNew,
|
||
SOCKADDR_IN * psockaddr, //Should be SOCKADDR *
|
||
PVOID pEndpointContext,
|
||
PVOID pAtqEndpointObject )
|
||
{
|
||
|
||
PIIS_ENDPOINT pEndpoint = (PIIS_ENDPOINT)pEndpointContext;
|
||
INT cbAddr = sizeof( sockaddr );
|
||
|
||
CLIENT_CONN_PARAMS clientParams;
|
||
SOCKADDR sockaddr;
|
||
|
||
if ( !((W3_IIS_SERVICE*)g_pInetSvc)->GetReferenceCount() )
|
||
{
|
||
return;
|
||
}
|
||
|
||
W3_IIS_SERVICE::ReferenceW3Service( g_pInetSvc );
|
||
|
||
DBG_ASSERT( sNew != INVALID_SOCKET );
|
||
|
||
g_pW3Stats->IncrConnectionAttempts();
|
||
|
||
IF_DEBUG( SOCKETS )
|
||
{
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"connect received from %s, socket = %d\n",
|
||
inet_ntoa( psockaddr->sin_addr ),
|
||
sNew ));
|
||
}
|
||
|
||
if ( getsockname( sNew,
|
||
&sockaddr,
|
||
&cbAddr ) != 0 )
|
||
{
|
||
//SendError( sNew, IDS_HTRESP_DENIED );
|
||
goto error_exit;
|
||
}
|
||
|
||
//
|
||
// We've got a new connection. Add this to the work list
|
||
//
|
||
|
||
clientParams.sClient = sNew;
|
||
clientParams.pEndpointObject = pAtqEndpointObject;
|
||
clientParams.pAtqContext = NULL;
|
||
clientParams.pAddrLocal = &sockaddr;
|
||
clientParams.pAddrRemote = (PSOCKADDR)psockaddr;
|
||
clientParams.pvInitialBuff = NULL;
|
||
clientParams.cbInitialBuff = 0;
|
||
clientParams.pEndpoint = (PIIS_ENDPOINT)pEndpointContext;
|
||
|
||
if ( CreateClient( &clientParams ) )
|
||
{
|
||
W3_IIS_SERVICE::DereferenceW3Service( g_pInetSvc );
|
||
return;
|
||
}
|
||
|
||
error_exit:
|
||
|
||
W3_IIS_SERVICE::DereferenceW3Service( g_pInetSvc );
|
||
CloseSocket( sNew );
|
||
|
||
} // W3OnConnect
|
||
|
||
|
||
|
||
VOID
|
||
W3OnConnectEx(
|
||
VOID * patqContext,
|
||
DWORD cbWritten,
|
||
DWORD err,
|
||
OVERLAPPED * lpo
|
||
)
|
||
{
|
||
BOOL fAllowConnection = FALSE;
|
||
PVOID pvBuff;
|
||
SOCKADDR * psockaddrLocal;
|
||
SOCKADDR * psockaddrRemote;
|
||
SOCKET sNew;
|
||
PIIS_ENDPOINT pEndpoint;
|
||
PW3_SERVER_INSTANCE pInstance;
|
||
CLIENT_CONN_PARAMS clientParams;
|
||
|
||
if ( err || !lpo )
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"[W3OnConnectEx] Completion failed with error %d, Atq context %lx\n",
|
||
err,
|
||
patqContext ));
|
||
|
||
AtqCloseSocket( (PATQ_CONTEXT) patqContext, FALSE );
|
||
AtqFreeContext( (PATQ_CONTEXT) patqContext, TRUE );
|
||
return;
|
||
}
|
||
|
||
if ( !((W3_IIS_SERVICE*)g_pInetSvc)->GetReferenceCount() )
|
||
{
|
||
return;
|
||
}
|
||
|
||
W3_IIS_SERVICE::ReferenceW3Service( g_pInetSvc );
|
||
|
||
g_pW3Stats->IncrConnectionAttempts();
|
||
|
||
IF_DEBUG( SOCKETS )
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"[W3OnConnectEx] connection received\n" ));
|
||
}
|
||
|
||
//
|
||
// Get AcceptEx parameters
|
||
//
|
||
|
||
AtqGetAcceptExAddrs( (PATQ_CONTEXT) patqContext,
|
||
&sNew,
|
||
&pvBuff,
|
||
(PVOID*)&pEndpoint,
|
||
&psockaddrLocal,
|
||
&psockaddrRemote );
|
||
|
||
IF_DEBUG( CONNECTION )
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"[W3OnConnectEx] New connection, AtqCont = %lx, buf = %lx, endp %x written = %d\n",
|
||
patqContext,
|
||
pvBuff,
|
||
pEndpoint,
|
||
cbWritten ));
|
||
|
||
|
||
}
|
||
|
||
//
|
||
// Set the timeout for future IOs on this context
|
||
//
|
||
|
||
AtqContextSetInfo( (PATQ_CONTEXT) patqContext,
|
||
ATQ_INFO_TIMEOUT,
|
||
W3_DEF_CONNECTION_TIMEOUT );
|
||
|
||
//
|
||
// We've got a new connection. Add this to the work list
|
||
//
|
||
|
||
clientParams.sClient = sNew;
|
||
clientParams.pEndpointObject = NULL;
|
||
clientParams.pAtqContext = (PATQ_CONTEXT)patqContext;
|
||
clientParams.pAddrLocal = psockaddrLocal;
|
||
clientParams.pAddrRemote = psockaddrRemote;
|
||
clientParams.pvInitialBuff = pvBuff;
|
||
clientParams.cbInitialBuff = cbWritten;
|
||
clientParams.pEndpoint = pEndpoint;
|
||
|
||
if ( CreateClient( &clientParams ) )
|
||
{
|
||
W3_IIS_SERVICE::DereferenceW3Service( g_pInetSvc );
|
||
return;
|
||
}
|
||
|
||
//
|
||
// This will also close the socket
|
||
//
|
||
|
||
DBG_REQUIRE( AtqCloseSocket( (PATQ_CONTEXT) patqContext, FALSE ));
|
||
AtqFreeContext( (PATQ_CONTEXT) patqContext, TRUE );
|
||
|
||
W3_IIS_SERVICE::DereferenceW3Service( g_pInetSvc );
|
||
|
||
return;
|
||
|
||
} // W3OnConnectEx
|
||
|
||
|
||
/*******************************************************************
|
||
|
||
NAME: CreateClient
|
||
|
||
SYNOPSIS: Creates a new connection object that manages the
|
||
client requests
|
||
|
||
ENTRY: sNew - New client socket
|
||
|
||
|
||
|
||
HISTORY:
|
||
KeithMo 09-Mar-1993 Created.
|
||
Johnl 02-Aug-1994 Reworked from FTP server
|
||
|
||
********************************************************************/
|
||
|
||
BOOL
|
||
CreateClient(
|
||
IN PCLIENT_CONN_PARAMS ClientParam
|
||
)
|
||
{
|
||
APIERR err = NO_ERROR;
|
||
CLIENT_CONN * pConn = NULL;
|
||
BOOL fGranted;
|
||
PATQ_CONTEXT patqContext = ClientParam->pAtqContext;
|
||
|
||
pConn = CLIENT_CONN::Alloc( ClientParam );
|
||
|
||
if( pConn == NULL ||
|
||
!pConn->IsValid() )
|
||
{
|
||
err = pConn ? GetLastError() : ERROR_NOT_ENOUGH_MEMORY;
|
||
|
||
if ( patqContext )
|
||
{
|
||
DBG_REQUIRE( AtqCloseSocket( patqContext, TRUE ));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We only have a context at this point if we're using AcceptEx
|
||
//
|
||
|
||
if ( patqContext )
|
||
{
|
||
//
|
||
// Associate the Client connection object with this socket handle
|
||
// for future completions
|
||
//
|
||
|
||
AtqContextSetInfo( patqContext,
|
||
ATQ_INFO_COMPLETION_CONTEXT,
|
||
(ULONG_PTR) pConn );
|
||
|
||
IF_DEBUG( CONNECTION )
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"[CreateClient] Setting Atq context %lx context to Conn object %lx\n",
|
||
patqContext,
|
||
pConn ));
|
||
}
|
||
}
|
||
|
||
//
|
||
// Kickstart the process. This will do an async read to get the
|
||
// client's header or it will start processing the receive buffer
|
||
// if AcceptEx is being used.
|
||
//
|
||
|
||
ReferenceConn( pConn );
|
||
DBG_REQUIRE( pConn->DoWork( 0,
|
||
NO_ERROR,
|
||
NULL ));
|
||
DereferenceConn( pConn );
|
||
return TRUE;
|
||
}
|
||
|
||
const CHAR * apszSubStrings[1];
|
||
|
||
DBG_ASSERT( ClientParam->pAddrRemote->sa_family == AF_INET );
|
||
apszSubStrings[0] = inet_ntoa( ((SOCKADDR_IN *)ClientParam->pAddrRemote)->sin_addr );
|
||
|
||
g_pInetSvc->LogEvent( W3_EVENT_CANNOT_CREATE_CLIENT_CONN,
|
||
1,
|
||
apszSubStrings,
|
||
err );
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"cannot create client object, error %lu\n",
|
||
err ));
|
||
|
||
if ( pConn )
|
||
{
|
||
CLIENT_CONN::Free( pConn );
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
} // CreateClient
|
||
|
||
#if 0
|
||
BOOL
|
||
SendError(
|
||
SOCKET socket,
|
||
DWORD ids
|
||
)
|
||
{
|
||
STR strResponse;
|
||
|
||
if ( !strResponse.Resize( 512 ) ||
|
||
!HTTP_REQ_BASE::BuildExtendedStatus( &strResponse,
|
||
HT_FORBIDDEN,
|
||
NO_ERROR,
|
||
ids ))
|
||
{
|
||
DBGPRINTF((DBG_CONTEXT,
|
||
"[SendError] Failed to build status (error %d)\n",
|
||
GetLastError()));
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Do a synchronous send
|
||
//
|
||
|
||
send( socket,
|
||
strResponse.QueryStr(),
|
||
strResponse.QueryCB(),
|
||
0 );
|
||
|
||
return TRUE ;
|
||
} // SendError
|
||
#endif
|
||
|
||
/*******************************************************************
|
||
|
||
NAME: CloseSocket
|
||
|
||
SYNOPSIS: Closes the specified socket. This is just a thin
|
||
wrapper around the "real" closesocket() API.
|
||
|
||
ENTRY: sock - The socket to close.
|
||
|
||
RETURNS: SOCKERR - 0 if successful, !0 if not.
|
||
|
||
HISTORY:
|
||
KeithMo 26-Apr-1993 Created.
|
||
|
||
********************************************************************/
|
||
SOCKERR CloseSocket( SOCKET sock )
|
||
{
|
||
SOCKERR serr = 0;
|
||
|
||
//
|
||
// Close the socket.
|
||
//
|
||
|
||
#if 0
|
||
shutdown( sock, 1 ); // Davidtr sez not needed
|
||
#endif
|
||
|
||
if( closesocket( sock ) != 0 )
|
||
{
|
||
serr = WSAGetLastError();
|
||
}
|
||
|
||
IF_DEBUG( SOCKETS )
|
||
{
|
||
if( serr == 0 )
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"closed socket %d\n",
|
||
sock ));
|
||
}
|
||
else
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"cannot close socket %d, error %d\n",
|
||
sock,
|
||
serr ));
|
||
}
|
||
}
|
||
|
||
return serr;
|
||
|
||
} // CloseSocket
|
||
|
||
#ifdef DEBUG
|
||
/*******************************************************************
|
||
|
||
NAME: DBG_CHECK_UnbalancedThreadToken
|
||
|
||
SYNOPSIS: Check for unbalanced Thread Token, this function will
|
||
try to make a open thread token call, it should fail, otherwise,
|
||
somebody forgets to release the thread token.
|
||
|
||
ENTRY:
|
||
|
||
RETURNS: NONE
|
||
|
||
HISTORY:
|
||
LeiJin 9/4/1997 Created.
|
||
|
||
********************************************************************/
|
||
|
||
VOID DBG_CHECK_UnbalancedThreadToken(
|
||
IN const char * pszFilePath,
|
||
IN int nLineNum
|
||
)
|
||
{
|
||
HANDLE hToken = (HANDLE)0;
|
||
BOOL fRet = FALSE;
|
||
|
||
fRet = OpenThreadToken(GetCurrentThread(),
|
||
TOKEN_QUERY, // the very minimum operation on a thread token
|
||
FALSE, // FALSE, the access check is performed using the
|
||
// security context for the calling thread.
|
||
&hToken);
|
||
if (fRet == TRUE)
|
||
{
|
||
DBGPRINTF((DBG_CONTEXT, "File %s, Line %d, OpenThreadToken() succeeded, found a token.\n",
|
||
pszFilePath,
|
||
nLineNum));
|
||
DBG_ASSERT(FALSE);
|
||
CloseHandle(hToken);
|
||
}
|
||
else
|
||
{
|
||
DWORD err = GetLastError();
|
||
|
||
if (err != ERROR_NO_TOKEN)
|
||
{
|
||
DBGPRINTF((DBG_CONTEXT, "File %s, Line %d, OpenThreadToken() failed, err = %lu.\n",
|
||
pszFilePath,
|
||
nLineNum));
|
||
}
|
||
}
|
||
|
||
}
|
||
#endif //debug
|