/*========================================================================== * * 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( dwByteCount - sizeof( pWriteIOData->m_DataBuffer.MessageHeader ) ); DBG_CASSERT( sizeof( pWriteIOData->m_DataBuffer.MessageHeader.wMessageCRC ) == sizeof( WORD ) ); pWriteIOData->m_DataBuffer.MessageHeader.wMessageCRC = static_cast( 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( GenerateCRC( reinterpret_cast( &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( GenerateCRC( reinterpret_cast( &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( 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; } //**********************************************************************