1227 lines
31 KiB
C++
1227 lines
31 KiB
C++
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: DataPort.cpp
|
|
* Content: Serial communications port management class
|
|
*
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 01/20/98 jtk Created
|
|
* 09/14/99 jtk Derived from ComPort.cpp
|
|
***************************************************************************/
|
|
|
|
#include "dnmdmi.h"
|
|
|
|
|
|
//**********************************************************************
|
|
// Constant definitions
|
|
//**********************************************************************
|
|
|
|
//
|
|
// number of milliseconds in one day
|
|
//
|
|
#define ONE_DAY 86400000
|
|
|
|
//
|
|
// number of BITS in a serial BYTE
|
|
//
|
|
#define BITS_PER_BYTE 8
|
|
|
|
//**********************************************************************
|
|
// Macro definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Structure definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Variable definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Function prototypes
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Function definitions
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::CDataPort - constructor
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
//
|
|
// Notes: Do not allocate anything in a constructor
|
|
// ------------------------------
|
|
CDataPort::CDataPort():
|
|
m_EndpointRefCount( 0 ),
|
|
m_State( DATA_PORT_STATE_UNKNOWN ),
|
|
m_Handle( INVALID_HANDLE_VALUE ),
|
|
m_pSPData( NULL ),
|
|
m_pActiveRead( NULL ),
|
|
m_LinkDirection( LINK_DIRECTION_UNKNOWN ),
|
|
m_hFile( INVALID_HANDLE_VALUE ),
|
|
m_hListenEndpoint( INVALID_HANDLE_VALUE ),
|
|
m_hConnectEndpoint( INVALID_HANDLE_VALUE ),
|
|
m_hEnumEndpoint( INVALID_HANDLE_VALUE )
|
|
{
|
|
m_ActiveListLinkage.Initialize();
|
|
|
|
DEBUG_ONLY( m_fInitialized = FALSE );
|
|
// DEBUG_ONLY( m_fDeviceParametersInitialized = FALSE );
|
|
// DEBUG_ONLY( m_fFileParametersInitialized = FALSE );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::~CDataPort - destructor
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDataPort::~CDataPort"
|
|
|
|
CDataPort::~CDataPort()
|
|
{
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized == FALSE ) );
|
|
|
|
DNASSERT( m_EndpointRefCount == 0 );
|
|
DNASSERT( GetState() == DATA_PORT_STATE_UNKNOWN );
|
|
DNASSERT( GetHandle() == INVALID_HANDLE_VALUE );
|
|
DNASSERT( GetSPData() == NULL );
|
|
DNASSERT( m_pActiveRead == NULL );
|
|
|
|
DNASSERT( m_ActiveListLinkage.IsEmpty() != FALSE );
|
|
|
|
DNASSERT( m_LinkDirection == LINK_DIRECTION_UNKNOWN );
|
|
DNASSERT( m_hFile == INVALID_HANDLE_VALUE );
|
|
|
|
DNASSERT( m_hListenEndpoint == INVALID_HANDLE_VALUE );
|
|
DNASSERT( m_hConnectEndpoint == INVALID_HANDLE_VALUE );
|
|
DNASSERT( m_hEnumEndpoint == INVALID_HANDLE_VALUE );
|
|
|
|
// DEBUG_ONLY( DNASSERT( m_fInitialized == FALSE ) );
|
|
// DEBUG_ONLY( DNASSERT( m_fDeviceParametersInitialized == FALSE ) );
|
|
// DEBUG_ONLY( DNASSERT( m_fFileParametersInitialized == FALSE ) );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::Initialize - initialize data port for use
|
|
//
|
|
// Entry: Pointer to SPData
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDataPort::Initialize"
|
|
|
|
HRESULT CDataPort::Initialize( CSPData *const pSPData )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DNASSERT( pSPData != NULL );
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized == FALSE ) );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
DNASSERT( m_pSPData == NULL );
|
|
m_pSPData = pSPData;
|
|
|
|
DNASSERT( m_ActiveListLinkage.IsEmpty() != FALSE );
|
|
|
|
DNASSERT( m_hListenEndpoint == INVALID_HANDLE_VALUE );
|
|
DNASSERT( m_hConnectEndpoint == INVALID_HANDLE_VALUE );
|
|
DNASSERT( m_hEnumEndpoint == INVALID_HANDLE_VALUE );
|
|
|
|
//
|
|
// Attempt to create critical section, recursion count needs to be non-zero
|
|
// to handle endpoint cleanup when a modem operation fails.
|
|
//
|
|
if ( DNInitializeCriticalSection( &m_Lock ) == FALSE )
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
DPFX(DPFPREP, 0, "Failed to initialized critical section on DataPort!" );
|
|
goto Failure;
|
|
}
|
|
DebugSetCriticalSectionRecursionCount( &m_Lock, 1 );
|
|
|
|
// //
|
|
// // initialize send queue
|
|
// //
|
|
// hr = m_SendQueue.Initialize();
|
|
// if ( hr != DPN_OK )
|
|
// {
|
|
// DPFX(DPFPREP, 0, "Failed to initialize send queue!" );
|
|
// DisplayDNError( 0, hr );
|
|
// goto Failure;
|
|
// }
|
|
|
|
|
|
SetState( DATA_PORT_STATE_INITIALIZED );
|
|
DEBUG_ONLY( m_fInitialized = TRUE );
|
|
|
|
Exit:
|
|
return hr;
|
|
|
|
Failure:
|
|
Deinitialize();
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::Deinitialize - deinitialize this data port
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDataPort::Deinitialize"
|
|
|
|
void CDataPort::Deinitialize( void )
|
|
{
|
|
m_pSPData = NULL;
|
|
|
|
DNASSERT( m_ActiveListLinkage.IsEmpty() != FALSE );
|
|
|
|
DNASSERT( m_hFile == INVALID_HANDLE_VALUE );
|
|
|
|
DNASSERT( m_hListenEndpoint == INVALID_HANDLE_VALUE );
|
|
DNASSERT( m_hConnectEndpoint == INVALID_HANDLE_VALUE );
|
|
DNASSERT( m_hEnumEndpoint == INVALID_HANDLE_VALUE );
|
|
|
|
// m_SendQueue.Deinitialize();
|
|
|
|
DNDeleteCriticalSection( &m_Lock );
|
|
|
|
SetState( DATA_PORT_STATE_UNKNOWN );
|
|
DEBUG_ONLY( m_fInitialized = FALSE );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::EndpointAddRef - increment endpoint reference count
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDataPort::EndpointAddRef"
|
|
|
|
void CDataPort::EndpointAddRef( void )
|
|
{
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
|
|
|
|
Lock();
|
|
|
|
DNASSERT( m_EndpointRefCount != -1 );
|
|
m_EndpointRefCount++;
|
|
|
|
AddRef();
|
|
|
|
Unlock();
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::EndpointDecRef - decrement endpoint reference count
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Endpoint reference count
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDataPort::EndpointDecRef"
|
|
|
|
DWORD CDataPort::EndpointDecRef( void )
|
|
{
|
|
DWORD dwReturn;
|
|
|
|
|
|
DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
|
|
|
|
DNASSERT( m_EndpointRefCount != 0 );
|
|
DNASSERT( ( GetState() == DATA_PORT_STATE_RECEIVING ) ||
|
|
( GetState() == DATA_PORT_STATE_INITIALIZED ) );
|
|
// ( GetState() == DATA_PORT_STATE_CLOSING ) );
|
|
|
|
|
|
Lock();
|
|
|
|
DNASSERT( m_EndpointRefCount != 0 );
|
|
m_EndpointRefCount--;
|
|
dwReturn = m_EndpointRefCount;
|
|
if ( m_EndpointRefCount == 0 )
|
|
{
|
|
SetState( DATA_PORT_STATE_UNBOUND );
|
|
UnbindFromNetwork();
|
|
}
|
|
|
|
Unlock();
|
|
|
|
DecRef();
|
|
|
|
return dwReturn;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::SetPortCommunicationParameters - set generate communication parameters
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDataPort::SetPortCommunicationParameters"
|
|
|
|
HRESULT CDataPort::SetPortCommunicationParameters( void )
|
|
{
|
|
HRESULT hr;
|
|
COMMTIMEOUTS CommTimeouts;
|
|
|
|
|
|
//
|
|
// set timeout values for serial port
|
|
//
|
|
hr = DPN_OK;
|
|
memset( &CommTimeouts, 0x00, sizeof( CommTimeouts ) );
|
|
// CommTimeouts.ReadIntervalTimeout = 1; // wait 1ms before timing out on input
|
|
CommTimeouts.ReadIntervalTimeout = ONE_DAY; // read timeout interval (none)
|
|
CommTimeouts.ReadTotalTimeoutMultiplier = ONE_DAY; // return immediately
|
|
CommTimeouts.ReadTotalTimeoutConstant = 0; // return immediately
|
|
// CommTimeouts.ReadIntervalTimeout = 0; // read timeout interval (none)
|
|
// CommTimeouts.ReadTotalTimeoutMultiplier = 0; // return immediately
|
|
// CommTimeouts.ReadTotalTimeoutConstant = 0; // return immediately
|
|
CommTimeouts.WriteTotalTimeoutMultiplier = 0; // no multiplier
|
|
CommTimeouts.WriteTotalTimeoutConstant = WRITE_TIMEOUT_MS; // write timeout interval
|
|
|
|
if ( SetCommTimeouts( m_hFile, &CommTimeouts ) == FALSE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
hr = DPNERR_GENERIC;
|
|
dwError = GetLastError();
|
|
// report error (there's no cleanup)
|
|
DPFX(DPFPREP, 0, "Unable to set comm timeouts!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// clear any outstanding communication data
|
|
//
|
|
if ( PurgeComm( m_hFile, ( PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ) == FALSE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Problem with PurgeComm() when opening com port!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
}
|
|
|
|
//
|
|
// set communication mask to listen for character receive
|
|
//
|
|
if ( SetCommMask( m_hFile, EV_RXCHAR ) == FALSE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
hr = DPNERR_GENERIC;
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Error setting communication mask!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
|
|
Failure:
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::StartReceiving - start receiving
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDataPort::StartReceiving"
|
|
|
|
HRESULT CDataPort::StartReceiving( void )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
Lock();
|
|
|
|
switch ( GetState() )
|
|
{
|
|
//
|
|
// port is initialized, but not receiving yet, start receiving
|
|
//
|
|
case DATA_PORT_STATE_INITIALIZED:
|
|
{
|
|
hr = Receive();
|
|
if ( ( hr == DPNERR_PENDING ) ||
|
|
( hr == DPN_OK ) )
|
|
{
|
|
SetState( DATA_PORT_STATE_RECEIVING );
|
|
|
|
//
|
|
// the receive was successful, return success for this function
|
|
//
|
|
hr = DPN_OK;
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed initial read!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// data port is already receiving, nothing to do
|
|
//
|
|
case DATA_PORT_STATE_RECEIVING:
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// data port is closing, we shouldn't be here!
|
|
//
|
|
case DATA_PORT_STATE_UNBOUND:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// bad state
|
|
//
|
|
case DATA_PORT_STATE_UNKNOWN:
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
|
|
Exit:
|
|
return hr;
|
|
|
|
Failure:
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::Receive - read from file
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDataPort::Receive"
|
|
|
|
HRESULT CDataPort::Receive( void )
|
|
{
|
|
HRESULT hr;
|
|
BOOL fReadReturn;
|
|
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
AddRef();
|
|
|
|
Reread:
|
|
//
|
|
// if there is no pending read, get one from the pool
|
|
//
|
|
if ( m_pActiveRead == NULL )
|
|
{
|
|
m_pActiveRead = m_pSPData->GetThreadPool()->CreateReadIOData();
|
|
if ( m_pActiveRead == NULL )
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
DPFX(DPFPREP, 0, "Failed to get buffer for read!" );
|
|
goto Failure;
|
|
}
|
|
|
|
m_pActiveRead->SetDataPort( this );
|
|
}
|
|
|
|
//
|
|
// check the state of the read and perform the appropriate action
|
|
//
|
|
DNASSERT( m_pActiveRead != NULL );
|
|
switch ( m_pActiveRead->m_ReadState )
|
|
{
|
|
//
|
|
// Initialize read state. This involves setting up to read a header
|
|
// and then reentering the loop.
|
|
//
|
|
case READ_STATE_UNKNOWN:
|
|
{
|
|
m_pActiveRead->SetReadState( READ_STATE_READ_HEADER );
|
|
m_pActiveRead->m_dwBytesToRead = sizeof( m_pActiveRead->m_ReceiveBuffer.MessageHeader );
|
|
m_pActiveRead->m_dwReadOffset = 0;
|
|
goto Reread;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// issue a read for a header or user data
|
|
//
|
|
case READ_STATE_READ_HEADER:
|
|
case READ_STATE_READ_DATA:
|
|
{
|
|
//
|
|
// don't change m_dwReadOffset because it might have been set
|
|
// elsewhere to recover a partially received message
|
|
//
|
|
// DNASSERT( m_pActiveReceiveBuffer != NULL );
|
|
// m_dwBytesReceived = 0;
|
|
// m_pActiveRead->m_dwBytesReceived = 0;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// unknown state
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// lock the active read list for Win9x only to prevent reads from completing
|
|
// early
|
|
//
|
|
#ifdef WIN95
|
|
m_pSPData->GetThreadPool()->LockReadData();
|
|
DNASSERT( m_pActiveRead->Win9xOperationPending() == FALSE );
|
|
m_pActiveRead->SetWin9xOperationPending( TRUE );
|
|
#endif
|
|
|
|
DNASSERT( m_pActiveRead->jkm_dwOverlappedBytesReceived == 0 );
|
|
|
|
|
|
DPFX(DPFPREP, 8, "Submitting read 0x%p (socketport 0x%p, file 0x%p).",
|
|
m_pActiveRead, this, m_hFile);
|
|
|
|
|
|
//
|
|
// perform read
|
|
//
|
|
fReadReturn = ReadFile( m_hFile, // file handle
|
|
&m_pActiveRead->m_ReceiveBuffer.ReceivedData[ m_pActiveRead->m_dwReadOffset ], // pointer to destination
|
|
m_pActiveRead->m_dwBytesToRead, // number of bytes to read
|
|
&m_pActiveRead->jkm_dwImmediateBytesReceived, // pointer to number of bytes received
|
|
m_pActiveRead->Overlap() // pointer to overlap structure
|
|
);
|
|
if ( fReadReturn == FALSE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
switch ( dwError )
|
|
{
|
|
//
|
|
// I/O is pending, wait for completion notification
|
|
//
|
|
case ERROR_IO_PENDING:
|
|
{
|
|
hr = DPNERR_PENDING;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// comport was closed, nothing else to do
|
|
//
|
|
case ERROR_INVALID_HANDLE:
|
|
{
|
|
hr = DPNERR_NOCONNECTION;
|
|
goto Failure;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other
|
|
//
|
|
default:
|
|
{
|
|
hr = DPNERR_GENERIC;
|
|
DPFX(DPFPREP, 0, "Unknown error from ReadFile!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
DNASSERT( FALSE );
|
|
goto Failure;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// read succeeded immediately, we'll handle it on the async notification
|
|
//
|
|
DNASSERT( hr == DPN_OK );
|
|
}
|
|
|
|
Exit:
|
|
#ifdef WIN95
|
|
m_pSPData->GetThreadPool()->UnlockReadData();
|
|
#endif
|
|
return hr;
|
|
|
|
Failure:
|
|
|
|
if ( m_pActiveRead != NULL )
|
|
{
|
|
#ifdef WIN95
|
|
m_pActiveRead->SetWin9xOperationPending( FALSE );
|
|
#endif
|
|
m_pActiveRead->DecRef();
|
|
m_pActiveRead = NULL;
|
|
}
|
|
|
|
DecRef();
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::SendData - send data
|
|
//
|
|
// Entry: Pointer to write buffer
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDataPort::SendData"
|
|
|
|
void CDataPort::SendData( CWriteIOData *const pWriteIOData )
|
|
{
|
|
// CWriteIOData *pActiveSend;
|
|
UINT_PTR uIndex;
|
|
DWORD dwByteCount;
|
|
BOOL fWriteFileReturn;
|
|
|
|
|
|
DNASSERT( m_EndpointRefCount != 0 );
|
|
DNASSERT( pWriteIOData->m_DataBuffer.MessageHeader.SerialSignature == SERIAL_HEADER_START );
|
|
DNASSERT( ( pWriteIOData->m_DataBuffer.MessageHeader.MessageTypeToken == SERIAL_DATA_USER_DATA ) ||
|
|
( ( pWriteIOData->m_DataBuffer.MessageHeader.MessageTypeToken & ~( ENUM_RTT_MASK ) ) == SERIAL_DATA_ENUM_QUERY ) ||
|
|
( ( pWriteIOData->m_DataBuffer.MessageHeader.MessageTypeToken & ~( ENUM_RTT_MASK ) )== SERIAL_DATA_ENUM_RESPONSE ) );
|
|
|
|
//
|
|
// check for command cancellation
|
|
//
|
|
if ( pWriteIOData->m_pCommand != NULL )
|
|
{
|
|
pWriteIOData->m_pCommand->Lock();
|
|
switch ( pWriteIOData->m_pCommand->GetState() )
|
|
{
|
|
//
|
|
// command pending, mark as uninterruptable and exit
|
|
//
|
|
case COMMAND_STATE_PENDING:
|
|
{
|
|
pWriteIOData->m_pCommand->SetState( COMMAND_STATE_INPROGRESS_CANNOT_CANCEL );
|
|
pWriteIOData->m_pCommand->Unlock();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// command is being cancelled, indicate command failure
|
|
//
|
|
case COMMAND_STATE_CANCELLING:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// flatten the buffer so it will send faster (no thread transitions from
|
|
// send complete to sending the next chunk).
|
|
//
|
|
dwByteCount = sizeof( pWriteIOData->m_DataBuffer.MessageHeader );
|
|
for ( uIndex = 0; uIndex < pWriteIOData->m_uBufferCount; uIndex++ )
|
|
{
|
|
memcpy( &pWriteIOData->m_DataBuffer.Data[ dwByteCount ],
|
|
pWriteIOData->m_pBuffers[ uIndex ].pBufferData,
|
|
pWriteIOData->m_pBuffers[ uIndex ].dwBufferSize );
|
|
dwByteCount += pWriteIOData->m_pBuffers[ uIndex ].dwBufferSize;
|
|
}
|
|
|
|
DNASSERT( dwByteCount <= MAX_MESSAGE_SIZE );
|
|
|
|
DNASSERT( dwByteCount < 65536 );
|
|
DBG_CASSERT( sizeof( pWriteIOData->m_DataBuffer.MessageHeader.wMessageSize ) == sizeof( WORD ) );
|
|
pWriteIOData->m_DataBuffer.MessageHeader.wMessageSize = static_cast<WORD>( dwByteCount - sizeof( pWriteIOData->m_DataBuffer.MessageHeader ) );
|
|
|
|
DBG_CASSERT( sizeof( pWriteIOData->m_DataBuffer.MessageHeader.wMessageCRC ) == sizeof( WORD ) );
|
|
pWriteIOData->m_DataBuffer.MessageHeader.wMessageCRC = static_cast<WORD>( GenerateCRC( &pWriteIOData->m_DataBuffer.Data[ sizeof( pWriteIOData->m_DataBuffer.MessageHeader ) ], pWriteIOData->m_DataBuffer.MessageHeader.wMessageSize ) );
|
|
|
|
DBG_CASSERT( sizeof( pWriteIOData->m_DataBuffer.MessageHeader.wHeaderCRC ) == sizeof( WORD ) );
|
|
DBG_CASSERT( sizeof( &pWriteIOData->m_DataBuffer.MessageHeader ) == sizeof( BYTE* ) );
|
|
pWriteIOData->m_DataBuffer.MessageHeader.wHeaderCRC = static_cast<WORD>( GenerateCRC( reinterpret_cast<BYTE*>( &pWriteIOData->m_DataBuffer.MessageHeader ),
|
|
( sizeof( pWriteIOData->m_DataBuffer.MessageHeader) - sizeof( pWriteIOData->m_DataBuffer.MessageHeader.wHeaderCRC ) ) ) );
|
|
|
|
|
|
DPFX(DPFPREP, 7, "(0x%p) Writing %u bytes (WriteData 0x%p, command = 0x%p, buffer = 0x%p).",
|
|
this, dwByteCount, pWriteIOData, pWriteIOData->m_pCommand, &(pWriteIOData->m_DataBuffer) );
|
|
|
|
|
|
AddRef();
|
|
|
|
#ifdef WIN95
|
|
m_pSPData->GetThreadPool()->LockWriteData();
|
|
DNASSERT( pWriteIOData->Win9xOperationPending() == FALSE );
|
|
pWriteIOData->SetWin9xOperationPending( TRUE );
|
|
#endif
|
|
DNASSERT( pWriteIOData->jkm_dwOverlappedBytesSent == 0 );
|
|
pWriteIOData->SetDataPort( this );
|
|
|
|
fWriteFileReturn = WriteFile( m_hFile, // file handle
|
|
&pWriteIOData->m_DataBuffer, // buffer to send
|
|
dwByteCount, // bytes to send
|
|
&pWriteIOData->jkm_dwImmediateBytesSent, // pointer to bytes written
|
|
pWriteIOData->Overlap() ); // pointer to overlapped structure
|
|
if ( fWriteFileReturn == FALSE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
//
|
|
// send didn't complete immediately, find out why
|
|
//
|
|
dwError = GetLastError();
|
|
switch ( dwError )
|
|
{
|
|
//
|
|
// Write is queued, no problem. Wait for asynchronous notification.
|
|
//
|
|
case ERROR_IO_PENDING:
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Other problem, stop if not 'known' to see if there's a better
|
|
// error return.
|
|
//
|
|
default:
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem with WriteFile!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
pWriteIOData->jkm_hSendResult = DPNERR_NOCONNECTION;
|
|
|
|
switch ( dwError )
|
|
{
|
|
case ERROR_INVALID_HANDLE:
|
|
{
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// fail the write
|
|
//
|
|
pWriteIOData->DataPort()->SendComplete( pWriteIOData, pWriteIOData->jkm_hSendResult );
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Send completed immediately. Wait for the asynchronous notification.
|
|
//
|
|
}
|
|
|
|
//Exit:
|
|
#ifdef WIN95
|
|
m_pSPData->GetThreadPool()->UnlockWriteData();
|
|
#endif
|
|
// SendData( NULL );
|
|
|
|
return;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::SendComplete - send has completed
|
|
//
|
|
// Entry: Pointer to write data
|
|
// Send result
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDataPort::SendComplete"
|
|
|
|
void CDataPort::SendComplete( CWriteIOData *const pWriteIOData, const HRESULT hSendResult )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DNASSERT( pWriteIOData != NULL );
|
|
#ifdef WIN95
|
|
DNASSERT( pWriteIOData->Win9xOperationPending() == FALSE );
|
|
#endif
|
|
|
|
switch ( pWriteIOData->m_SendCompleteAction )
|
|
{
|
|
case SEND_COMPLETE_ACTION_COMPLETE_COMMAND:
|
|
{
|
|
DPFX(DPFPREP, 8, "Data port 0x%p completing send command 0x%p, hr = 0x%lx, context = 0x%p to interface 0x%p.",
|
|
this, pWriteIOData->m_pCommand, hSendResult,
|
|
pWriteIOData->m_pCommand->GetUserContext(),
|
|
m_pSPData->DP8SPCallbackInterface());
|
|
|
|
hr = IDP8SPCallback_CommandComplete( m_pSPData->DP8SPCallbackInterface(), // pointer to callback interface
|
|
pWriteIOData->m_pCommand, // command handle
|
|
hSendResult, // error code
|
|
pWriteIOData->m_pCommand->GetUserContext() // user context
|
|
);
|
|
|
|
DPFX(DPFPREP, 8, "Data port 0x%p returning from command complete [0x%lx].", this, hr);
|
|
|
|
break;
|
|
}
|
|
|
|
case SEND_COMPLETE_ACTION_NONE:
|
|
{
|
|
if (pWriteIOData->m_pCommand != NULL)
|
|
{
|
|
DPFX(DPFPREP, 8, "Data port 0x%p not completing send command 0x%p, hr = 0x%lx, context = 0x%p.",
|
|
this, pWriteIOData->m_pCommand, hSendResult, pWriteIOData->m_pCommand->GetUserContext() );
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 8, "Data port 0x%p not completing NULL send command, hr = 0x%lx",
|
|
this, hSendResult );
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_pSPData->GetThreadPool()->ReturnWriteIOData( pWriteIOData );
|
|
DecRef();
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CDataPort::ProcessReceivedData - process received data
|
|
//
|
|
// Entry: Count of bytes received
|
|
// Error code
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDataPort::ProcessReceivedData"
|
|
|
|
void CDataPort::ProcessReceivedData( const DWORD dwBytesReceived, const DWORD dwError )
|
|
{
|
|
DNASSERT( m_pActiveRead != NULL );
|
|
DNASSERT( dwBytesReceived <= m_pActiveRead->m_dwBytesToRead );
|
|
|
|
//
|
|
// If this data port is not actively receiving, returnt the active read to
|
|
// the pool. This happens on shutdown and when the modem disconnects.
|
|
//
|
|
if ( GetState() != DATA_PORT_STATE_RECEIVING )
|
|
{
|
|
DPFX(DPFPREP, 7, "Data port 0x%p not receiving, ignoring %u bytes received and err %u.",
|
|
this, dwBytesReceived, dwError );
|
|
|
|
if ( m_pActiveRead != NULL )
|
|
{
|
|
#ifdef WIN95
|
|
m_pActiveRead->SetWin9xOperationPending( FALSE );
|
|
#endif
|
|
m_pActiveRead->DecRef();
|
|
m_pActiveRead = NULL;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
switch ( dwError )
|
|
{
|
|
//
|
|
// ERROR_OPERATION_ABORTED = something stopped operation, stop and look.
|
|
//
|
|
case ERROR_OPERATION_ABORTED:
|
|
{
|
|
DPFX(DPFPREP, 8, "Operation aborted, data port 0x%p, bytes received = %u.",
|
|
this, dwBytesReceived );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// ERROR_SUCCESS = data was received (may be 0 bytes from a timeout)
|
|
//
|
|
case ERROR_SUCCESS:
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
DPFX(DPFPREP, 0, "Failed read!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_pActiveRead->m_dwBytesToRead -= dwBytesReceived;
|
|
if ( m_pActiveRead->m_dwBytesToRead != 0 )
|
|
{
|
|
DPFX(DPFPREP, 7, "Data port 0x%p got %u bytes but there are %u bytes remaining to be read.",
|
|
this, dwBytesReceived, m_pActiveRead->m_dwBytesToRead );
|
|
|
|
m_pSPData->GetThreadPool()->ReinsertInReadList( m_pActiveRead );
|
|
Receive();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// all data has been read, attempt to process it
|
|
//
|
|
switch ( m_pActiveRead->m_ReadState )
|
|
{
|
|
//
|
|
// Header. Check header integrity before proceeding. If the header
|
|
// is bad, attempt to find another header signature and reread.
|
|
//
|
|
case READ_STATE_READ_HEADER:
|
|
{
|
|
WORD wCRC;
|
|
DWORD dwCRCSize;
|
|
|
|
|
|
DPFX(DPFPREP, 9, "Reading header.");
|
|
|
|
DBG_CASSERT( OFFSETOF( MESSAGE_HEADER, SerialSignature ) == 0 );
|
|
dwCRCSize = sizeof( m_pActiveRead->m_ReceiveBuffer.MessageHeader ) - sizeof( m_pActiveRead->m_ReceiveBuffer.MessageHeader.wHeaderCRC );
|
|
wCRC = static_cast<WORD>( GenerateCRC( reinterpret_cast<BYTE*>( &m_pActiveRead->m_ReceiveBuffer.MessageHeader ), dwCRCSize ) );
|
|
if ( ( m_pActiveRead->m_ReceiveBuffer.MessageHeader.SerialSignature != SERIAL_HEADER_START ) ||
|
|
( wCRC != m_pActiveRead->m_ReceiveBuffer.MessageHeader.wHeaderCRC ) )
|
|
{
|
|
DWORD dwIndex;
|
|
|
|
|
|
DPFX(DPFPREP, 1, "Header failed signature or CRC check (%u != %u or %u != %u), searching for next header.",
|
|
m_pActiveRead->m_ReceiveBuffer.MessageHeader.SerialSignature,
|
|
SERIAL_HEADER_START, wCRC,
|
|
m_pActiveRead->m_ReceiveBuffer.MessageHeader.wHeaderCRC);
|
|
|
|
|
|
dwIndex = sizeof( m_pActiveRead->m_ReceiveBuffer.MessageHeader.SerialSignature );
|
|
while ( ( dwIndex < sizeof( m_pActiveRead->m_ReceiveBuffer.MessageHeader ) ) &&
|
|
( m_pActiveRead->m_ReceiveBuffer.ReceivedData[ dwIndex ] != SERIAL_HEADER_START ) )
|
|
{
|
|
dwIndex++;
|
|
}
|
|
|
|
m_pActiveRead->m_dwBytesToRead = dwIndex;
|
|
m_pActiveRead->m_dwReadOffset = sizeof( m_pActiveRead->m_ReceiveBuffer.MessageHeader ) - dwIndex;
|
|
memcpy( &m_pActiveRead->m_ReceiveBuffer.ReceivedData,
|
|
&m_pActiveRead->m_ReceiveBuffer.ReceivedData[ dwIndex ],
|
|
sizeof( m_pActiveRead->m_ReceiveBuffer.MessageHeader ) - dwIndex );
|
|
}
|
|
else
|
|
{
|
|
m_pActiveRead->SetReadState( READ_STATE_READ_DATA );
|
|
m_pActiveRead->m_dwBytesToRead = m_pActiveRead->m_ReceiveBuffer.MessageHeader.wMessageSize;
|
|
m_pActiveRead->m_dwReadOffset = sizeof( m_pActiveRead->m_ReceiveBuffer.MessageHeader );
|
|
}
|
|
|
|
#ifdef WIN95
|
|
m_pActiveRead->SetWin9xOperationPending( FALSE );
|
|
#endif
|
|
m_pActiveRead->jkm_dwOverlappedBytesReceived = 0;
|
|
m_pSPData->GetThreadPool()->ReinsertInReadList( m_pActiveRead );
|
|
Receive();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Reading data. Regardless of the validity of the data, start reading
|
|
// another frame before processing the current data. If the data is
|
|
// valid, send it to a higher layer.
|
|
//
|
|
case READ_STATE_READ_DATA:
|
|
{
|
|
WORD wCRC;
|
|
CReadIOData *pTempRead;
|
|
|
|
|
|
pTempRead = m_pActiveRead;
|
|
m_pActiveRead = NULL;
|
|
Receive();
|
|
|
|
|
|
DPFX(DPFPREP, 7, "Reading regular data.");
|
|
|
|
DNASSERT( pTempRead->m_SPReceivedBuffer.BufferDesc.pBufferData == &pTempRead->m_ReceiveBuffer.ReceivedData[ sizeof( pTempRead->m_ReceiveBuffer.MessageHeader ) ] );
|
|
wCRC = static_cast<WORD>( GenerateCRC( &pTempRead->m_ReceiveBuffer.ReceivedData[ sizeof( pTempRead->m_ReceiveBuffer.MessageHeader ) ],
|
|
pTempRead->m_ReceiveBuffer.MessageHeader.wMessageSize ) );
|
|
if ( wCRC == pTempRead->m_ReceiveBuffer.MessageHeader.wMessageCRC )
|
|
{
|
|
pTempRead->m_SPReceivedBuffer.BufferDesc.dwBufferSize = pTempRead->m_ReceiveBuffer.MessageHeader.wMessageSize;
|
|
|
|
Lock();
|
|
switch ( pTempRead->m_ReceiveBuffer.MessageHeader.MessageTypeToken & ~( ENUM_RTT_MASK ) )
|
|
{
|
|
//
|
|
// User data. Send the data up the connection if there is
|
|
// one, otherwise pass it up the listen.
|
|
//
|
|
case SERIAL_DATA_USER_DATA:
|
|
{
|
|
if ( m_hConnectEndpoint != INVALID_HANDLE_VALUE )
|
|
{
|
|
CEndpoint *pEndpoint;
|
|
|
|
|
|
pEndpoint = m_pSPData->EndpointFromHandle( m_hConnectEndpoint );
|
|
Unlock();
|
|
|
|
if ( pEndpoint != NULL )
|
|
{
|
|
pEndpoint->ProcessUserData( pTempRead );
|
|
pEndpoint->DecCommandRef();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( m_hListenEndpoint != INVALID_HANDLE_VALUE )
|
|
{
|
|
CEndpoint *pEndpoint;
|
|
|
|
|
|
pEndpoint = m_pSPData->EndpointFromHandle( m_hListenEndpoint );
|
|
Unlock();
|
|
|
|
if ( pEndpoint != NULL )
|
|
{
|
|
pEndpoint->ProcessUserDataOnListen( pTempRead );
|
|
pEndpoint->DecCommandRef();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// no endpoint to handle data, drop it
|
|
//
|
|
Unlock();
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Enum query. Send it up the listen.
|
|
//
|
|
case SERIAL_DATA_ENUM_QUERY:
|
|
{
|
|
if ( m_hListenEndpoint != INVALID_HANDLE_VALUE )
|
|
{
|
|
CEndpoint *pEndpoint;
|
|
|
|
|
|
pEndpoint = m_pSPData->EndpointFromHandle( m_hListenEndpoint );
|
|
Unlock();
|
|
|
|
if ( pEndpoint != NULL )
|
|
{
|
|
pEndpoint->ProcessEnumData( &pTempRead->m_SPReceivedBuffer,
|
|
pTempRead->m_ReceiveBuffer.MessageHeader.MessageTypeToken & ENUM_RTT_MASK );
|
|
pEndpoint->DecCommandRef();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// no endpoint to handle data, drop it
|
|
//
|
|
Unlock();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Enum response. Send it up the enum.
|
|
//
|
|
case SERIAL_DATA_ENUM_RESPONSE:
|
|
{
|
|
if ( m_hEnumEndpoint != INVALID_HANDLE_VALUE )
|
|
{
|
|
CEndpoint *pEndpoint;
|
|
|
|
|
|
pEndpoint = m_pSPData->EndpointFromHandle( m_hEnumEndpoint );
|
|
Unlock();
|
|
|
|
if ( pEndpoint != NULL )
|
|
{
|
|
pEndpoint->ProcessEnumResponseData( &pTempRead->m_SPReceivedBuffer,
|
|
pTempRead->m_ReceiveBuffer.MessageHeader.MessageTypeToken & ENUM_RTT_MASK );
|
|
|
|
pEndpoint->DecCommandRef();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// no endpoint to handle data, drop it
|
|
//
|
|
Unlock();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// way busted message!
|
|
//
|
|
default:
|
|
{
|
|
Unlock();
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Data failed CRC check (%u != %u).",
|
|
wCRC, pTempRead->m_ReceiveBuffer.MessageHeader.wMessageCRC);
|
|
}
|
|
|
|
pTempRead->DecRef();
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other state
|
|
//
|
|
default:
|
|
{
|
|
DNASSERT( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
DecRef();
|
|
return;
|
|
}
|
|
//**********************************************************************
|
|
|