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.
507 lines
14 KiB
507 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
xportcon.cxx
|
|
|
|
Abstract:
|
|
|
|
This module defines the member functions of XPORT_CONNECTIONS
|
|
which keeps track of information about connections for
|
|
different transports.
|
|
|
|
Author:
|
|
|
|
Murali R. Krishnan ( MuraliK ) 07-March-1995
|
|
|
|
Environment:
|
|
|
|
Win32 -- User Mode
|
|
|
|
Project:
|
|
|
|
Internet Services Common DLL
|
|
|
|
Functions Exported:
|
|
|
|
TS_XPORT_CONNECTIONS::Cleanup()
|
|
TS_XPORT_CONNECTIONS::EstablishListenConnections()
|
|
TS_XPORT_CONNECTIONS::StartListenPumps()
|
|
TS_XPORT_CONNECTIONS::StopListenPumps()
|
|
TS_XPORT_CONNECTIONS::GetListenSockets()
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
/************************************************************
|
|
* Include Headers
|
|
************************************************************/
|
|
|
|
# include <tcpdllp.hxx>
|
|
# include "conninfo.hxx"
|
|
|
|
|
|
/************************************************************
|
|
* Functions
|
|
************************************************************/
|
|
|
|
|
|
BOOL
|
|
TS_XPORT_CONNECTIONS::Cleanup( VOID)
|
|
/*++
|
|
|
|
This function cleansup the TS_XPORT_CONNECTIONS object.
|
|
It attempts to stop all the connection threads in each of the
|
|
ConnectionInfo object. Destroys the connection info objects and
|
|
deletes the array of connection info objects maintained.
|
|
|
|
Returns:
|
|
|
|
TRUE if successful and false if there are any errors.
|
|
|
|
--*/
|
|
{
|
|
IF_DEBUG( DLL_CONNECTION) {
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
" Deleting the TS_XPORT_CONNECTIONS object %08x.\n",
|
|
this));
|
|
}
|
|
|
|
if ( m_ppConnectionInfo != NULL) {
|
|
|
|
PTS_CONNECTION_INFO_BASE * ppConnInfo;
|
|
|
|
StopListenPumps();
|
|
// return value is ignored. since all objects will be destroyed.
|
|
|
|
//
|
|
// Delete the individual Connection objects
|
|
//
|
|
|
|
for( ppConnInfo = m_ppConnectionInfo;
|
|
ppConnInfo < m_ppConnectionInfo + m_nXports;
|
|
ppConnInfo++) {
|
|
|
|
if ( *ppConnInfo != NULL) {
|
|
|
|
delete ( *ppConnInfo);
|
|
*ppConnInfo = NULL;
|
|
}
|
|
} // for
|
|
|
|
delete [] m_ppConnectionInfo;
|
|
m_ppConnectionInfo = NULL;
|
|
m_nXports = 0;
|
|
|
|
} // if ( m_ppConnectionInfo)
|
|
|
|
return ( TRUE);
|
|
|
|
} // TS_XPORT_CONNECTIONS::Cleanup()
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
TS_XPORT_CONNECTIONS::EstablishListenConnections(
|
|
IN CONST TCHAR * pszServiceName,
|
|
IN PCSADDR_INFO pcsAddrInfo,
|
|
IN DWORD nAddresses,
|
|
OUT LPDWORD lpdwNumEstablished,
|
|
IN DWORD nListenBacklog,
|
|
IN BOOL fUseAcceptEx )
|
|
/*++
|
|
|
|
This function allocates nAddress TS_CONNECTION_INFO objects, one
|
|
each for one of the protocol addresses specified in the array
|
|
of Protocol addresses ( pcsAddrInfo).
|
|
It also creates listen sockets for each of the connection objects.
|
|
|
|
Arguments:
|
|
|
|
pszServiceName - Name of the service (i.e., W3Svc, GopherSvc etc).
|
|
Should correspond to the name specified to the RNR
|
|
API SetService during setup
|
|
pcsAddrInfo pointer to an array of CSADDR_INFO object, which
|
|
contain the protocol addresses to bind the
|
|
listen sockets to.
|
|
nAddresses number of addresses present in pcsAddrInfo
|
|
lpdwNumEstablished pointer to a DWORD, which on return will contain
|
|
the number of valid listen sockets established.
|
|
nListenBacklog number of backlogs for listen socket.
|
|
fUseAcceptEx TRUE if the connections are coming in on AcceptEx
|
|
(as opposed to thread per socket listens)
|
|
|
|
Returns:
|
|
TRUE on successfully establishing listen sockets for all the addresses
|
|
specified.
|
|
FALSE if there is a failure to create at least one listen socket.
|
|
|
|
The caller can ignore failures in establishing sockets if desired.
|
|
--*/
|
|
{
|
|
DWORD dwError = NO_ERROR;
|
|
|
|
DBG_ASSERT( lpdwNumEstablished != NULL);
|
|
DBG_ASSERT( nAddresses > 0);
|
|
|
|
IF_DEBUG( DLL_CONNECTION) {
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
" EstablishListenSockets( %08x, %ul, %08x) called.\n",
|
|
pcsAddrInfo, nAddresses, lpdwNumEstablished));
|
|
}
|
|
|
|
*lpdwNumEstablished = 0; // Set this to nothing initially
|
|
|
|
DBG_ASSERT( m_ppConnectionInfo == NULL && m_nXports == 0);
|
|
|
|
//
|
|
// Allocate the TS_CONNECTION_INFO objects
|
|
//
|
|
|
|
m_ppConnectionInfo = new PTS_CONNECTION_INFO_BASE[ nAddresses];
|
|
|
|
if ( m_ppConnectionInfo == NULL) {
|
|
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
} else {
|
|
|
|
PTS_CONNECTION_INFO_BASE * ppConnInfo;
|
|
PCSADDR_INFO pcsAddrScan;
|
|
|
|
ZeroMemory( m_ppConnectionInfo,
|
|
nAddresses*sizeof(PTS_CONNECTION_INFO));
|
|
m_nXports = nAddresses;
|
|
|
|
for( ppConnInfo = m_ppConnectionInfo, pcsAddrScan = pcsAddrInfo;
|
|
ppConnInfo < m_ppConnectionInfo + m_nXports;
|
|
ppConnInfo++, pcsAddrScan++) {
|
|
|
|
DBG_ASSERT( pcsAddrScan < pcsAddrInfo + nAddresses);
|
|
|
|
//
|
|
// Create a new PTS_CONNECTION_INFO object
|
|
//
|
|
|
|
if ( fUseAcceptEx ) {
|
|
|
|
*ppConnInfo = new TS_ACCEPTEX_CONNECTION_INFO();
|
|
} else {
|
|
*ppConnInfo = new TS_CONNECTION_INFO();
|
|
}
|
|
|
|
if ( *ppConnInfo == NULL) {
|
|
|
|
//
|
|
// The error is memory error. If there is a memory error,
|
|
// mostly all the subsequent operations will also fail.
|
|
// Indicate the cause of failure and stop creating new objects.
|
|
//
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
"Creating Connection %d failed.",
|
|
ppConnInfo - m_ppConnectionInfo));
|
|
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create a new Listen socket
|
|
//
|
|
|
|
dwError = ( (*ppConnInfo)->
|
|
CreateListenSocket( pcsAddrScan->LocalAddr.lpSockaddr,
|
|
pcsAddrScan->
|
|
LocalAddr.iSockaddrLength,
|
|
pcsAddrScan->iSocketType,
|
|
pcsAddrScan->iProtocol,
|
|
nListenBacklog )
|
|
);
|
|
|
|
if ( dwError == NO_ERROR) {
|
|
|
|
*lpdwNumEstablished += 1;
|
|
|
|
} else {
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
" %08x::CreateListenSocket( Index = %d) failed."
|
|
" Error = %u\n",
|
|
ppConnInfo - m_ppConnectionInfo,
|
|
*ppConnInfo, dwError));
|
|
}
|
|
|
|
} // for
|
|
}
|
|
|
|
if ( dwError ) {
|
|
|
|
SetLastError( dwError);
|
|
}
|
|
|
|
return ( nAddresses == *lpdwNumEstablished);
|
|
|
|
} // TS_XPORT_CONNECTIONS::EstablishListenConnections()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
TS_XPORT_CONNECTIONS::StartListenPumps(
|
|
IN PFN_CONNECT_CALLBACK pfnConnect,
|
|
IN ATQ_COMPLETION pfnConnectEx,
|
|
IN ATQ_COMPLETION pfnIOCompletion,
|
|
IN DWORD cbAcceptExReceiveBuffer,
|
|
IN const CHAR * pszRegParamKey,
|
|
OUT LPDWORD lpdwNumStarted
|
|
) const
|
|
/*++
|
|
|
|
This function starts the listening threads on each of the connections
|
|
established by TS_XPORT_CONNECTIONS::EstablishListenConnections.
|
|
|
|
One listen thread is scheduled per transport in question.
|
|
|
|
Arguments:
|
|
pfnConnect pointer to Function which will be called on a new
|
|
connection being established.
|
|
pfnConnectEx
|
|
Connection callback to use if AcceptEx is available
|
|
|
|
pfnIOCompletion
|
|
Async IO completion routine to use if AcceptEx is available
|
|
|
|
cbAcceptexReceiveBuffer
|
|
count of bytes of buffer to be used for initial receive
|
|
(If 0 no receive buffer isallocated).
|
|
|
|
lpdwNumStarted pointer to DWORD which if not NULL, on return will contain
|
|
the count of threads started.
|
|
A user may choose to stop the threads and connections
|
|
if *lpdwNumStarted < QueryNumTransports()
|
|
since one thread is started per transport.
|
|
|
|
Returns:
|
|
TRUE when connections are established already and all the connection
|
|
threads are started successfully.
|
|
FALSE if even one connection thread could not be started.
|
|
Check the value in *lpdwNumStarted to find the number of threads that
|
|
failed.
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT( lpdwNumStarted != NULL);
|
|
|
|
IF_DEBUG( DLL_CONNECTION) {
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
" StartConnectionPumps() called with Function( %08x).\n",
|
|
pfnConnect));
|
|
}
|
|
|
|
*lpdwNumStarted = 0; // Set this to nothing initially
|
|
|
|
if ( m_ppConnectionInfo != NULL) {
|
|
|
|
PTS_CONNECTION_INFO_BASE * ppConnInfo;
|
|
|
|
for( ppConnInfo = m_ppConnectionInfo;
|
|
ppConnInfo < m_ppConnectionInfo + m_nXports;
|
|
ppConnInfo++) {
|
|
|
|
//
|
|
// start off a thread to watch new connections
|
|
//
|
|
|
|
DBG_ASSERT( *ppConnInfo != NULL);
|
|
|
|
if ( !( *ppConnInfo)->StartConnectionPump( pfnConnect,
|
|
pfnConnectEx,
|
|
pfnIOCompletion,
|
|
cbAcceptExReceiveBuffer,
|
|
pszRegParamKey )
|
|
) {
|
|
|
|
DBG_CODE(
|
|
DWORD err = GetLastError();
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
" StartConnectionPumps( Index = %d) failed."
|
|
" Error =%u\n",
|
|
ppConnInfo - m_ppConnectionInfo, err));
|
|
SetLastError( err);
|
|
);
|
|
|
|
} else {
|
|
|
|
*lpdwNumStarted += 1;
|
|
}
|
|
|
|
} // for
|
|
}
|
|
|
|
return ( m_nXports == *lpdwNumStarted);
|
|
|
|
} // TS_XPORT_CONNECTIONS::StartListenPumps()
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
TS_XPORT_CONNECTIONS::StopListenPumps( VOID ) const
|
|
/*++
|
|
|
|
This function stops all the connection threads that are running.
|
|
|
|
Returns:
|
|
|
|
TRUE on success ( when all the threads had stopped.
|
|
FALSE if there is a failure in at least one of the threads from
|
|
being stopped.
|
|
--*/
|
|
{
|
|
BOOL fStop = TRUE; // Did the connection thread stop?
|
|
|
|
IF_DEBUG( DLL_CONNECTION) {
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
" StopConnectionPumps() called\n"
|
|
));
|
|
}
|
|
|
|
if ( m_ppConnectionInfo != NULL) {
|
|
|
|
PTS_CONNECTION_INFO_BASE * ppConnInfo;
|
|
|
|
for( ppConnInfo = m_ppConnectionInfo;
|
|
ppConnInfo < m_ppConnectionInfo + m_nXports;
|
|
ppConnInfo++) {
|
|
|
|
//
|
|
// stop one thread after another.
|
|
//
|
|
|
|
DBG_ASSERT( *ppConnInfo != NULL);
|
|
|
|
if ( !( *ppConnInfo)->StopConnectionPump( )) {
|
|
|
|
DWORD err = GetLastError();
|
|
//
|
|
// What should we do when we fail ???
|
|
// For now ignore the failure.
|
|
// Ideally the blasting of connection
|
|
// object below, should take care of the scenario.
|
|
// Still it could be tougher to monitor the same.
|
|
// Later we may modify this code.... NYI
|
|
//
|
|
|
|
IF_DEBUG( DLL_CONNECTION) {
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
" Failed to Stop Connection pump of"
|
|
" ConnInfo( %08x)( Error = %u). Ignoring...\n",
|
|
*ppConnInfo, err));
|
|
}
|
|
|
|
|
|
fStop = FALSE;
|
|
}
|
|
} // for
|
|
}
|
|
|
|
return ( fStop);
|
|
} // TS_XPORT_CONNECTIONS::StopListenPumps()
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
TS_XPORT_CONNECTIONS::GetListenSockets(
|
|
IN OUT SOCKET * pSockets,
|
|
IN OUT LPDWORD pnSocketsMax) const
|
|
/*++
|
|
This function collects the socket numbers for the listen sockets established.
|
|
This should be called after EstablishListenConnections() returns success.
|
|
|
|
Arguments:
|
|
pSockets pointer to an array of socket entries to be filled in.
|
|
The maximum number of sockets that can be filled in is
|
|
specified by nSocketsMax.
|
|
pnSocketsMax pointer to DWORD containing the number of socket entries
|
|
during the call. On return contains the number of entries
|
|
copied or required.
|
|
Returns:
|
|
TRUE on success and FALSE on failure.
|
|
Use GetLastError() for further details.
|
|
--*/
|
|
{
|
|
DWORD nConn;
|
|
|
|
if ( pSockets == NULL || pnSocketsMax == NULL || *pnSocketsMax < m_nXports)
|
|
{
|
|
|
|
SetLastError( ERROR_INSUFFICIENT_BUFFER);
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
for( nConn = 0; nConn < m_nXports; nConn++) {
|
|
|
|
pSockets[nConn] = m_ppConnectionInfo[nConn]->QueryListenSocket();
|
|
} // for
|
|
|
|
*pnSocketsMax = m_nXports;
|
|
return (TRUE);
|
|
} // TS_XPORT_CONNECTIONS::GetListenSockets()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# if DBG
|
|
|
|
|
|
VOID
|
|
TS_XPORT_CONNECTIONS::Print( VOID) const
|
|
{
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
" Printing TS_XPORT_CONNECTIONS ( %08x). "
|
|
" Array of connection Info = %08x. Number of Xports = %d\n",
|
|
this, m_ppConnectionInfo, m_nXports));
|
|
|
|
|
|
if ( m_ppConnectionInfo != NULL) {
|
|
|
|
PTS_CONNECTION_INFO_BASE * ppConnInfo;
|
|
|
|
DBG_ASSERT( m_nXports > 0);
|
|
|
|
for( ppConnInfo = m_ppConnectionInfo;
|
|
ppConnInfo < m_ppConnectionInfo + m_nXports;
|
|
ppConnInfo++) {
|
|
|
|
(*ppConnInfo)->Print();
|
|
} // for
|
|
}
|
|
|
|
return;
|
|
|
|
} // TS_XPORT_CONNECTIONS::Print()
|
|
|
|
# endif // DBG
|
|
|
|
|
|
/************************ End of File ***********************/
|