Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

474 lines
12 KiB

/**********************************************************************/
/** 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