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