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.
3160 lines
83 KiB
3160 lines
83 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: Endpoint.cpp
|
|
* Content: DNSerial communications endpoint base class
|
|
*
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 01/20/99 jtk Created
|
|
* 05/12/99 jtk Derived from modem endpoint class
|
|
***************************************************************************/
|
|
|
|
#include "dnmdmi.h"
|
|
|
|
|
|
//**********************************************************************
|
|
// Constant definitions
|
|
//**********************************************************************
|
|
|
|
#define DEFAULT_TAPI_DEV_CAPS_SIZE 1024
|
|
|
|
//**********************************************************************
|
|
// Macro definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Structure definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Variable definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Function prototypes
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Function definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::CopyConnectData - copy data for connect command
|
|
//
|
|
// Entry: Pointer to job information
|
|
//
|
|
// Exit: Nothing
|
|
//
|
|
// Note: Since we've already initialized the local adapter, and we've either
|
|
// completely parsed the host address (or are about to display a dialog
|
|
// asking for more information), the address information doesn't need
|
|
// to be copied.
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::CopyConnectData"
|
|
|
|
void CModemEndpoint::CopyConnectData( const SPCONNECTDATA *const pConnectData )
|
|
{
|
|
DNASSERT( GetType() == ENDPOINT_TYPE_CONNECT );
|
|
DNASSERT( pConnectData != NULL );
|
|
DNASSERT( pConnectData->hCommand != NULL );
|
|
DNASSERT( pConnectData->dwCommandDescriptor != NULL_DESCRIPTOR );
|
|
DNASSERT( m_Flags.fCommandPending == FALSE );
|
|
DNASSERT( m_pCommandHandle == NULL );
|
|
|
|
DBG_CASSERT( sizeof( m_CurrentCommandParameters.ConnectData ) == sizeof( *pConnectData ) );
|
|
memcpy( &m_CurrentCommandParameters.ConnectData, pConnectData, sizeof( m_CurrentCommandParameters.ConnectData ) );
|
|
m_CurrentCommandParameters.ConnectData.pAddressHost = NULL;
|
|
m_CurrentCommandParameters.ConnectData.pAddressDeviceInfo = NULL;
|
|
|
|
m_Flags.fCommandPending = TRUE;
|
|
m_pCommandHandle = static_cast<CModemCommandData*>( m_CurrentCommandParameters.ConnectData.hCommand );
|
|
m_pCommandHandle->SetUserContext( pConnectData->pvContext );
|
|
SetState( ENDPOINT_STATE_ATTEMPTING_CONNECT );
|
|
};
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::ConnectJobCallback - asynchronous callback wrapper from work thread
|
|
//
|
|
// Entry: Pointer to job information
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::ConnectJobCallback"
|
|
|
|
void CModemEndpoint::ConnectJobCallback( THREAD_POOL_JOB *const pDelayedCommand )
|
|
{
|
|
HRESULT hr;
|
|
CModemEndpoint *pThisEndpoint;
|
|
|
|
|
|
DNASSERT( pDelayedCommand != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
pThisEndpoint = static_cast<CModemEndpoint*>( pDelayedCommand->JobData.JobDelayedCommand.pContext );
|
|
|
|
DNASSERT( pThisEndpoint->m_Flags.fCommandPending != FALSE );
|
|
DNASSERT( pThisEndpoint->m_pCommandHandle != NULL );
|
|
DNASSERT( pThisEndpoint->m_CurrentCommandParameters.ConnectData.hCommand == pThisEndpoint->m_pCommandHandle );
|
|
DNASSERT( pThisEndpoint->m_CurrentCommandParameters.ConnectData.dwCommandDescriptor != NULL_DESCRIPTOR );
|
|
|
|
hr = pThisEndpoint->CompleteConnect();
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem completing connect in job callback!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Don't do anything here because it's possible that this object was returned
|
|
// to the pool!!!
|
|
//
|
|
|
|
Exit:
|
|
pThisEndpoint->DecRef();
|
|
return;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::CancelConnectJobCallback - cancel for connect job
|
|
//
|
|
// Entry: Pointer to job information
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::CancelConnectJobCallback"
|
|
|
|
void CModemEndpoint::CancelConnectJobCallback( THREAD_POOL_JOB *const pDelayedCommand )
|
|
{
|
|
CModemEndpoint *pThisEndpoint;
|
|
|
|
|
|
DNASSERT( pDelayedCommand != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
pThisEndpoint = static_cast<CModemEndpoint*>( pDelayedCommand->JobData.JobDelayedCommand.pContext );
|
|
DNASSERT( pThisEndpoint != NULL );
|
|
DNASSERT( pThisEndpoint->m_State == ENDPOINT_STATE_ATTEMPTING_CONNECT );
|
|
|
|
//
|
|
// we're cancelling this command, set the command state to 'cancel'
|
|
//
|
|
DNASSERT( pThisEndpoint->m_pCommandHandle != NULL );
|
|
pThisEndpoint->m_pCommandHandle->Lock();
|
|
DNASSERT( ( pThisEndpoint->m_pCommandHandle->GetState() == COMMAND_STATE_PENDING ) ||
|
|
( pThisEndpoint->m_pCommandHandle->GetState() == COMMAND_STATE_CANCELLING ) );
|
|
pThisEndpoint->m_pCommandHandle->SetState( COMMAND_STATE_CANCELLING );
|
|
pThisEndpoint->m_pCommandHandle->Unlock();
|
|
|
|
pThisEndpoint->Close( DPNERR_USERCANCEL );
|
|
pThisEndpoint->GetSPData()->CloseEndpointHandle( pThisEndpoint );
|
|
pThisEndpoint->DecRef();
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::CompleteConnect - complete connection
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
HRESULT CModemEndpoint::CompleteConnect( void )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
DNASSERT( GetState() == ENDPOINT_STATE_ATTEMPTING_CONNECT );
|
|
DNASSERT( m_Flags.fCommandPending != FALSE );
|
|
DNASSERT( m_pCommandHandle != NULL );
|
|
DNASSERT( m_CurrentCommandParameters.ConnectData.hCommand == m_pCommandHandle );
|
|
DNASSERT( m_CurrentCommandParameters.ConnectData.dwCommandDescriptor != NULL_DESCRIPTOR );
|
|
|
|
|
|
//
|
|
// check for user cancelling command
|
|
//
|
|
m_pCommandHandle->Lock();
|
|
|
|
DNASSERT( m_pCommandHandle->GetType() == COMMAND_TYPE_CONNECT );
|
|
switch ( m_pCommandHandle->GetState() )
|
|
{
|
|
//
|
|
// Command is still pending, don't mark it as uninterruptable because
|
|
// it might be cancelled before indicating the final connect.
|
|
//
|
|
case COMMAND_STATE_PENDING:
|
|
{
|
|
DNASSERT( hr == DPN_OK );
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// command has been cancelled
|
|
//
|
|
case COMMAND_STATE_CANCELLING:
|
|
{
|
|
hr = DPNERR_USERCANCEL;
|
|
DPFX(DPFPREP, 0, "User cancelled connect!" );
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other state
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
m_pCommandHandle->Unlock();
|
|
if ( hr != DPN_OK )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// find a dataport to bind with
|
|
//
|
|
hr = m_pSPData->BindEndpoint( this, GetDeviceID(), GetDeviceContext() );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to bind to data port in connect!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// The connect sequence will complete when the CDataPort indicates that the
|
|
// outbound connection has been established.
|
|
//
|
|
|
|
Exit:
|
|
return hr;
|
|
|
|
Failure:
|
|
Close( hr );
|
|
m_pSPData->CloseEndpointHandle( this );
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::Disconnect - disconnect this endpoint
|
|
//
|
|
// Entry: Old handle value
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::Disconnect"
|
|
|
|
HRESULT CModemEndpoint::Disconnect( const DPNHANDLE hOldEndpointHandle )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPFX(DPFPREP, 6, "(0x%p) Parameters: (0x%p)", this, hOldEndpointHandle );
|
|
|
|
AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
Lock();
|
|
switch ( GetState() )
|
|
{
|
|
//
|
|
// connected endpoint
|
|
//
|
|
case ENDPOINT_STATE_CONNECT_CONNECTED:
|
|
{
|
|
DNASSERT( m_Flags.fCommandPending == FALSE );
|
|
DNASSERT( m_pCommandHandle == NULL );
|
|
|
|
SetState( ENDPOINT_STATE_DISCONNECTING );
|
|
AddRef();
|
|
|
|
//
|
|
// Unlock this endpoint before calling to a higher level. The endpoint
|
|
// has already been labeled as DISCONNECTING so nothing will happen to it.
|
|
//
|
|
Unlock();
|
|
|
|
//
|
|
// Note the old endpoint handle so it can be used in the disconnect
|
|
// indication that will be given just before this endpoint is returned
|
|
// to the pool. Need to release the reference that was added for the
|
|
// connection at this point or the endpoint will never be returned to
|
|
// the pool.
|
|
//
|
|
SetDisconnectIndicationHandle( hOldEndpointHandle );
|
|
DecRef();
|
|
|
|
Close( DPN_OK );
|
|
|
|
//
|
|
// close outstanding reference for this command
|
|
//
|
|
DecCommandRef();
|
|
DecRef();
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// endpoint waiting for the modem to pick up on the other end
|
|
//
|
|
case ENDPOINT_STATE_ATTEMPTING_CONNECT:
|
|
{
|
|
SetState( ENDPOINT_STATE_DISCONNECTING );
|
|
AddRef();
|
|
Unlock();
|
|
|
|
Close( DPNERR_NOCONNECTION );
|
|
|
|
//
|
|
// close outstanding reference for this command
|
|
//
|
|
DecCommandRef();
|
|
DecRef();
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// some other endpoint state
|
|
//
|
|
default:
|
|
{
|
|
hr = DPNERR_INVALIDENDPOINT;
|
|
DPFX(DPFPREP, 0, "Attempted to disconnect endpoint that's not connected!" );
|
|
switch ( m_State )
|
|
{
|
|
case ENDPOINT_STATE_UNINITIALIZED:
|
|
{
|
|
DPFX(DPFPREP, 0, "ENDPOINT_STATE_UNINITIALIZED" );
|
|
break;
|
|
}
|
|
|
|
case ENDPOINT_STATE_ATTEMPTING_LISTEN:
|
|
{
|
|
DPFX(DPFPREP, 0, "ENDPOINT_STATE_ATTEMPTING_LISTEN" );
|
|
break;
|
|
}
|
|
|
|
case ENDPOINT_STATE_ENUM:
|
|
{
|
|
DPFX(DPFPREP, 0, "ENDPOINT_STATE_ENUM" );
|
|
break;
|
|
}
|
|
|
|
case ENDPOINT_STATE_DISCONNECTING:
|
|
{
|
|
DPFX(DPFPREP, 0, "ENDPOINT_STATE_DISCONNECTING" );
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
DNASSERT( FALSE );
|
|
goto Failure;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 6, "(0x%p) Returning [0x%lx]", this, hr );
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
// nothing to do
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::StopEnumCommand - stop an enum job
|
|
//
|
|
// Entry: Error code for completing command
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::StopEnumCommand"
|
|
|
|
void CModemEndpoint::StopEnumCommand( const HRESULT hCommandResult )
|
|
{
|
|
Lock();
|
|
DNASSERT( GetState() == ENDPOINT_STATE_DISCONNECTING );
|
|
if ( m_hActiveDialogHandle != NULL )
|
|
{
|
|
StopSettingsDialog( m_hActiveDialogHandle );
|
|
Unlock();
|
|
}
|
|
else
|
|
{
|
|
BOOL fStoppedJob;
|
|
|
|
|
|
Unlock();
|
|
fStoppedJob = m_pSPData->GetThreadPool()->StopTimerJob( m_pCommandHandle, hCommandResult );
|
|
if ( ! fStoppedJob )
|
|
{
|
|
DPFX(DPFPREP, 1, "Unable to stop timer job (context 0x%p) manually setting result to 0x%lx.",
|
|
m_pCommandHandle, hCommandResult);
|
|
|
|
//
|
|
// Set the command result so it can be returned when the endpoint
|
|
// reference count is zero.
|
|
//
|
|
SetCommandResult( hCommandResult );
|
|
}
|
|
}
|
|
|
|
m_pSPData->CloseEndpointHandle( this );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::SetState - set state of this endpoint
|
|
//
|
|
// Entry: New state
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::SetState"
|
|
|
|
void CModemEndpoint::SetState( const ENDPOINT_STATE EndpointState )
|
|
{
|
|
DNASSERT( ( GetState() == ENDPOINT_STATE_UNINITIALIZED ) ||
|
|
( EndpointState == ENDPOINT_STATE_UNINITIALIZED ) ||
|
|
( ( m_State== ENDPOINT_STATE_ATTEMPTING_LISTEN ) && ( EndpointState == ENDPOINT_STATE_LISTENING ) ) ||
|
|
( ( m_State == ENDPOINT_STATE_LISTENING ) && ( EndpointState == ENDPOINT_STATE_DISCONNECTING ) ) ||
|
|
( ( m_State == ENDPOINT_STATE_ATTEMPTING_ENUM ) && ( EndpointState == ENDPOINT_STATE_ENUM ) ) ||
|
|
( ( m_State == ENDPOINT_STATE_ENUM ) && ( EndpointState == ENDPOINT_STATE_DISCONNECTING ) ) ||
|
|
( ( m_State == ENDPOINT_STATE_ATTEMPTING_ENUM ) && ( EndpointState == ENDPOINT_STATE_DISCONNECTING ) ) ||
|
|
( ( m_State == ENDPOINT_STATE_ATTEMPTING_CONNECT ) && ( EndpointState == ENDPOINT_STATE_DISCONNECTING ) ) ||
|
|
( ( m_State == ENDPOINT_STATE_CONNECT_CONNECTED ) && ( EndpointState == ENDPOINT_STATE_DISCONNECTING ) ) );
|
|
m_State = EndpointState;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::CopyListenData - copy data for listen command
|
|
//
|
|
// Entry: Pointer to job information
|
|
//
|
|
// Exit: Nothing
|
|
//
|
|
// Note: Since we've already initialized the local adapter, and we've either
|
|
// completely parsed the host address (or are about to display a dialog
|
|
// asking for more information), the address information doesn't need
|
|
// to be copied.
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::CopyListenData"
|
|
|
|
void CModemEndpoint::CopyListenData( const SPLISTENDATA *const pListenData )
|
|
{
|
|
DNASSERT( GetType() == ENDPOINT_TYPE_LISTEN );
|
|
DNASSERT( pListenData != NULL );
|
|
DNASSERT( pListenData->hCommand != NULL );
|
|
DNASSERT( pListenData->dwCommandDescriptor != NULL_DESCRIPTOR );
|
|
DNASSERT( m_Flags.fCommandPending == FALSE );
|
|
DNASSERT( m_pCommandHandle == NULL );
|
|
DNASSERT( m_Flags.fListenStatusNeedsToBeIndicated == FALSE );
|
|
|
|
DBG_CASSERT( sizeof( m_CurrentCommandParameters.ListenData ) == sizeof( *pListenData ) );
|
|
memcpy( &m_CurrentCommandParameters.ListenData, pListenData, sizeof( m_CurrentCommandParameters.ListenData ) );
|
|
DEBUG_ONLY( m_CurrentCommandParameters.ListenData.pAddressDeviceInfo = NULL );
|
|
|
|
m_Flags.fCommandPending = TRUE;
|
|
m_Flags.fListenStatusNeedsToBeIndicated = TRUE;
|
|
m_pCommandHandle = static_cast<CModemCommandData*>( m_CurrentCommandParameters.ListenData.hCommand );
|
|
m_pCommandHandle->SetUserContext( pListenData->pvContext );
|
|
|
|
SetState( ENDPOINT_STATE_ATTEMPTING_LISTEN );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::ListenJobCallback - asynchronous callback wrapper for work thread
|
|
//
|
|
// Entry: Pointer to job information
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::ListenJobCallback"
|
|
|
|
void CModemEndpoint::ListenJobCallback( THREAD_POOL_JOB *const pDelayedCommand )
|
|
{
|
|
HRESULT hr;
|
|
CModemEndpoint *pThisEndpoint;
|
|
|
|
|
|
DNASSERT( pDelayedCommand != NULL );
|
|
|
|
// initialize
|
|
pThisEndpoint = static_cast<CModemEndpoint*>( pDelayedCommand->JobData.JobDelayedCommand.pContext );
|
|
|
|
DNASSERT( pThisEndpoint->GetState() == ENDPOINT_STATE_ATTEMPTING_LISTEN );
|
|
DNASSERT( pThisEndpoint->m_Flags.fCommandPending != NULL );
|
|
DNASSERT( pThisEndpoint->m_pCommandHandle != NULL );
|
|
DNASSERT( pThisEndpoint->m_CurrentCommandParameters.ListenData.hCommand == pThisEndpoint->m_pCommandHandle );
|
|
DNASSERT( pThisEndpoint->m_CurrentCommandParameters.ListenData.dwCommandDescriptor != NULL_DESCRIPTOR );
|
|
|
|
hr = pThisEndpoint->CompleteListen();
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem completing listen in job callback!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
pThisEndpoint->DecRef();
|
|
|
|
//
|
|
// Don't do anything here because it's possible that this object was returned
|
|
// to the pool!!!!
|
|
//
|
|
|
|
return;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::CancelListenJobCallback - cancel for listen job
|
|
//
|
|
// Entry: Pointer to job information
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::CancelListenJobCallback"
|
|
|
|
void CModemEndpoint::CancelListenJobCallback( THREAD_POOL_JOB *const pDelayedCommand )
|
|
{
|
|
CModemEndpoint *pThisEndpoint;
|
|
|
|
|
|
DNASSERT( pDelayedCommand != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
pThisEndpoint = static_cast<CModemEndpoint*>( pDelayedCommand->JobData.JobDelayedCommand.pContext );
|
|
DNASSERT( pThisEndpoint != NULL );
|
|
DNASSERT( pThisEndpoint->m_State == ENDPOINT_STATE_ATTEMPTING_LISTEN );
|
|
|
|
//
|
|
// we're cancelling this command, set the command state to 'cancel'
|
|
//
|
|
DNASSERT( pThisEndpoint->m_pCommandHandle != NULL );
|
|
pThisEndpoint->m_pCommandHandle->Lock();
|
|
DNASSERT( ( pThisEndpoint->m_pCommandHandle->GetState() == COMMAND_STATE_PENDING ) ||
|
|
( pThisEndpoint->m_pCommandHandle->GetState() == COMMAND_STATE_CANCELLING ) );
|
|
pThisEndpoint->m_pCommandHandle->SetState( COMMAND_STATE_CANCELLING );
|
|
pThisEndpoint->m_pCommandHandle->Unlock();
|
|
|
|
pThisEndpoint->Close( DPNERR_USERCANCEL );
|
|
pThisEndpoint->GetSPData()->CloseEndpointHandle( pThisEndpoint );
|
|
pThisEndpoint->DecRef();
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::CompleteListen - complete listen process
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
HRESULT CModemEndpoint::CompleteListen( void )
|
|
{
|
|
HRESULT hr;
|
|
BOOL fEndpointLocked;
|
|
SPIE_LISTENSTATUS ListenStatus;
|
|
HRESULT hTempResult;
|
|
|
|
|
|
DNASSERT( GetState() == ENDPOINT_STATE_ATTEMPTING_LISTEN );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
fEndpointLocked = FALSE;
|
|
|
|
DNASSERT( GetState() == ENDPOINT_STATE_ATTEMPTING_LISTEN );
|
|
DNASSERT( m_Flags.fCommandPending != FALSE );
|
|
DNASSERT( m_pCommandHandle != NULL );
|
|
DNASSERT( m_pCommandHandle->GetEndpoint() == this );
|
|
DNASSERT( m_CurrentCommandParameters.ListenData.hCommand == m_pCommandHandle );
|
|
DNASSERT( m_CurrentCommandParameters.ListenData.dwCommandDescriptor != NULL_DESCRIPTOR );
|
|
|
|
|
|
//
|
|
// check for user cancelling command
|
|
//
|
|
Lock();
|
|
fEndpointLocked = TRUE;
|
|
m_pCommandHandle->Lock();
|
|
|
|
DNASSERT( m_pCommandHandle->GetType() == COMMAND_TYPE_LISTEN );
|
|
switch ( m_pCommandHandle->GetState() )
|
|
{
|
|
//
|
|
// command is pending, mark as in-progress and cancellable
|
|
//
|
|
case COMMAND_STATE_PENDING:
|
|
{
|
|
m_pCommandHandle->SetState( COMMAND_STATE_INPROGRESS );
|
|
DNASSERT( hr == DPN_OK );
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// command has been cancelled
|
|
//
|
|
case COMMAND_STATE_CANCELLING:
|
|
{
|
|
hr = DPNERR_USERCANCEL;
|
|
DPFX(DPFPREP, 0, "User cancelled listen!" );
|
|
|
|
Unlock();
|
|
fEndpointLocked = FALSE;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other state
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
Unlock();
|
|
fEndpointLocked = FALSE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
m_pCommandHandle->Unlock();
|
|
if ( hr != DPN_OK )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// find a dataport to bind with
|
|
//
|
|
hr = m_pSPData->BindEndpoint( this, GetDeviceID(), GetDeviceContext() );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to bind endpoint for serial listen!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// We're done and everyone's happy. Listen commands never
|
|
// complete until cancelled by the user. Don't complete
|
|
// the command at this point.
|
|
//
|
|
SetState( ENDPOINT_STATE_LISTENING );
|
|
DNASSERT( m_Flags.fCommandPending != FALSE );
|
|
DNASSERT( m_pCommandHandle != NULL );
|
|
|
|
Exit:
|
|
if ( fEndpointLocked != FALSE )
|
|
{
|
|
Unlock();
|
|
fEndpointLocked = FALSE;
|
|
}
|
|
|
|
if ( m_Flags.fListenStatusNeedsToBeIndicated != FALSE )
|
|
{
|
|
m_Flags.fListenStatusNeedsToBeIndicated = FALSE;
|
|
memset( &ListenStatus, 0x00, sizeof( ListenStatus ) );
|
|
ListenStatus.hResult = hr;
|
|
DNASSERT( m_pCommandHandle == m_CurrentCommandParameters.ListenData.hCommand );
|
|
ListenStatus.hCommand = m_CurrentCommandParameters.ListenData.hCommand;
|
|
ListenStatus.pUserContext = m_CurrentCommandParameters.ListenData.pvContext;
|
|
ListenStatus.hEndpoint = (HANDLE)(DWORD_PTR)GetHandle();
|
|
DeviceIDToGuid( &ListenStatus.ListenAdapter, GetDeviceID(), GetEncryptionGuid() );
|
|
|
|
hTempResult = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to DPlay callbacks
|
|
SPEV_LISTENSTATUS, // data type
|
|
&ListenStatus // pointer to data
|
|
);
|
|
DNASSERT( hTempResult == DPN_OK );
|
|
}
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
//
|
|
// we've failed to complete the listen, clean up and return this
|
|
// endpoint to the pool
|
|
//
|
|
Close( hr );
|
|
|
|
m_pSPData->CloseEndpointHandle( this );
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::CopyEnumQueryData - copy data for enum query command
|
|
//
|
|
// Entry: Pointer to command data
|
|
//
|
|
// Exit: Nothing
|
|
//
|
|
// Note: Since we've already initialized the local adapter, and we've either
|
|
// completely parsed the host address (or are about to display a dialog
|
|
// asking for more information), the address information doesn't need
|
|
// to be copied.
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::CopyEnumQueryData"
|
|
|
|
void CModemEndpoint::CopyEnumQueryData( const SPENUMQUERYDATA *const pEnumQueryData )
|
|
{
|
|
DNASSERT( GetType() == ENDPOINT_TYPE_ENUM );
|
|
DNASSERT( pEnumQueryData != NULL );
|
|
DNASSERT( pEnumQueryData->hCommand != NULL );
|
|
DNASSERT( pEnumQueryData->dwCommandDescriptor != NULL_DESCRIPTOR );
|
|
DNASSERT( m_Flags.fCommandPending == FALSE );
|
|
DNASSERT( m_pCommandHandle == NULL );
|
|
|
|
DBG_CASSERT( sizeof( m_CurrentCommandParameters.EnumQueryData ) == sizeof( *pEnumQueryData ) );
|
|
memcpy( &m_CurrentCommandParameters.EnumQueryData, pEnumQueryData, sizeof( m_CurrentCommandParameters.EnumQueryData ) );
|
|
m_CurrentCommandParameters.EnumQueryData.pAddressHost = NULL;
|
|
m_CurrentCommandParameters.EnumQueryData.pAddressDeviceInfo = NULL;
|
|
|
|
m_Flags.fCommandPending = TRUE;
|
|
m_pCommandHandle = static_cast<CModemCommandData*>( m_CurrentCommandParameters.EnumQueryData.hCommand );
|
|
m_pCommandHandle->SetUserContext( pEnumQueryData->pvContext );
|
|
SetState( ENDPOINT_STATE_ATTEMPTING_ENUM );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::EnumQueryJobCallback - asynchronous callback wrapper for work thread
|
|
//
|
|
// Entry: Pointer to job information
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::EnumQueryJobCallback"
|
|
|
|
void CModemEndpoint::EnumQueryJobCallback( THREAD_POOL_JOB *const pDelayedCommand )
|
|
{
|
|
HRESULT hr;
|
|
CModemEndpoint *pThisEndpoint;
|
|
|
|
|
|
DNASSERT( pDelayedCommand != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
pThisEndpoint = static_cast<CModemEndpoint*>( pDelayedCommand->JobData.JobDelayedCommand.pContext );
|
|
|
|
DNASSERT( pThisEndpoint->m_Flags.fCommandPending != FALSE );
|
|
DNASSERT( pThisEndpoint->m_pCommandHandle != NULL );
|
|
DNASSERT( pThisEndpoint->m_CurrentCommandParameters.EnumQueryData.hCommand == pThisEndpoint->m_pCommandHandle );
|
|
DNASSERT( pThisEndpoint->m_CurrentCommandParameters.EnumQueryData.dwCommandDescriptor != NULL_DESCRIPTOR );
|
|
|
|
hr = pThisEndpoint->CompleteEnumQuery();
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem completing enum query in job callback!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Don't do anything here because it's possible that this object was returned to the pool!!!!
|
|
//
|
|
Exit:
|
|
pThisEndpoint->DecRef();
|
|
|
|
return;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::CancelEnumQueryJobCallback - cancel for enum query job
|
|
//
|
|
// Entry: Pointer to job information
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::CancelEnumQueryJobCallback"
|
|
|
|
void CModemEndpoint::CancelEnumQueryJobCallback( THREAD_POOL_JOB *const pDelayedCommand )
|
|
{
|
|
CModemEndpoint *pThisEndpoint;
|
|
|
|
|
|
DNASSERT( pDelayedCommand != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
pThisEndpoint = static_cast<CModemEndpoint*>( pDelayedCommand->JobData.JobDelayedCommand.pContext );
|
|
DNASSERT( pThisEndpoint != NULL );
|
|
DNASSERT( pThisEndpoint->m_State == ENDPOINT_STATE_ATTEMPTING_ENUM );
|
|
|
|
//
|
|
// we're cancelling this command, set the command state to 'cancel'
|
|
//
|
|
DNASSERT( pThisEndpoint->m_pCommandHandle != NULL );
|
|
pThisEndpoint->m_pCommandHandle->Lock();
|
|
DNASSERT( ( pThisEndpoint->m_pCommandHandle->GetState() == COMMAND_STATE_INPROGRESS ) ||
|
|
( pThisEndpoint->m_pCommandHandle->GetState() == COMMAND_STATE_CANCELLING ) );
|
|
pThisEndpoint->m_pCommandHandle->SetState( COMMAND_STATE_CANCELLING );
|
|
pThisEndpoint->m_pCommandHandle->Unlock();
|
|
|
|
pThisEndpoint->Close( DPNERR_USERCANCEL );
|
|
pThisEndpoint->GetSPData()->CloseEndpointHandle( pThisEndpoint );
|
|
pThisEndpoint->DecRef();
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::CompleteEnumQuery - complete enum query process
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
HRESULT CModemEndpoint::CompleteEnumQuery( void )
|
|
{
|
|
HRESULT hr;
|
|
BOOL fEndpointLocked;
|
|
BOOL fEndpointBound;
|
|
CDataPort *pDataPort;
|
|
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
fEndpointLocked = FALSE;
|
|
fEndpointBound = FALSE;
|
|
pDataPort = NULL;
|
|
|
|
DNASSERT( GetState() == ENDPOINT_STATE_ATTEMPTING_ENUM );
|
|
DNASSERT( m_Flags.fCommandPending != FALSE );
|
|
DNASSERT( m_pCommandHandle != NULL );
|
|
DNASSERT( m_pCommandHandle->GetEndpoint() == this );
|
|
DNASSERT( m_CurrentCommandParameters.EnumQueryData.hCommand == m_pCommandHandle );
|
|
DNASSERT( m_CurrentCommandParameters.EnumQueryData.dwCommandDescriptor != NULL_DESCRIPTOR );
|
|
|
|
//
|
|
// check for user cancelling command
|
|
//
|
|
Lock();
|
|
fEndpointLocked = TRUE;
|
|
m_pCommandHandle->Lock();
|
|
|
|
DNASSERT( m_pCommandHandle->GetType() == COMMAND_TYPE_ENUM_QUERY );
|
|
switch ( m_pCommandHandle->GetState() )
|
|
{
|
|
//
|
|
// command is still in progress
|
|
//
|
|
case COMMAND_STATE_INPROGRESS:
|
|
{
|
|
DNASSERT( hr == DPN_OK );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// command has been cancelled
|
|
//
|
|
case COMMAND_STATE_CANCELLING:
|
|
{
|
|
hr = DPNERR_USERCANCEL;
|
|
DPFX(DPFPREP, 0, "User cancelled enum query!" );
|
|
Unlock();
|
|
fEndpointLocked = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other state
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
Unlock();
|
|
fEndpointLocked = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
m_pCommandHandle->Unlock();
|
|
if ( hr != DPN_OK )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// find a dataport to bind with
|
|
//
|
|
hr = m_pSPData->BindEndpoint( this, GetDeviceID(), GetDeviceContext() );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to bind to data port for EnumQuery!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
fEndpointBound = TRUE;
|
|
|
|
SetState( ENDPOINT_STATE_ENUM );
|
|
|
|
Exit:
|
|
if ( fEndpointLocked != FALSE )
|
|
{
|
|
Unlock();
|
|
fEndpointLocked = FALSE;
|
|
}
|
|
|
|
if ( pDataPort != NULL )
|
|
{
|
|
pDataPort->EndpointDecRef();
|
|
pDataPort = NULL;
|
|
}
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
if ( fEndpointBound != FALSE )
|
|
{
|
|
DNASSERT( GetDataPort() != NULL );
|
|
m_pSPData->UnbindEndpoint( this, GetType() );
|
|
fEndpointBound = FALSE;
|
|
}
|
|
|
|
if ( fEndpointLocked != FALSE )
|
|
{
|
|
Unlock();
|
|
fEndpointLocked = FALSE;
|
|
}
|
|
|
|
Close( hr );
|
|
m_pSPData->CloseEndpointHandle( this );
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::OutgoingConnectionEstablished - an outgoing connection was established
|
|
//
|
|
// Entry: Command result (DPN_OK == connection succeeded)
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
void CModemEndpoint::OutgoingConnectionEstablished( const HRESULT hCommandResult )
|
|
{
|
|
HRESULT hr;
|
|
CModemCommandData *pCommandData;
|
|
|
|
|
|
DPFX(DPFPREP, 6, "(0x%p) Parameters: (0x%lx)", this, hCommandResult);
|
|
|
|
pCommandData = GetCommandData();
|
|
DNASSERT( pCommandData != NULL );
|
|
|
|
//
|
|
// check for successful connection
|
|
//
|
|
if ( hCommandResult != DPN_OK )
|
|
{
|
|
DNASSERT( FALSE );
|
|
hr = hCommandResult;
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// determine which type of outgoing connection this is and complete it
|
|
//
|
|
switch ( GetType() )
|
|
{
|
|
case ENDPOINT_TYPE_CONNECT:
|
|
{
|
|
BOOL fProceed;
|
|
|
|
|
|
fProceed = TRUE;
|
|
pCommandData->Lock();
|
|
switch ( pCommandData->GetState() )
|
|
{
|
|
case COMMAND_STATE_PENDING:
|
|
{
|
|
pCommandData->SetState( COMMAND_STATE_INPROGRESS_CANNOT_CANCEL );
|
|
DNASSERT( fProceed != FALSE );
|
|
break;
|
|
}
|
|
|
|
case COMMAND_STATE_CANCELLING:
|
|
{
|
|
fProceed = FALSE;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
pCommandData->Unlock();
|
|
|
|
if ( fProceed != FALSE )
|
|
{
|
|
SPIE_CONNECT ConnectIndicationData;
|
|
|
|
|
|
//
|
|
// Inform user of connection. Assume that the user will accept
|
|
// and everything will succeed so we can set the user context
|
|
// for the endpoint. If the connection fails, clear the user
|
|
// endpoint context.
|
|
//
|
|
memset( &ConnectIndicationData, 0x00, sizeof( ConnectIndicationData ) );
|
|
DBG_CASSERT( sizeof( ConnectIndicationData.hEndpoint ) == sizeof( HANDLE ) );
|
|
ConnectIndicationData.hEndpoint = (HANDLE)(DWORD_PTR)GetHandle();
|
|
ConnectIndicationData.pCommandContext = m_CurrentCommandParameters.ConnectData.pvContext;
|
|
SetUserEndpointContext( ConnectIndicationData.pEndpointContext );
|
|
|
|
hr = SignalConnect( &ConnectIndicationData );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DNASSERT( hr == DPNERR_ABORTED );
|
|
DPFX(DPFPREP, 0, "User refused connect in CompleteConnect!" );
|
|
DisplayDNError( 0, hr );
|
|
SetUserEndpointContext( NULL );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// we're done and everyone's happy, complete the command, this
|
|
// will clear all of our internal command data
|
|
//
|
|
CompletePendingCommand( hr );
|
|
DNASSERT( m_Flags.fCommandPending == FALSE );
|
|
DNASSERT( m_pCommandHandle == NULL );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ENDPOINT_TYPE_ENUM:
|
|
{
|
|
UINT_PTR uRetryCount;
|
|
BOOL fRetryForever;
|
|
DWORD dwRetryInterval;
|
|
BOOL fWaitForever;
|
|
DWORD dwIdleTimeout;
|
|
|
|
|
|
|
|
//
|
|
// check retry to determine if we're enumerating forever
|
|
//
|
|
switch ( m_CurrentCommandParameters.EnumQueryData.dwRetryCount )
|
|
{
|
|
//
|
|
// let SP determine retry count
|
|
//
|
|
case 0:
|
|
{
|
|
uRetryCount = DEFAULT_ENUM_RETRY_COUNT;
|
|
fRetryForever = FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// retry forever
|
|
//
|
|
case INFINITE:
|
|
{
|
|
uRetryCount = 1;
|
|
fRetryForever = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other
|
|
//
|
|
default:
|
|
{
|
|
uRetryCount = m_CurrentCommandParameters.EnumQueryData.dwRetryCount;
|
|
fRetryForever = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// check interval for default
|
|
//
|
|
if ( m_CurrentCommandParameters.EnumQueryData.dwRetryInterval == 0 )
|
|
{
|
|
dwRetryInterval = DEFAULT_ENUM_RETRY_INTERVAL;
|
|
}
|
|
else
|
|
{
|
|
dwRetryInterval = m_CurrentCommandParameters.EnumQueryData.dwRetryInterval;
|
|
}
|
|
|
|
//
|
|
// check timeout to see if we're waiting forever
|
|
//
|
|
switch ( m_CurrentCommandParameters.EnumQueryData.dwTimeout )
|
|
{
|
|
//
|
|
// wait forever
|
|
//
|
|
case INFINITE:
|
|
{
|
|
fWaitForever = TRUE;
|
|
dwIdleTimeout = -1;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// possible default
|
|
//
|
|
case 0:
|
|
{
|
|
fWaitForever = FALSE;
|
|
dwIdleTimeout = DEFAULT_ENUM_TIMEOUT;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other
|
|
//
|
|
default:
|
|
{
|
|
fWaitForever = FALSE;
|
|
dwIdleTimeout = m_CurrentCommandParameters.EnumQueryData.dwTimeout;
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_dwEnumSendIndex = 0;
|
|
memset( m_dwEnumSendTimes, 0, sizeof( m_dwEnumSendTimes ) );
|
|
|
|
pCommandData->Lock();
|
|
if ( pCommandData->GetState() == COMMAND_STATE_INPROGRESS )
|
|
{
|
|
//
|
|
// add a reference for the timer job, must be cleaned on failure
|
|
//
|
|
AddRef();
|
|
|
|
hr = m_pSPData->GetThreadPool()->SubmitTimerJob( uRetryCount, // number of times to retry command
|
|
fRetryForever, // retry forever
|
|
dwRetryInterval, // retry interval
|
|
fWaitForever, // wait forever after all enums sent
|
|
dwIdleTimeout, // timeout to wait after command complete
|
|
CModemEndpoint::EnumTimerCallback, // function called when timer event fires
|
|
CModemEndpoint::EnumCompleteWrapper, // function called when timer event expires
|
|
m_pCommandHandle ); // context
|
|
if ( hr != DPN_OK )
|
|
{
|
|
pCommandData->Unlock();
|
|
DPFX(DPFPREP, 0, "Failed to spool enum job on work thread!" );
|
|
DisplayDNError( 0, hr );
|
|
DecRef();
|
|
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// if everything is a success, we should still have an active command
|
|
//
|
|
DNASSERT( m_Flags.fCommandPending != FALSE );
|
|
DNASSERT( m_pCommandHandle != NULL );
|
|
}
|
|
|
|
pCommandData->Unlock();
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 6, "(0x%p) Returning", this);
|
|
|
|
return;
|
|
|
|
Failure:
|
|
DNASSERT( FALSE );
|
|
Close( hr );
|
|
m_pSPData->CloseEndpointHandle( this );
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::EnumCompleteWrapper - this enum has expired
|
|
//
|
|
// Entry: Error code
|
|
// Context (command pointer)
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::EnumCompleteWrapper"
|
|
|
|
void CModemEndpoint::EnumCompleteWrapper( const HRESULT hResult, void *const pContext )
|
|
{
|
|
CModemCommandData *pCommandData;
|
|
|
|
|
|
DNASSERT( pContext != NULL );
|
|
pCommandData = static_cast<CModemCommandData*>( pContext );
|
|
pCommandData->GetEndpoint()->EnumComplete( hResult );
|
|
pCommandData->GetEndpoint()->DecRef();
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::EnumTimerCallback - timed callback to send enum data
|
|
//
|
|
// Entry: Pointer to context
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::EnumTimerCallback"
|
|
|
|
void CModemEndpoint::EnumTimerCallback( void *const pContext )
|
|
{
|
|
CModemCommandData *pCommandData;
|
|
CModemEndpoint *pThisObject;
|
|
CModemWriteIOData *pWriteData;
|
|
|
|
|
|
DNASSERT( pContext != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
pCommandData = static_cast<CModemCommandData*>( pContext );
|
|
pThisObject = pCommandData->GetEndpoint();
|
|
pWriteData = NULL;
|
|
|
|
pThisObject->Lock();
|
|
|
|
switch ( pThisObject->m_State )
|
|
{
|
|
//
|
|
// we're enumerating (as expected)
|
|
//
|
|
case ENDPOINT_STATE_ENUM:
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// this endpoint is disconnecting, bail!
|
|
//
|
|
case ENDPOINT_STATE_DISCONNECTING:
|
|
{
|
|
pThisObject->Unlock();
|
|
goto Exit;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// there's a problem
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
pThisObject->Unlock();
|
|
|
|
//
|
|
// attempt to get a new IO buffer for this endpoint
|
|
//
|
|
pWriteData = pThisObject->m_pSPData->GetThreadPool()->CreateWriteIOData();
|
|
if ( pWriteData == NULL )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to get write data for an enum!" );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Set all data for the write. Since this is an enum and we
|
|
// don't care about the outgoing data so don't send an indication
|
|
// when it completes.
|
|
//
|
|
DNASSERT( pThisObject->m_Flags.fCommandPending != FALSE );
|
|
DNASSERT( pThisObject->m_pCommandHandle != NULL );
|
|
DNASSERT( pThisObject->GetState() == ENDPOINT_STATE_ENUM );
|
|
pWriteData->m_pBuffers = pThisObject->m_CurrentCommandParameters.EnumQueryData.pBuffers;
|
|
pWriteData->m_uBufferCount = pThisObject->m_CurrentCommandParameters.EnumQueryData.dwBufferCount;
|
|
pWriteData->m_SendCompleteAction = SEND_COMPLETE_ACTION_NONE;
|
|
|
|
DNASSERT( pWriteData->m_pCommand != NULL );
|
|
DNASSERT( pWriteData->m_pCommand->GetUserContext() == NULL );
|
|
pWriteData->m_pCommand->SetState( COMMAND_STATE_PENDING );
|
|
|
|
DNASSERT( pThisObject->GetDataPort() != NULL );
|
|
pThisObject->m_dwEnumSendIndex++;
|
|
pThisObject->m_dwEnumSendTimes[ pThisObject->m_dwEnumSendIndex & ENUM_RTT_MASK ] = GETTIMESTAMP();
|
|
pThisObject->m_pDataPort->SendEnumQueryData( pWriteData,
|
|
( pThisObject->m_dwEnumSendIndex & ENUM_RTT_MASK ) );
|
|
|
|
Exit:
|
|
return;
|
|
|
|
Failure:
|
|
// nothing to clean up at this time
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::SignalConnect - note connection
|
|
//
|
|
// Entry: Pointer to connect data
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::SignalConnect"
|
|
|
|
HRESULT CModemEndpoint::SignalConnect( SPIE_CONNECT *const pConnectData )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DNASSERT( pConnectData != NULL );
|
|
DNASSERT( pConnectData->hEndpoint == (HANDLE)(DWORD_PTR)GetHandle() );
|
|
AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
switch ( m_State )
|
|
{
|
|
//
|
|
// disconnecting, nothing to do
|
|
//
|
|
case ENDPOINT_STATE_DISCONNECTING:
|
|
{
|
|
goto Exit;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// we're attempting to connect
|
|
//
|
|
case ENDPOINT_STATE_ATTEMPTING_CONNECT:
|
|
{
|
|
DNASSERT( m_Flags.fConnectIndicated == FALSE );
|
|
hr = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // interface
|
|
SPEV_CONNECT, // event type
|
|
pConnectData // pointer to data
|
|
);
|
|
switch ( hr )
|
|
{
|
|
//
|
|
// connection accepted
|
|
//
|
|
case DPN_OK:
|
|
{
|
|
//
|
|
// note that we're connected
|
|
//
|
|
SetUserEndpointContext( pConnectData->pEndpointContext );
|
|
m_Flags.fConnectIndicated = TRUE;
|
|
m_State = ENDPOINT_STATE_CONNECT_CONNECTED;
|
|
AddRef();
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// user aborted connection attempt, nothing to do, just pass
|
|
// the result on
|
|
//
|
|
case DPNERR_ABORTED:
|
|
{
|
|
DNASSERT( GetUserEndpointContext() == NULL );
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// states where we shouldn't be getting called
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::SignalDisconnect - note disconnection
|
|
//
|
|
// Entry: Old endpoint handle
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::SignalDisconnect"
|
|
|
|
void CModemEndpoint::SignalDisconnect( const DPNHANDLE hOldEndpointHandle )
|
|
{
|
|
HRESULT hr;
|
|
SPIE_DISCONNECT DisconnectData;
|
|
|
|
|
|
// tell user that we're disconnecting
|
|
DNASSERT( m_Flags.fConnectIndicated != FALSE );
|
|
DBG_CASSERT( sizeof( DisconnectData.hEndpoint ) == sizeof( this ) );
|
|
DisconnectData.hEndpoint = (HANDLE)(DWORD_PTR)hOldEndpointHandle;
|
|
DisconnectData.pEndpointContext = GetUserEndpointContext();
|
|
m_Flags.fConnectIndicated = FALSE;
|
|
DNASSERT( m_pSPData != NULL );
|
|
hr = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // callback interface
|
|
SPEV_DISCONNECT, // event type
|
|
&DisconnectData // pointer to data
|
|
);
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem with SignalDisconnect!" );
|
|
DisplayDNError( 0, hr );
|
|
DNASSERT( FALSE );
|
|
}
|
|
|
|
SetDisconnectIndicationHandle( 0 );
|
|
|
|
return;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::CleanUpCommand - perform cleanup now that the command on this
|
|
// endpoint is essentially complete. There may be outstanding references,
|
|
// but nobody will be asking the endpoint to do anything else.
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
void CModemEndpoint::CleanUpCommand( void )
|
|
{
|
|
DPFX(DPFPREP, 6, "(0x%p) Enter", this );
|
|
|
|
|
|
if ( GetDataPort() != NULL )
|
|
{
|
|
DNASSERT( m_pSPData != NULL );
|
|
m_pSPData->UnbindEndpoint( this, GetType() );
|
|
}
|
|
|
|
//
|
|
// If we're bailing here it's because the UI didn't complete. There is no
|
|
// adapter guid to return because one may have not been specified. Return
|
|
// a bogus endpoint handle so it can't be queried for addressing data.
|
|
//
|
|
if ( m_Flags.fListenStatusNeedsToBeIndicated != FALSE )
|
|
{
|
|
HRESULT hTempResult;
|
|
SPIE_LISTENSTATUS ListenStatus;
|
|
|
|
|
|
memset( &ListenStatus, 0x00, sizeof( ListenStatus ) );
|
|
ListenStatus.hCommand = m_pCommandHandle;
|
|
ListenStatus.hEndpoint = 0;
|
|
ListenStatus.hResult = CommandResult();
|
|
memset( &ListenStatus.ListenAdapter, 0x00, sizeof( ListenStatus.ListenAdapter ) );
|
|
ListenStatus.pUserContext = m_pCommandHandle->GetUserContext();
|
|
|
|
hTempResult = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to DPlay callbacks
|
|
SPEV_LISTENSTATUS, // data type
|
|
&ListenStatus // pointer to data
|
|
);
|
|
DNASSERT( hTempResult == DPN_OK );
|
|
|
|
m_Flags.fListenStatusNeedsToBeIndicated = FALSE;
|
|
}
|
|
|
|
SetHandle( 0 );
|
|
SetState( ENDPOINT_STATE_UNINITIALIZED );
|
|
|
|
|
|
DPFX(DPFPREP, 6, "(0x%p) Leave", this );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::ProcessEnumData - process received enum data
|
|
//
|
|
// Entry: Pointer to received data
|
|
// Enum RTT index
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::ProcessEnumData"
|
|
|
|
void CModemEndpoint::ProcessEnumData( SPRECEIVEDBUFFER *const pReceivedBuffer, const UINT_PTR uEnumRTTIndex )
|
|
{
|
|
DNASSERT( pReceivedBuffer != NULL );
|
|
AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
|
|
|
|
//
|
|
// find out what state the endpoint is in before processing data
|
|
//
|
|
switch ( m_State )
|
|
{
|
|
//
|
|
// we're listening, this is the only way to detect enums
|
|
//
|
|
case ENDPOINT_STATE_LISTENING:
|
|
{
|
|
ENDPOINT_ENUM_QUERY_CONTEXT QueryContext;
|
|
HRESULT hr;
|
|
|
|
|
|
DNASSERT( m_pCommandHandle != NULL );
|
|
DEBUG_ONLY( memset( &QueryContext, 0x00, sizeof( QueryContext ) ) );
|
|
|
|
QueryContext.hEndpoint = (HANDLE)(DWORD_PTR)GetHandle();
|
|
QueryContext.uEnumRTTIndex = uEnumRTTIndex;
|
|
QueryContext.EnumQueryData.pReceivedData = pReceivedBuffer;
|
|
QueryContext.EnumQueryData.pUserContext = m_pCommandHandle->GetUserContext();
|
|
|
|
QueryContext.EnumQueryData.pAddressSender = GetRemoteHostDP8Address();
|
|
QueryContext.EnumQueryData.pAddressDevice = GetLocalAdapterDP8Address( ADDRESS_TYPE_LOCAL_ADAPTER );
|
|
|
|
//
|
|
// attempt to build a DNAddress for the user, if we can't allocate
|
|
// the memory ignore this enum
|
|
//
|
|
if ( ( QueryContext.EnumQueryData.pAddressSender != NULL ) &&
|
|
( QueryContext.EnumQueryData.pAddressDevice != NULL ) )
|
|
{
|
|
hr = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to DirectNet interface
|
|
SPEV_ENUMQUERY, // data type
|
|
&QueryContext.EnumQueryData // pointer to data
|
|
);
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "User returned unexpected error from enum query indication!" );
|
|
DisplayDNError( 0, hr );
|
|
DNASSERT( FALSE );
|
|
}
|
|
}
|
|
|
|
if ( QueryContext.EnumQueryData.pAddressSender != NULL )
|
|
{
|
|
IDirectPlay8Address_Release( QueryContext.EnumQueryData.pAddressSender );
|
|
QueryContext.EnumQueryData.pAddressSender = NULL;
|
|
}
|
|
|
|
if ( QueryContext.EnumQueryData.pAddressDevice )
|
|
{
|
|
IDirectPlay8Address_Release( QueryContext.EnumQueryData.pAddressDevice );
|
|
QueryContext.EnumQueryData.pAddressDevice = NULL;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// we're disconnecting, ignore this message
|
|
//
|
|
case ENDPOINT_STATE_ATTEMPTING_LISTEN:
|
|
case ENDPOINT_STATE_DISCONNECTING:
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other state
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::ProcessEnumResponseData - process received enum response data
|
|
//
|
|
// Entry: Pointer to received data
|
|
// Pointer to address of sender
|
|
//
|
|
// Exit: Nothing
|
|
//
|
|
// Note: This function assumes that the endpoint has been locked.
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::ProcessEnumResponseData"
|
|
|
|
void CModemEndpoint::ProcessEnumResponseData( SPRECEIVEDBUFFER *const pReceivedBuffer, const UINT_PTR uRTTIndex )
|
|
{
|
|
DNASSERT( pReceivedBuffer != NULL );
|
|
AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
|
|
|
|
//
|
|
// find out what state the endpoint is in before processing data
|
|
//
|
|
switch ( m_State )
|
|
{
|
|
//
|
|
// endpoint is enuming, it can handle enum responses
|
|
//
|
|
case ENDPOINT_STATE_ENUM:
|
|
{
|
|
SPIE_QUERYRESPONSE QueryResponseData;
|
|
HRESULT hr;
|
|
|
|
|
|
DNASSERT( m_pCommandHandle != NULL );
|
|
DEBUG_ONLY( memset( &QueryResponseData, 0x00, sizeof( QueryResponseData ) ) );
|
|
QueryResponseData.pReceivedData = pReceivedBuffer;
|
|
QueryResponseData.dwRoundTripTime = GETTIMESTAMP() - m_dwEnumSendTimes[ uRTTIndex ];
|
|
QueryResponseData.pUserContext = m_pCommandHandle->GetUserContext();
|
|
|
|
//
|
|
// attempt to build a DNAddress for the user, if we can't allocate
|
|
// the memory ignore this enum
|
|
//
|
|
QueryResponseData.pAddressSender = GetRemoteHostDP8Address();
|
|
QueryResponseData.pAddressDevice = GetLocalAdapterDP8Address( ADDRESS_TYPE_LOCAL_ADAPTER );
|
|
if ( ( QueryResponseData.pAddressSender != NULL ) &&
|
|
( QueryResponseData.pAddressDevice != NULL ) )
|
|
{
|
|
hr = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to DirectNet interface
|
|
SPEV_QUERYRESPONSE, // data type
|
|
&QueryResponseData // pointer to data
|
|
);
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "User returned unknown error when indicating query response!" );
|
|
DisplayDNError( 0, hr );
|
|
DNASSERT( FALSE );
|
|
}
|
|
|
|
}
|
|
|
|
if ( QueryResponseData.pAddressSender != NULL )
|
|
{
|
|
IDirectPlay8Address_Release( QueryResponseData.pAddressSender );
|
|
QueryResponseData.pAddressSender = NULL;
|
|
}
|
|
|
|
if ( QueryResponseData.pAddressDevice != NULL )
|
|
{
|
|
IDirectPlay8Address_Release( QueryResponseData.pAddressDevice );
|
|
QueryResponseData.pAddressDevice = NULL;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// endpoint is disconnecting, ignore data
|
|
//
|
|
case ENDPOINT_STATE_DISCONNECTING:
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other state
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::ProcessUserData - process received user data
|
|
//
|
|
// Entry: Pointer to received data
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::ProcessUserData"
|
|
|
|
void CModemEndpoint::ProcessUserData( CModemReadIOData *const pReadData )
|
|
{
|
|
DNASSERT( pReadData != NULL );
|
|
|
|
switch ( m_State )
|
|
{
|
|
//
|
|
// endpoint is connected
|
|
//
|
|
case ENDPOINT_STATE_CONNECT_CONNECTED:
|
|
{
|
|
HRESULT hr;
|
|
SPIE_DATA UserData;
|
|
|
|
|
|
//
|
|
// it's possible that the user wants to keep the data, add a
|
|
// reference to keep it from going away
|
|
//
|
|
pReadData->AddRef();
|
|
|
|
//
|
|
// we're connected, report the user data
|
|
//
|
|
DEBUG_ONLY( memset( &UserData, 0x00, sizeof( UserData ) ) );
|
|
DBG_CASSERT( sizeof( this ) == sizeof( HANDLE ) );
|
|
UserData.hEndpoint = (HANDLE)(DWORD_PTR)GetHandle();
|
|
UserData.pEndpointContext = GetUserEndpointContext();
|
|
UserData.pReceivedData = &pReadData->m_SPReceivedBuffer;
|
|
|
|
DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_DATA 0x%p to interface 0x%p.",
|
|
this, &UserData, m_pSPData->DP8SPCallbackInterface());
|
|
|
|
hr = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to interface
|
|
SPEV_DATA, // user data was received
|
|
&UserData // pointer to data
|
|
);
|
|
|
|
DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_DATA [0x%lx].", this, hr);
|
|
|
|
switch ( hr )
|
|
{
|
|
//
|
|
// user didn't keep the data, remove the reference added above
|
|
//
|
|
case DPN_OK:
|
|
{
|
|
DNASSERT( pReadData != NULL );
|
|
pReadData->DecRef();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The user kept the data buffer, they will return it later.
|
|
// Leave the reference to prevent this buffer from being returned
|
|
// to the pool.
|
|
//
|
|
case DPNERR_PENDING:
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Unknown return. Remove the reference added above.
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( pReadData != NULL );
|
|
pReadData->DecRef();
|
|
|
|
DPFX(DPFPREP, 0, "User returned unknown error when indicating user data!" );
|
|
DisplayDNError( 0, hr );
|
|
DNASSERT( FALSE );
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Endpoint disconnecting, or we haven't finished acknowledging a connect,
|
|
// ignore data.
|
|
//
|
|
case ENDPOINT_STATE_ATTEMPTING_CONNECT:
|
|
case ENDPOINT_STATE_DISCONNECTING:
|
|
{
|
|
DPFX(DPFPREP, 3, "Endpoint 0x%p ignoring data, state = %u.", this, m_State );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other state
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::ProcessUserDataOnListen - process received user data on a listen
|
|
// port that may result in a new connection
|
|
//
|
|
// Entry: Pointer to received data
|
|
//
|
|
// Exit: Nothing
|
|
//
|
|
// Note: This function assumes that this endpoint has been locked.
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::ProcessUserDataOnListen"
|
|
|
|
void CModemEndpoint::ProcessUserDataOnListen( CModemReadIOData *const pReadData )
|
|
{
|
|
HRESULT hr;
|
|
CModemEndpoint *pNewEndpoint;
|
|
SPIE_CONNECT ConnectData;
|
|
BOOL fEndpointBound;
|
|
|
|
|
|
DNASSERT( pReadData != NULL );
|
|
AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
|
|
|
|
DPFX(DPFPREP, 8, "Reporting connect on a listen!" );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
pNewEndpoint = NULL;
|
|
fEndpointBound = FALSE;
|
|
|
|
switch ( m_State )
|
|
{
|
|
//
|
|
// this endpoint is still listening
|
|
//
|
|
case ENDPOINT_STATE_LISTENING:
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// we're unable to process this user data, exti
|
|
//
|
|
case ENDPOINT_STATE_DISCONNECTING:
|
|
{
|
|
goto Exit;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other state
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// get a new endpoint from the pool
|
|
//
|
|
pNewEndpoint = m_pSPData->GetNewEndpoint();
|
|
if ( pNewEndpoint == NULL )
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
DPFX(DPFPREP, 0, "Could not create new endpoint for new connection on listen!" );
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// We are adding this endpoint to the hash table and indicating it up
|
|
// to the user, so it's possible that it could be disconnected (and thus
|
|
// removed from the table) while we're still in here. We need to
|
|
// hold an additional reference for the duration of this function to
|
|
// prevent it from disappearing while we're still indicating data.
|
|
//
|
|
pNewEndpoint->AddCommandRef();
|
|
|
|
|
|
//
|
|
// open this endpoint as a new connection, since the new endpoint
|
|
// is related to 'this' endpoint, copy local information
|
|
//
|
|
hr = pNewEndpoint->OpenOnListen( this );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem initializing new endpoint when indicating connect on listen!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Attempt to bind this endpoint to the socket port. This will reserve our
|
|
// slot before we notify the user. If another message is attempting this same
|
|
// procedure we won't be able to add this endpoint and we'll bail on the message.
|
|
//
|
|
DNASSERT( hr == DPN_OK );
|
|
hr = m_pSPData->BindEndpoint( pNewEndpoint, pNewEndpoint->GetDeviceID(), pNewEndpoint->GetDeviceContext() );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to bind endpoint to dataport on new connect from listen!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
fEndpointBound = TRUE;
|
|
|
|
//
|
|
// Indicate connect on this endpoint.
|
|
//
|
|
DEBUG_ONLY( memset( &ConnectData, 0x00, sizeof( ConnectData ) ) );
|
|
DBG_CASSERT( sizeof( ConnectData.hEndpoint ) == sizeof( pNewEndpoint ) );
|
|
ConnectData.hEndpoint = (HANDLE)(DWORD_PTR)pNewEndpoint->GetHandle();
|
|
|
|
DNASSERT( m_Flags.fCommandPending != FALSE );
|
|
DNASSERT( m_pCommandHandle != NULL );
|
|
ConnectData.pCommandContext = m_CurrentCommandParameters.ListenData.pvContext;
|
|
|
|
DNASSERT( pNewEndpoint->GetUserEndpointContext() == NULL );
|
|
hr = pNewEndpoint->SignalConnect( &ConnectData );
|
|
switch ( hr )
|
|
{
|
|
//
|
|
// user accepted new connection
|
|
//
|
|
case DPN_OK:
|
|
{
|
|
//
|
|
// fall through to code below
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// user refused new connection
|
|
//
|
|
case DPNERR_ABORTED:
|
|
{
|
|
DNASSERT( pNewEndpoint->GetUserEndpointContext() == NULL );
|
|
DPFX(DPFPREP, 8, "User refused new connection!" );
|
|
goto Failure;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other
|
|
//
|
|
default:
|
|
{
|
|
DPFX(DPFPREP, 0, "Unknown return when indicating connect event on new connect from listen!" );
|
|
DisplayDNError( 0, hr );
|
|
DNASSERT( FALSE );
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// note that a connection has been establised and send the data received
|
|
// through this new endpoint
|
|
//
|
|
pNewEndpoint->ProcessUserData( pReadData );
|
|
|
|
|
|
//
|
|
// Remove the reference we added just after creating the endpoint.
|
|
//
|
|
pNewEndpoint->DecCommandRef();
|
|
pNewEndpoint = NULL;
|
|
|
|
Exit:
|
|
return;
|
|
|
|
Failure:
|
|
if ( pNewEndpoint != NULL )
|
|
{
|
|
if ( fEndpointBound != FALSE )
|
|
{
|
|
m_pSPData->UnbindEndpoint( pNewEndpoint, ENDPOINT_TYPE_CONNECT );
|
|
fEndpointBound = FALSE;
|
|
}
|
|
|
|
//
|
|
// closing endpoint decrements reference count and may return it to the pool
|
|
//
|
|
pNewEndpoint->Close( hr );
|
|
m_pSPData->CloseEndpointHandle( pNewEndpoint );
|
|
pNewEndpoint->DecCommandRef(); // remove reference added just after creating endpoint
|
|
pNewEndpoint = NULL;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::SettingsDialogComplete - dialog has completed
|
|
//
|
|
// Entry: Error code for dialog
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
void CModemEndpoint::SettingsDialogComplete( const HRESULT hDialogResult )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = hDialogResult;
|
|
|
|
//
|
|
// since the dialog is exiting, clear our handle to the dialog
|
|
//
|
|
m_hActiveDialogHandle = NULL;
|
|
|
|
//
|
|
// dialog failed, fail the user's command
|
|
//
|
|
if ( hr != DPN_OK )
|
|
{
|
|
if ( hr != DPNERR_USERCANCEL)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failing dialog (err = 0x%lx)!", hr );
|
|
}
|
|
|
|
goto Failure;
|
|
}
|
|
|
|
AddRef();
|
|
|
|
//
|
|
// the remote machine address has been adjusted, finish the command
|
|
//
|
|
switch ( GetType() )
|
|
{
|
|
case ENDPOINT_TYPE_ENUM:
|
|
{
|
|
hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( EnumQueryJobCallback,
|
|
CancelEnumQueryJobCallback,
|
|
this );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DecRef();
|
|
DPFX(DPFPREP, 0, "Failed to set delayed enum query!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ENDPOINT_TYPE_CONNECT:
|
|
{
|
|
hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( ConnectJobCallback,
|
|
CancelConnectJobCallback,
|
|
this );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DecRef();
|
|
DPFX(DPFPREP, 0, "Failed to set delayed connect!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ENDPOINT_TYPE_LISTEN:
|
|
{
|
|
hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( ListenJobCallback,
|
|
CancelListenJobCallback,
|
|
this );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DecRef();
|
|
DPFX(DPFPREP, 0, "Failed to set delayed listen!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// unknown!
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
hr = DPNERR_GENERIC;
|
|
goto Failure;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
DecRef();
|
|
|
|
return;
|
|
|
|
Failure:
|
|
//
|
|
// close this endpoint
|
|
//
|
|
Close( hr );
|
|
m_pSPData->CloseEndpointHandle( this );
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::CompletePendingCommand - complete an internal commad
|
|
//
|
|
// Entry: Error code returned for command
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::CompletePendingCommand"
|
|
|
|
void CModemEndpoint::CompletePendingCommand( const HRESULT hr )
|
|
{
|
|
DNASSERT( m_Flags.fCommandPending != FALSE );
|
|
DNASSERT( m_pCommandHandle != NULL );
|
|
|
|
DNASSERT( m_pSPData != NULL );
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Endpoint 0x%p completing command handle 0x%p (result = 0x%lx, user context 0x%p) to interface 0x%p.",
|
|
this, m_pCommandHandle, hr,
|
|
m_pCommandHandle->GetUserContext(),
|
|
m_pSPData->DP8SPCallbackInterface());
|
|
|
|
IDP8SPCallback_CommandComplete( m_pSPData->DP8SPCallbackInterface(), // pointer to SP callbacks
|
|
m_pCommandHandle, // command handle
|
|
hr, // return
|
|
m_pCommandHandle->GetUserContext() // user cookie
|
|
);
|
|
|
|
DPFX(DPFPREP, 5, "Endpoint 0x%p returning from command complete [0x%lx].", this, hr);
|
|
|
|
|
|
m_Flags.fCommandPending = FALSE;
|
|
m_pCommandHandle->DecRef();
|
|
m_pCommandHandle = NULL;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::GetLinkDirection - get link direction for this endpoint
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Link direction
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::GetLinkDirection"
|
|
|
|
LINK_DIRECTION CModemEndpoint::GetLinkDirection( void ) const
|
|
{
|
|
LINK_DIRECTION LinkDirection;
|
|
|
|
|
|
LinkDirection = LINK_DIRECTION_OUTGOING;
|
|
|
|
switch ( GetType() )
|
|
{
|
|
case ENDPOINT_TYPE_LISTEN:
|
|
{
|
|
LinkDirection = LINK_DIRECTION_INCOMING;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// connect and enum are outgoing
|
|
//
|
|
case ENDPOINT_TYPE_CONNECT:
|
|
case ENDPOINT_TYPE_ENUM:
|
|
{
|
|
DNASSERT( LinkDirection == LINK_DIRECTION_OUTGOING );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// shouldn't be here
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return LinkDirection;
|
|
}
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::ReturnSelfToPool - return this item to the pool
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::ReturnSelfToPool"
|
|
|
|
void CModemEndpoint::ReturnSelfToPool( void )
|
|
{
|
|
if ( m_Flags.fCommandPending != FALSE )
|
|
{
|
|
CompletePendingCommand( PendingCommandResult() );
|
|
}
|
|
|
|
if ( m_Flags.fConnectIndicated != FALSE )
|
|
{
|
|
SignalDisconnect( GetDisconnectIndicationHandle() );
|
|
}
|
|
|
|
DNASSERT( m_Flags.fConnectIndicated == FALSE );
|
|
|
|
memset( m_PhoneNumber, 0x00, sizeof( m_PhoneNumber ) );
|
|
|
|
SetUserEndpointContext( NULL );
|
|
|
|
if (m_fModem)
|
|
{
|
|
g_ModemEndpointPool.Release( this );
|
|
}
|
|
else
|
|
{
|
|
g_ComEndpointPool.Release( this );
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::PoolAllocFunction - function called when item is created in pool
|
|
//
|
|
// Entry: Pointer to pool context
|
|
//
|
|
// Exit: Boolean indicating success
|
|
// TRUE = success
|
|
// FALSE = failure
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::PoolAllocFunction"
|
|
|
|
BOOL CModemEndpoint::PoolAllocFunction( void* pvItem, void* pvContext )
|
|
{
|
|
CModemEndpoint* pEndpoint = (CModemEndpoint*)pvItem;
|
|
const ENDPOINT_POOL_CONTEXT* pEPContext = (ENDPOINT_POOL_CONTEXT*)pvContext;
|
|
|
|
DNASSERT( pEPContext != NULL );
|
|
|
|
pEndpoint->m_fModem = pEPContext->fModem;
|
|
|
|
pEndpoint->m_Sig[0] = 'M';
|
|
pEndpoint->m_Sig[1] = 'O';
|
|
pEndpoint->m_Sig[2] = 'E';
|
|
pEndpoint->m_Sig[3] = 'P';
|
|
|
|
memset( &pEndpoint->m_PhoneNumber, 0x00, sizeof( pEndpoint->m_PhoneNumber ) );
|
|
|
|
pEndpoint->m_dwDeviceID = INVALID_DEVICE_ID;
|
|
|
|
//
|
|
// initialize base object
|
|
//
|
|
|
|
pEndpoint->m_pSPData = NULL;
|
|
pEndpoint->m_pCommandHandle = NULL;
|
|
pEndpoint->m_Handle = 0;
|
|
pEndpoint->m_State = ENDPOINT_STATE_UNINITIALIZED;
|
|
pEndpoint->m_lCommandRefCount = 0;
|
|
pEndpoint->m_EndpointType = ENDPOINT_TYPE_UNKNOWN;
|
|
pEndpoint->m_pDataPort = NULL;
|
|
pEndpoint->m_hPendingCommandResult = DPNERR_GENERIC;
|
|
pEndpoint->m_hDisconnectIndicationHandle = 0;
|
|
pEndpoint->m_pUserEndpointContext = NULL;
|
|
pEndpoint->m_hActiveDialogHandle = NULL;
|
|
pEndpoint->m_dwEnumSendIndex = 0;
|
|
pEndpoint->m_iRefCount = 0;
|
|
|
|
pEndpoint->m_Flags.fConnectIndicated = FALSE;
|
|
pEndpoint->m_Flags.fCommandPending = FALSE;
|
|
pEndpoint->m_Flags.fListenStatusNeedsToBeIndicated = FALSE;
|
|
|
|
pEndpoint->m_ComPortData.Reset();
|
|
|
|
memset( &pEndpoint->m_CurrentCommandParameters, 0x00, sizeof( pEndpoint->m_CurrentCommandParameters ) );
|
|
memset( &pEndpoint->m_Flags, 0x00, sizeof( pEndpoint->m_Flags ) );
|
|
|
|
if ( DNInitializeCriticalSection( &pEndpoint->m_Lock ) == FALSE )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to initialize endpoint lock!" );
|
|
return FALSE;
|
|
}
|
|
DebugSetCriticalSectionRecursionCount( &pEndpoint->m_Lock, 0 );
|
|
DebugSetCriticalSectionGroup( &pEndpoint->m_Lock, &g_blDPNModemCritSecsHeld ); // separate dpnmodem CSes from the rest of DPlay's CSes
|
|
|
|
pEndpoint->m_Flags.fInitialized = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::PoolInitFunction - function called when item is created in pool
|
|
//
|
|
// Entry: Pointer to pool context
|
|
//
|
|
// Exit: Boolean indicating success
|
|
// TRUE = success
|
|
// FALSE = failure
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::PoolInitFunction"
|
|
|
|
void CModemEndpoint::PoolInitFunction( void* pvItem, void* pvContext )
|
|
{
|
|
CModemEndpoint* pEndpoint = (CModemEndpoint*)pvItem;
|
|
ENDPOINT_POOL_CONTEXT* pEPContext = (ENDPOINT_POOL_CONTEXT*)pvContext;
|
|
|
|
DNASSERT( pEPContext != NULL );
|
|
DNASSERT( pEndpoint->m_pSPData == NULL );
|
|
DNASSERT( pEndpoint->GetState() == ENDPOINT_STATE_UNINITIALIZED );
|
|
DNASSERT( pEndpoint->GetType() == ENDPOINT_TYPE_UNKNOWN );
|
|
DNASSERT( pEndpoint->GetDeviceID() == INVALID_DEVICE_ID );
|
|
DNASSERT( pEndpoint->GetDisconnectIndicationHandle() == 0 );
|
|
|
|
pEndpoint->m_pSPData = pEPContext->pSPData;
|
|
pEndpoint->m_pSPData->ObjectAddRef();
|
|
|
|
//
|
|
// set reasonable defaults
|
|
//
|
|
pEndpoint->m_ComPortData.SetBaudRate( CBR_57600 );
|
|
pEndpoint->m_ComPortData.SetStopBits( ONESTOPBIT );
|
|
pEndpoint->m_ComPortData.SetParity( NOPARITY );
|
|
pEndpoint->m_ComPortData.SetFlowControl( FLOW_RTSDTR );
|
|
|
|
DNASSERT(pEndpoint->m_iRefCount == 0);
|
|
pEndpoint->m_iRefCount = 1;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::PoolReleaseFunction - function called when returned to pool
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::PoolReleaseFunction"
|
|
|
|
void CModemEndpoint::PoolReleaseFunction( void* pvItem )
|
|
{
|
|
CModemSPData *pSPData;
|
|
|
|
CModemEndpoint* pEndpoint = (CModemEndpoint*)pvItem;
|
|
|
|
DNASSERT(pEndpoint->m_iRefCount == 0);
|
|
|
|
//
|
|
// deinitialize base object
|
|
//
|
|
DNASSERT( pEndpoint->m_pSPData != NULL );
|
|
pSPData = pEndpoint->m_pSPData;
|
|
pEndpoint->m_pSPData = NULL;
|
|
|
|
pEndpoint->m_ComPortData.Reset();
|
|
pEndpoint->SetType( ENDPOINT_TYPE_UNKNOWN );
|
|
pEndpoint->SetState( ENDPOINT_STATE_UNINITIALIZED );
|
|
pEndpoint->SetDeviceID( INVALID_DEVICE_ID );
|
|
DNASSERT( pEndpoint->GetDisconnectIndicationHandle() == 0 );
|
|
|
|
DNASSERT( pEndpoint->m_Flags.fConnectIndicated == FALSE );
|
|
DNASSERT( pEndpoint->m_Flags.fCommandPending == FALSE );
|
|
DNASSERT( pEndpoint->m_Flags.fListenStatusNeedsToBeIndicated == FALSE );
|
|
DNASSERT( pEndpoint->m_pCommandHandle == NULL );
|
|
DNASSERT( pEndpoint->m_hActiveDialogHandle == NULL );
|
|
|
|
pSPData->ObjectDecRef();
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::PoolDeallocFunction - function called when deleted from pool
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::PoolDeallocFunction"
|
|
|
|
void CModemEndpoint::PoolDeallocFunction( void* pvItem )
|
|
{
|
|
CModemEndpoint* pEndpoint = (CModemEndpoint*)pvItem;
|
|
|
|
DNASSERT( pEndpoint->m_Flags.fInitialized != FALSE );
|
|
DNDeleteCriticalSection( &pEndpoint->m_Lock );
|
|
pEndpoint->m_pSPData = NULL;
|
|
|
|
DNASSERT( pEndpoint->m_pCommandHandle == NULL );
|
|
DNASSERT( pEndpoint->m_Flags.fCommandPending == FALSE );
|
|
|
|
pEndpoint->SetState( ENDPOINT_STATE_UNINITIALIZED );
|
|
pEndpoint->SetType( ENDPOINT_TYPE_UNKNOWN );
|
|
|
|
DNASSERT( pEndpoint->GetDataPort() == NULL );
|
|
pEndpoint->m_Flags.fInitialized = FALSE;
|
|
|
|
DNASSERT( pEndpoint->GetDeviceID() == INVALID_DEVICE_ID );
|
|
|
|
DNASSERT( pEndpoint->GetDisconnectIndicationHandle() == 0 );
|
|
DNASSERT( pEndpoint->m_pSPData == NULL );
|
|
DNASSERT( pEndpoint->m_Flags.fInitialized == FALSE );
|
|
DNASSERT( pEndpoint->m_Flags.fConnectIndicated == FALSE );
|
|
DNASSERT( pEndpoint->m_Flags.fCommandPending == FALSE );
|
|
DNASSERT( pEndpoint->m_Flags.fListenStatusNeedsToBeIndicated == FALSE );
|
|
DNASSERT( pEndpoint->m_pCommandHandle == NULL );
|
|
DNASSERT( pEndpoint->m_Handle == 0 );
|
|
DNASSERT( pEndpoint->m_State == ENDPOINT_STATE_UNINITIALIZED );
|
|
DNASSERT( pEndpoint->m_lCommandRefCount == 0 );
|
|
DNASSERT( pEndpoint->m_EndpointType == ENDPOINT_TYPE_UNKNOWN );
|
|
DNASSERT( pEndpoint->m_pDataPort == NULL );
|
|
// DNASSERT( pEndpoint->m_hPendingCommandResult == DPNERR_GENERIC ); MASONB: NOTE: PreFAST caught a bug here because == was =, but it now asserts. Check intent.
|
|
DNASSERT( pEndpoint->m_pUserEndpointContext == NULL );
|
|
DNASSERT( pEndpoint->m_hActiveDialogHandle == NULL );
|
|
DNASSERT( pEndpoint->m_dwEnumSendIndex == 0 );
|
|
|
|
DNASSERT( pEndpoint->m_iRefCount == 0 );
|
|
}
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::Open - open communications with endpoint
|
|
//
|
|
// Entry: Pointer to host address
|
|
// Pointer to adapter address
|
|
// Link direction
|
|
// Endpoint type
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::Open"
|
|
|
|
HRESULT CModemEndpoint::Open( IDirectPlay8Address *const pHostAddress,
|
|
IDirectPlay8Address *const pAdapterAddress,
|
|
const LINK_DIRECTION LinkDirection,
|
|
const ENDPOINT_TYPE EndpointType )
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hDeviceResult;
|
|
GUID ModemDeviceGuid;
|
|
|
|
|
|
DNASSERT( pAdapterAddress != NULL );
|
|
|
|
DNASSERT( ( LinkDirection == LINK_DIRECTION_INCOMING ) ||
|
|
( LinkDirection == LINK_DIRECTION_OUTGOING ) );
|
|
DNASSERT( ( EndpointType == ENDPOINT_TYPE_CONNECT ) ||
|
|
( EndpointType == ENDPOINT_TYPE_ENUM ) ||
|
|
( EndpointType == ENDPOINT_TYPE_LISTEN ) ||
|
|
( EndpointType == ENDPOINT_TYPE_CONNECT_ON_LISTEN ) );
|
|
DNASSERT( ( ( pHostAddress != NULL ) && ( LinkDirection == LINK_DIRECTION_OUTGOING ) ) ||
|
|
( ( pHostAddress == NULL ) && ( LinkDirection == LINK_DIRECTION_INCOMING ) ) );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
if (m_fModem)
|
|
{
|
|
DNASSERT( lstrlen( m_PhoneNumber ) == 0 );
|
|
DNASSERT( GetDeviceID() == INVALID_DEVICE_ID );
|
|
|
|
hDeviceResult = IDirectPlay8Address_GetDevice( pAdapterAddress, &ModemDeviceGuid );
|
|
switch ( hDeviceResult )
|
|
{
|
|
case DPN_OK:
|
|
{
|
|
SetDeviceID( GuidToDeviceID( &ModemDeviceGuid, &g_ModemSPEncryptionGuid ) );
|
|
break;
|
|
}
|
|
|
|
case DPNERR_DOESNOTEXIST:
|
|
{
|
|
DNASSERT( GetDeviceID() == INVALID_DEVICE_ID );
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = hDeviceResult;
|
|
DPFX(DPFPREP, 0, "Failed to get modem device!" );
|
|
DisplayDNError( 0, hr);
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
if ( LinkDirection == LINK_DIRECTION_OUTGOING )
|
|
{
|
|
HRESULT hPhoneNumberResult;
|
|
DWORD dwWCHARPhoneNumberSize;
|
|
DWORD dwDataType;
|
|
WCHAR PhoneNumber[ LENGTHOF( m_PhoneNumber ) ];
|
|
|
|
|
|
dwWCHARPhoneNumberSize = sizeof( PhoneNumber );
|
|
hPhoneNumberResult = IDirectPlay8Address_GetComponentByName( pHostAddress,
|
|
DPNA_KEY_PHONENUMBER,
|
|
PhoneNumber,
|
|
&dwWCHARPhoneNumberSize,
|
|
&dwDataType );
|
|
switch ( hPhoneNumberResult )
|
|
{
|
|
case DPN_OK:
|
|
{
|
|
#ifdef UNICODE
|
|
lstrcpy(m_PhoneNumber, PhoneNumber);
|
|
#else
|
|
DWORD dwASCIIPhoneNumberSize;
|
|
|
|
//
|
|
// can't use the STR_ functions to convert ANSI to WIDE phone
|
|
// numbers because phone numbers with symbols: "9,", "*70" are
|
|
// interpreted as already being WCHAR when they're not!
|
|
//
|
|
dwASCIIPhoneNumberSize = sizeof( m_PhoneNumber );
|
|
DNASSERT( dwDataType == DPNA_DATATYPE_STRING );
|
|
hr = PhoneNumberFromWCHAR( PhoneNumber, m_PhoneNumber, &dwASCIIPhoneNumberSize );
|
|
DNASSERT( hr == DPN_OK );
|
|
#endif // UNICODE
|
|
|
|
break;
|
|
}
|
|
|
|
case DPNERR_DOESNOTEXIST:
|
|
{
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
hr = hPhoneNumberResult;
|
|
DPFX(DPFPREP, 0, "Failed to process phone number!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ( GetDeviceID() == INVALID_DEVICE_ID ) ||
|
|
( ( LinkDirection == LINK_DIRECTION_OUTGOING ) && ( lstrlen( m_PhoneNumber ) == 0 ) ) )
|
|
{
|
|
hr = DPNERR_INCOMPLETEADDRESS;
|
|
goto Failure;
|
|
}
|
|
}
|
|
else // !m_fModem
|
|
{
|
|
hr = m_ComPortData.ComPortDataFromDP8Addresses( pHostAddress, pAdapterAddress );
|
|
}
|
|
|
|
Exit:
|
|
SetType( EndpointType );
|
|
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem with CModemEndpoint::Open" );
|
|
DisplayDNError( 0, hr );
|
|
}
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::OpenOnListen - open this endpoint when data is received on a listen
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Noting
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::OpenOnListen"
|
|
|
|
HRESULT CModemEndpoint::OpenOnListen( const CModemEndpoint *const pListenEndpoint )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DNASSERT( pListenEndpoint != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
if (m_fModem)
|
|
{
|
|
SetDeviceID( pListenEndpoint->GetDeviceID() );
|
|
}
|
|
else
|
|
{
|
|
m_ComPortData.Copy( pListenEndpoint->GetComPortData() );
|
|
}
|
|
SetType( ENDPOINT_TYPE_CONNECT_ON_LISTEN );
|
|
SetState( ENDPOINT_STATE_ATTEMPTING_CONNECT );
|
|
|
|
return hr;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::Close - close this endpoint
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Noting
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::Close"
|
|
|
|
void CModemEndpoint::Close( const HRESULT hActiveCommandResult )
|
|
{
|
|
DPFX(DPFPREP, 6, "(0x%p) Parameters (0x%lx)", this, hActiveCommandResult);
|
|
|
|
|
|
//
|
|
// Set the command result so it can be returned when the endpoint reference
|
|
// count is zero.
|
|
//
|
|
SetCommandResult( hActiveCommandResult );
|
|
|
|
|
|
DPFX(DPFPREP, 6, "(0x%p) Leaving", this);
|
|
}
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::GetLinkSpeed - get speed of link
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Link speed
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::GetLinkSpeed"
|
|
|
|
DWORD CModemEndpoint::GetLinkSpeed( void ) const
|
|
{
|
|
return GetBaudRate();
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::EnumComplete - enumeration has completed
|
|
//
|
|
// Entry: Command completion code
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::EnumComplete"
|
|
|
|
void CModemEndpoint::EnumComplete( const HRESULT hCommandResult )
|
|
{
|
|
Close( hCommandResult );
|
|
m_pSPData->CloseEndpointHandle( this );
|
|
m_dwEnumSendIndex = 0;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::GetDeviceContext - get device context to initialize data port
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Device context
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::GetDeviceContext"
|
|
|
|
const void *CModemEndpoint::GetDeviceContext( void ) const
|
|
{
|
|
if (m_fModem)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return &m_ComPortData;
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::GetRemoteHostDP8Address - get address of remote host
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Pointer to address
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::GetRemoteHostDP8Address"
|
|
|
|
IDirectPlay8Address *CModemEndpoint::GetRemoteHostDP8Address( void ) const
|
|
{
|
|
IDirectPlay8Address *pAddress;
|
|
HRESULT hr;
|
|
|
|
if (!m_fModem)
|
|
{
|
|
return GetLocalAdapterDP8Address( ADDRESS_TYPE_REMOTE_HOST );
|
|
}
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
pAddress = NULL;
|
|
|
|
hr = COM_CoCreateInstance( CLSID_DirectPlay8Address,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDirectPlay8Address,
|
|
reinterpret_cast<void**>( &pAddress ), FALSE );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DNASSERT( pAddress == NULL );
|
|
DPFX(DPFPREP, 0, "GetRemoteHostDP8Address: Failed to create Address when converting data port to address!" );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// set the SP guid
|
|
//
|
|
hr = IDirectPlay8Address_SetSP( pAddress, &CLSID_DP8SP_MODEM );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "GetRemoteHostDP8Address: Failed to set service provider GUID!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Host names can only be returned for connect and enum endpoints. Host
|
|
// names are the phone numbers that were called and will be unknown on a
|
|
// 'listen' endpoint.
|
|
//
|
|
switch ( GetType() )
|
|
{
|
|
case ENDPOINT_TYPE_ENUM:
|
|
case ENDPOINT_TYPE_CONNECT:
|
|
{
|
|
DWORD dwPhoneNumberLength;
|
|
|
|
|
|
dwPhoneNumberLength = lstrlen( m_PhoneNumber );
|
|
if ( dwPhoneNumberLength != 0 )
|
|
{
|
|
#ifdef UNICODE
|
|
hr = IDirectPlay8Address_AddComponent( pAddress,
|
|
DPNA_KEY_PHONENUMBER,
|
|
m_PhoneNumber,
|
|
(dwPhoneNumberLength + 1) * sizeof( *m_PhoneNumber ),
|
|
DPNA_DATATYPE_STRING );
|
|
#else
|
|
WCHAR WCHARPhoneNumber[ sizeof( m_PhoneNumber ) ];
|
|
DWORD dwWCHARPhoneNumberLength;
|
|
|
|
//
|
|
// can't use the STR_ functions to convert ANSI to WIDE phone
|
|
// numbers because phone numbers with symbols: "9,", "*70" are
|
|
// interpreted as already being WCHAR when they're not!
|
|
//
|
|
dwWCHARPhoneNumberLength = LENGTHOF( WCHARPhoneNumber );
|
|
hr = PhoneNumberToWCHAR( m_PhoneNumber, WCHARPhoneNumber, &dwWCHARPhoneNumberLength );
|
|
DNASSERT( hr == DPN_OK );
|
|
|
|
hr = IDirectPlay8Address_AddComponent( pAddress,
|
|
DPNA_KEY_PHONENUMBER,
|
|
WCHARPhoneNumber,
|
|
dwWCHARPhoneNumberLength * sizeof( *WCHARPhoneNumber ),
|
|
DPNA_DATATYPE_STRING );
|
|
#endif // UNICODE
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "GetRemoteHostDP8Address: Failed to add phone number to hostname!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ENDPOINT_TYPE_LISTEN:
|
|
{
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
Exit:
|
|
return pAddress;
|
|
|
|
Failure:
|
|
if ( pAddress != NULL )
|
|
{
|
|
IDirectPlay8Address_Release( pAddress );
|
|
pAddress = NULL;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::GetLocalAdapterDP8Address - get address from local adapter
|
|
//
|
|
// Entry: Adadpter address format
|
|
//
|
|
// Exit: Pointer to address
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::GetLocalAdapterDP8Address"
|
|
|
|
IDirectPlay8Address *CModemEndpoint::GetLocalAdapterDP8Address( const ADDRESS_TYPE AddressType ) const
|
|
{
|
|
CDataPort *pDataPort;
|
|
|
|
DNASSERT( GetDataPort() != NULL );
|
|
pDataPort = GetDataPort();
|
|
|
|
if (m_fModem)
|
|
{
|
|
return pDataPort->GetLocalAdapterDP8Address( AddressType );
|
|
}
|
|
else
|
|
{
|
|
return pDataPort->ComPortData()->DP8AddressFromComPortData( AddressType );
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|
|
#ifndef DPNBUILD_NOSPUI
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::ShowIncomingSettingsDialog - show dialog for incoming modem settings
|
|
//
|
|
// Entry: Pointer to thread pool
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::ShowIncomingSettingsDialog"
|
|
|
|
HRESULT CModemEndpoint::ShowIncomingSettingsDialog( CModemThreadPool *const pThreadPool )
|
|
{
|
|
HRESULT hr;
|
|
DIALOG_FUNCTION* pFunction;
|
|
|
|
if (m_fModem)
|
|
{
|
|
pFunction = DisplayIncomingModemSettingsDialog;
|
|
}
|
|
else
|
|
{
|
|
pFunction = DisplayComPortSettingsDialog;
|
|
}
|
|
|
|
DNASSERT( pThreadPool != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
AddRef();
|
|
hr = pThreadPool->SpawnDialogThread( pFunction, this );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to start incoming modem dialog!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
|
|
Failure:
|
|
DecRef();
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::ShowOutgoingSettingsDialog - show settings dialog for outgoing
|
|
// modem connection
|
|
//
|
|
// Entry: Pointer to thread pool
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::ShowOutgoingSettingsDialog"
|
|
|
|
HRESULT CModemEndpoint::ShowOutgoingSettingsDialog( CModemThreadPool *const pThreadPool )
|
|
{
|
|
HRESULT hr;
|
|
DIALOG_FUNCTION* pFunction;
|
|
|
|
|
|
DNASSERT( pThreadPool != NULL );
|
|
|
|
if (m_fModem)
|
|
{
|
|
pFunction = DisplayOutgoingModemSettingsDialog;
|
|
}
|
|
else
|
|
{
|
|
pFunction = DisplayComPortSettingsDialog;
|
|
}
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
AddRef();
|
|
hr = pThreadPool->SpawnDialogThread( pFunction, this );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to start incoming modem dialog!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
|
|
Failure:
|
|
DecRef();
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CModemEndpoint::StopSettingsDialog - stop a settings dialog
|
|
//
|
|
// Entry: Dialog handle
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CModemEndpoint::StopSettingsDialog"
|
|
|
|
void CModemEndpoint::StopSettingsDialog( const HWND hDialog )
|
|
{
|
|
if (m_fModem)
|
|
{
|
|
StopModemSettingsDialog( hDialog );
|
|
}
|
|
else
|
|
{
|
|
StopComPortSettingsDialog( hDialog );
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|
|
#endif // !DPNBUILD_NOSPUI
|