diff -r 000000000000 -r d0791faffa3f mtptransports/mtpptpiptransport/ptpipplugin/src/cptpipsockhandlerbase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mtptransports/mtpptpiptransport/ptpipplugin/src/cptpipsockhandlerbase.cpp Tue Feb 02 01:11:40 2010 +0200 @@ -0,0 +1,1008 @@ +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// cptpipsockethandler.cpp +// +// + +/** + @internalComponent +*/ + +#include "cptpipsockhandlerbase.h" +#include "cptpipconnection.h" +#include "ptpippanic.h" + +const TUint32 KPTPIPHeaderSize = 8; +const TUint KMaxPacketSixe = 16; +const TUint64 KMaxPTPIPPacketSize = 0x18FF4; // 100 KB - 12 + +//#define MTP_DEBUG_FLOG_HEX_DUMP + +#define UNUSED_VAR(a) (a)=(a) + +/** +Constructor +*/ +CPTPIPSocketHandlerBase::CPTPIPSocketHandlerBase(CPTPIPConnection& aConnection, TPriority priority ) : + CActive(priority), + iChunkStatus(0), + iSendChunkData(NULL, 0), + iSendData(NULL, 0), + iReceiveChunkData(NULL, 0), + iPTPPacketLength(0), + iState(EIdle), + iPacketBuffer(NULL), + iPacketSizeMax(NULL), + iReceiveData(NULL, 0), + iIsFirstChunk(EFalse), + iPTPPacketLengthReceived(0), + iReceiveDataCommit(EFalse), + iSendHeaderData(NULL, 0), + iPTPIPDataHeader(NULL), + iConnection(aConnection), + iReceiveDataSink(NULL), + iSendDataSource(NULL), + iCurrentChunkData(NULL,0,0) + { + CActiveScheduler::Add(this); + } + + + +/** +Second phase constructor. +*/ +#ifdef __FLOG_ACTIVE +void CPTPIPSocketHandlerBase::ConstructL(const TDesC8& aComponentName) +#else +void CPTPIPSocketHandlerBase::ConstructL() +#endif + { + __FLOG_OPEN(KMTPSubsystem, aComponentName); + __FLOG(_L8("CSocketHandler::ConstructL - Entry")); + iPacketSizeMax = KMaxPacketSixe; + iPacketBuffer.ReAllocL(iPacketSizeMax); + iPTPIPDataHeader = CPTPIPDataContainer::NewL(); + __FLOG(_L8("CSocketHandler::ConstructL - Exit")); + } + + /** + Destructor + */ + CPTPIPSocketHandlerBase::~CPTPIPSocketHandlerBase() + { + __FLOG(_L8("CSocketHandler::~CSocketHandler - Entry")); + Cancel(); + iPacketBuffer.Close(); + iSocket.Close(); + delete iPTPIPDataHeader; + __FLOG(_L8("CSocketHandler::~CSocketHandler - Exit")); + __FLOG_CLOSE; + } + + +// +// CActive Functions +// + +/** + This will be called after every chunk is sent or received over the socket. +*/ +void CPTPIPSocketHandlerBase::RunL() + { + __FLOG(_L8("RunL - Entry")); + __FLOG_VA((_L8("Current State is 0x%08X, and status is %d"), iState, iStatus.Int())); + + switch ( DataStreamDirection() ) + { + case EReceivingState: + + __FLOG_VA((_L8("Receive data completion status = %d"), iStatus.Int())); + if (iState == EReceiveFastInProgress) + { + InitiateFirstChunkReceiveL(); + } + + else if (iStatus != KErrNone) + { + // Abnormal completion. + __FLOG_VA((_L8("PTPIP Error: Receive data completed with error = %d"), iStatus.Int())); + SetState(EReceiveComplete); + } + else if (iState != EReceiveComplete) + { + // Update the chunk data length. We use the iReceiveData variable with the socket + // so only its length gets updated on receive. + + // However during remaining processing we use iReceiveChunkData, so update its len. + iReceiveChunkData.SetLength(iReceiveChunkData.Length() + iReceiveData.Length()); + if (iIsFirstChunk) + { + // process the first chunk. + ProcessFirstReceivedChunkL(); + } + else + { + ResumeReceiveDataStreamL(); + } + } + + if (iState == EReceiveComplete) + { + // Save the pointer to the last populated location on the current chunk + iCurrentChunkData.Set(iReceiveChunkData); + // Reset the receive data stream and notify the connection. + MMTPType& data(*iReceiveDataSink); + ResetReceiveDataStream(); + TRAPD(err, ReceiveDataCompleteL(iStatus.Int(), data)); + if (err != KErrNone) + { + __FLOG_VA((_L8("Framework threw an error from ReceiveDataCompleteL = %d"), err)); + ReceiveDataCompleteL(err, data); + } + } + break; + + case ESendingState: + // Special case for handling the sending of init ack, handled in the derived class. + if (HandleInitAck()) + { + ResetSendDataStream(); + break; + } + + __FLOG_VA((_L8("Send data stream completion status = %d"), iStatus.Int())); + if (iStatus != KErrNone) + { + // Abnormal completion. + SetState(ESendComplete); + } + else + { + ProcessSendDataL(); + } + if (iState == ESendComplete) + { + // Reset the send data stream and notify the connection. + const MMTPType& data(*iSendDataSource); + ResetSendDataStream(); + TRAPD(err, SendDataCompleteL(iStatus.Int(), data)); + if (err != KErrNone) + { + __FLOG_VA((_L8("Framework threw an error from SendDataCompleteL = %d"), err)); + SendDataCompleteL(err, data); + } + } + break; + + case ESendDataState: + if (iStatus != KErrNone) + { + // Abnormal completion. + SetState(ESendDataComplete); + } + else if (iState == ESendingDataHeader) + { + SetState(ESendingDataPacket); + } + else if (iState == ESendingDataPacket) + { + SetState(ESendingDataHeader); + } + else if (iState == ESendDataPacketCompleting) + { + SetState(ESendDataComplete); + } + + if (iState == ESendDataComplete || iState == ESendDataCancelled) + { + // Reset the send data stream and notify the connection. + const MMTPType& data(*iSendDataSource); + ResetSendDataStream(); + SendDataCompleteL(iStatus.Int(), data); + } + else + { + CreateAndSendDataPacketsL(); + } + break; + + default: + + __FLOG_VA((_L8("PTPIP ERROR: Invalid state of the sockethandler: RunL should not be called with 0x%08X state"), iState)); + Panic(EPTPIPBadState); + break; + + }// switch + + __FLOG_VA((_L8("IsActive = %d"), IsActive())); + __FLOG(_L8("RunL - Exit")); + } + +/** +Tell the Asynchronous Service provider to cancel all outstanding operations. +*/ +void CPTPIPSocketHandlerBase::DoCancel() + { + __FLOG(_L8("DoCancel - Entry")); + switch (iState & EStateDirection) + { + case EReceivingState: + __FLOG(_L8("Cancelling receive on the socket")); + iSocket.CancelRecv(); + ResetReceiveDataStream(); + break; + + case ESendingState: + __FLOG(_L8("Cancelling send on the socket")); + iSocket.CancelSend(); + ResetSendDataStream(); + break; + + case ESendDataState: + __FLOG(_L8("Cancelling send on the socket")); + iSocket.CancelSend(); + ResetSendDataStream(); + break; + + default: + break; + } + __FLOG(_L8("DoCancel - Exit")); + } + +/** +This is invoked when a panic occurs during RunL. +To handle this , all operations are cancelled, and if we were processing +a send or recv operation, we complete it with the error code. +@param - The error code with which RunL left +*/ +TInt CPTPIPSocketHandlerBase::RunError(TInt aError) + { + __FLOG(_L8("RunError - Entry")); + __FLOG_VA((_L8("Error reported is %d and state is 0x%08X, and status is %d"), aError, iState, iStatus.Int())); + + // Cancel any outstanding request. + Cancel(); + + // Notify the protocol layer of the error. + TInt32 streamDirection = DataStreamDirection(); + if (streamDirection == EReceivingState) + { + __FLOG(_L8("Error in EReceivingState")); + // Notify the connection and reset the receive data stream. + MMTPType& data(*iReceiveDataSink); + ResetReceiveDataStream(); + TRAPD(err, ReceiveDataCompleteL(aError, data)); + UNUSED_VAR(err); + } + else if (streamDirection == ESendingState || (streamDirection == ESendDataState)) + { + __FLOG(_L8("Error in ESendingState")); + // Notify the connection and reset the send data stream. + const MMTPType& data(*iSendDataSource); + ResetSendDataStream(); + TRAPD(err, SendDataCompleteL(aError, data)); + UNUSED_VAR(err); + } + // We are neither in sending nor receiving state, the error in RunL + // must have originated from the MTP framework, tell the connection + // to stop. + else + { + Connection().HandleError(aError); + } + + __FLOG(_L8("RunError - Exit")); + return KErrNone; + } + +// +// Send Data Functions +// + +/** +This sends the data over the socket. The buffer is provided by the MTP fw. +@param aData - The data buffer to be sent +@param aTransactionId - The id of the current onging transaction. This is needed + in case the data in R to I phase has to be split into multiple PTPIP data packets + In such a case the PTPIP Data packet header needs to be created which contains the tran id. +*/ +void CPTPIPSocketHandlerBase::SendDataL(const MMTPType& aData, TUint32 aTransactionId ) + { + __FLOG(_L8("SendDataL - Entry")); + iSendDataSource = &aData; + TUint64 size = iSendDataSource->Size(); + __FLOG_VA((_L8("Size of total data to be sent = %ld bytes"), size)); + + // if the data is less than KMaxPTPIPPacketSize then it can be sent in a shot, + // Currently the ptp ip packet has the end data packet already, so it can be sent directly. + if ( size < KMaxPTPIPPacketSize) + { + __FLOG(_L8("Size of data is less than KMaxPTPIPPacketSize, sending as one ptpip packet.")); + SetState(ESendInitialising); + ProcessSendDataL(); + } + + // if the data is greater than KMaxPTPIPPacketSize then it needs to be split into + // multiple packets. The PTPIP header will be locally created , and sent + // and then one chunk will be sent as one PTPIP packet. + else + { + __FLOG(_L8("Size of data is more than KMaxPTPIPPacketSize, sending as multiple ptpip packets.")); + iPTPIPDataHeader->SetUint32L(CPTPIPDataContainer::ETransactionId, aTransactionId); + iPTPIPDataHeader->SetPayloadL(NULL); + + // We can ignore this header, since we create our own while sending each packet. + iChunkStatus = iSendDataSource->FirstReadChunk(iSendChunkData); + + SetState(ESendingDataHeader); + CreateAndSendDataPacketsL(); + } + + __FLOG(_L8("SendDataL - Exit")); + } + +/** +Using the same algo as the USB send, to buffer into a local buffer, and sending +only when buffer exceeds the max socket send size, or all chunks have been buffered. +*/ +void CPTPIPSocketHandlerBase::ProcessSendDataL() + { + __FLOG(_L8("ProcessSendDataL - Entry")); + + iSendData.Set(KNullDesC8); + + TUint chunkAvailableLen(iSendChunkData.Length()); + if (!chunkAvailableLen) + { + // Fetch the next read data chunk. + switch (iState) + { + case ESendInitialising: + __FLOG(_L8("Fetching first read data chunk")); + iChunkStatus = iSendDataSource->FirstReadChunk(iSendChunkData); + iPacketBuffer.Zero(); + break; + + case ESendInProgress: + __FLOG(_L8("Fetching next read data chunk")); + iChunkStatus = iSendDataSource->NextReadChunk(iSendChunkData); + break; + + case ESendCompleting: + break; + + case EIdle: + default: + __FLOG(_L8("Invalid send data stream state")); + Panic(EPTPIPBadState); + break; + } + + // Fetch the new chunk data size available. + chunkAvailableLen = iSendChunkData.Length(); + + // Update data stream state. + switch (iChunkStatus) + { + case KErrNone: + SetState(ESendInProgress); + break; + + case KMTPChunkSequenceCompletion: + if (iState == ESendCompleting) + { + SetState(ESendComplete); + } + else + { + SetState(ESendCompleting); + } + break; + + case KErrNotFound:// CMTPTypeFile returns this when it has zero length + if( 0 == iSendChunkData.Length() ) + { + if (iState == ESendCompleting) + { + SetState(ESendComplete); + } + else + { + SetState(ESendCompleting); + } + } + break; + default: + User::Leave(iChunkStatus); + break; + } + } + __FLOG_VA((_L8("Chunk status = %d"), iChunkStatus)); + + // Process the buffered residual and/or available chunk data. + TUint bufferedLen(iPacketBuffer.Length()); + TUint chunkIntegralLen((chunkAvailableLen / iPacketSizeMax) * iPacketSizeMax); + TUint chunkResidualLen(chunkAvailableLen % iPacketSizeMax); + __FLOG_VA((_L8("Buffered residual data = %d bytes"), bufferedLen)); + __FLOG_VA((_L8("Chunk data available = %d bytes"), chunkAvailableLen)); + __FLOG_VA((_L8("Chunk data packet integral portion = %d bytes"), chunkIntegralLen)); + __FLOG_VA((_L8("Chunk data packet residual portion = %d bytes"), chunkResidualLen)); + + if (bufferedLen) + { + // Data is buffered in the packet buffer. Fill the available packet buffer space. + if (chunkAvailableLen) + { + // Fill the packet buffer. + TUint consumedLen(0); + TUint unconsumedLen(0); + TUint capacity(iPacketBuffer.MaxLength() - iPacketBuffer.Length()); + if (chunkAvailableLen > capacity) + { + consumedLen = capacity; + unconsumedLen = (chunkAvailableLen - consumedLen); + } + else + { + consumedLen = chunkAvailableLen; + } + __FLOG_VA((_L8("Buffering %d bytes"), consumedLen)); + iPacketBuffer.Append(iSendChunkData.Left(consumedLen)); + + // Update the available chunk data to reflect only the unconsumed portion. + __FLOG_VA((_L8("Residual chunk data = %d bytes"), unconsumedLen)); + if (unconsumedLen) + { + iSendChunkData.Set(iSendChunkData.Right(unconsumedLen)); + } + else + { + iSendChunkData.Set(NULL, 0); + } + } + + // Send the packet buffer when full. + if ((iState == ESendCompleting) || (iPacketBuffer.Size() == iPacketBuffer.MaxSize())) + { + iSendData.Set(iPacketBuffer); + iPacketBuffer.Zero(); + } + + } + else if (iState == ESendInProgress) + { + // Send the chunk data packet integral portion. + if (chunkIntegralLen) + { + iSendData.Set(iSendChunkData.Left(chunkIntegralLen)); + } + + // Buffer the chunk data packet residual portion. + if (chunkResidualLen) + { + __FLOG_VA((_L8("Buffering %d bytes"), chunkResidualLen)); + iPacketBuffer.Append(iSendChunkData.Right(chunkResidualLen)); + } + + // All data has been consumed and/or buffered. + iSendChunkData.Set(NULL, 0); + } + else if (iState == ESendCompleting) + { + // Send all available chunk data. + iSendData.Set(iSendChunkData); + + // All data has been consumed. + iSendChunkData.Set(NULL, 0); + } + + // Send the available data or reschedule to process the next chunk. + TUint sendBytes(iSendData.Length()); + if (sendBytes) + { + __FLOG_VA((_L8("Send data length = %d bytes"), iSendData.Length())); +#ifdef MTP_DEBUG_FLOG_HEX_DUMP + __FLOG_HEXDUMP((iSendData, _L8("Sending data on socket "))); +#endif + iSocket.Send(iSendData, 0, iStatus); + SetActive(); + __FLOG(_L8("Request issued")); + } + else if (iState != ESendComplete) + { + iStatus = KRequestPending; + CompleteSelf(KErrNone); + } + + __FLOG_VA((_L8("CSocketHandler state on exit = 0x%08X"), iState)); + __FLOG(_L8("ProcessSendDataL - Exit")); + } + + + +/** +first the data header will be sent, +next the packet will be sent. + +in case this is the last chunk, then the data header will have the last data +*/ + +void CPTPIPSocketHandlerBase::CreateAndSendDataPacketsL() + { + __FLOG(_L8("CreateAndSendDataPacketsL - Entry")); + + // Create the data header and prepare to send it. + if (iState == ESendingDataHeader) + { + // if we've received a Cancel, then don't send further packets and return to the connection. + if (iCancelReceived) + { + iState = ESendDataCancelled; + CompleteSelf(KErrNone); + __FLOG(_L8("Sending the PTPIP data ")); + return; + } + else + { + iChunkStatus = iSendDataSource->NextReadChunk(iSendChunkData); + TInt32 size = iPTPIPDataHeader->Size() + iSendChunkData.Size(); + iPTPIPDataHeader->SetUint32L(CPTPIPDataContainer::EPacketLength, size); + __FLOG_VA((_L8("Size of ptpip packet data to be sent = %d bytes"), size)); + + switch (iChunkStatus) + { + case KErrNone: + iPTPIPDataHeader->SetUint32L(CPTPIPDataContainer::EPacketType, EPTPIPPacketTypeData); + break; + + case KMTPChunkSequenceCompletion: + iPTPIPDataHeader->SetUint32L(CPTPIPDataContainer::EPacketType, EPTPIPPacketTypeEndData); + break; + + default: + __FLOG(_L8("PTPIP Error :chunkStatus returned an error")); + User::Leave(iChunkStatus); + break; + } + // Set the iSendData to point to the ptpip header. + TInt ret = iPTPIPDataHeader->FirstReadChunk(iSendData); + } + } + + // Set the iSendData to point to the actual data chunk. + else if (iState == ESendingDataPacket) + { + iSendData.Set(iSendChunkData); + __FLOG(_L8("Sending the PTPIP data ")); + // if this is the last packet then set state. + if (iChunkStatus == KMTPChunkSequenceCompletion) + SetState(ESendDataPacketCompleting); + } + // We exited due to an error condition, + else + { + Panic(EPTPIPBadState); + } + + __FLOG_VA((_L8("Send data length = %d bytes"), iSendData.Length())); +#ifdef MTP_DEBUG_FLOG_HEX_DUMP + __FLOG_HEXDUMP((iSendData, _L8("Sending data on socket "))); +#endif + iSocket.Send(iSendData, 0, iStatus); + SetActive(); + __FLOG(_L8("Request issued")); + __FLOG(_L8("CreateAndSendDataPacketsL - Exit")); + } + + + +/** +Signals tthe data transfer controller that an asynchronous data send sequence +has completed. +@leave One of the system wide error codes, if a processing failure occurs. +@panic EPTPIPNotSupported In debug builds only, if the derived class has not fully +implemented the send data path. +*/ +void CPTPIPSocketHandlerBase::SendDataCompleteL(TInt /*aError*/, const MMTPType& /*aSource*/) + { + __FLOG(_L8("CSocketHandler::SendDataCompleteL - Entry")); + __DEBUG_ONLY(Panic(EPTPIPNotSupported)); + __FLOG(_L8("CSocketHandler::SendDataCompleteL - Exit")); + } + +/** +Forces the completion of a transfer in progress. + +@param aReason error code describing the reason for cancelling. +@leave Any of the system wide error codes. +*/ +void CPTPIPSocketHandlerBase::CancelSendL(TInt aReason) + { + __FLOG(_L8("CSocketHandler::CancelSendL - Entry")); + + if ( (DataStreamDirection() == ESendingState) || (DataStreamDirection() == ESendDataState)) + { + __FLOG(_L8("Cancel in ESendingState")); + // Cancel any outstanding request. + Cancel(); + ResetSendDataStream(); + SendDataCompleteL(aReason, *iSendDataSource); + } + + __FLOG(_L8("CSocketHandler::CancelSendL - Exit")); + } + + +// +// Receive Data Functions +// + +/** +This receives the data over the socket. The data may be event or command data. +The buffer is provided by the fw in case its a data in. +@param aSink The buffer into which the data from initiator will be received. +*/ +void CPTPIPSocketHandlerBase::ReceiveDataL(MMTPType& aSink) + { + __FLOG(_L8("ReceiveDataL - Entry")); + + // Set the state + SetState(EReceiveInProgress); + + // The memory has come from the conection. In case it was a command receive + // then the connection itself had put the memory for the payload + // from its members, + // in case it was a data receive , then the payload buffer was provided by + // the framework. + + iReceiveDataSink = &aSink; + iReceiveDataCommit = iReceiveDataSink->CommitRequired(); + + InitiateFirstChunkReceiveL(); + __FLOG(_L8("ReceiveDataL - Exit")); + } + +/** +Reads the first chunk. Then validates what was read and adjusts the buffer accordingly. +*/ +void CPTPIPSocketHandlerBase::InitiateFirstChunkReceiveL() + { + __FLOG(_L8("InitiateFirstChunkReceiveL - Entry")); + + // sink refers to the buffer from connection. + // Now the ptr iReceiveChunkData is set to it first chunk. + iChunkStatus = iReceiveDataSink->FirstWriteChunk(iReceiveChunkData); + + // The first chunk is going to be read. + iIsFirstChunk = ETrue; + __FLOG_VA((_L8("Receive chunk capacity = %d bytes, length = %d bytes"), iReceiveChunkData.MaxLength(), iReceiveChunkData.Length())); + __FLOG_VA((_L8("Chunk status = %d"), iChunkStatus)); + + iReceiveData.Set(iReceiveChunkData); + + // start the timer. + + // Make the async request to read on the socket and set ourselves active. + // once data is read on the socket, the iStatus will be changed by the comms framework. + iSocket.Recv(iReceiveData, 0, iStatus); +#ifdef MTP_DEBUG_FLOG_HEX_DUMP + __FLOG_HEXDUMP((iReceiveData, _L8("Received data on socket "))); +#endif + + SetActive(); + __FLOG(_L8("Request issued")); + __FLOG(_L8("InitiateFirstChunkReceiveL - Exit")); + } + +/** +The first chunk received will have the length of the data and the ptpip packet type. +Validate the ptp packet type, and set the correct packet type in the generic container. +Set the state to complete or read further depending on the size. +*/ +void CPTPIPSocketHandlerBase::ProcessFirstReceivedChunkL() + { + __FLOG(_L8("ProcessFirstReceivedChunkL - Entry")); + iIsFirstChunk = EFalse; + // Reset the data counter, This will be filled in later in the ResumeReceiveDataStreamL. + iPTPPacketLengthReceived = 0; + iType = EPTPIPPacketTypeUndefined; + + // Parse and get the packet type, and packet length into type and iPTPPacketLength. + // This will also validate that the correct payload is set to get the remaining data. + iType = ParsePTPIPHeaderL(); + + // If the PTPIP type is not one of the standard expected types, + // or not expected in the current transaction phase then we stop further receiving + // This current RunL will + if (EPTPIPPacketTypeUndefined == iType ) + { + __FLOG(_L8("PTPIP ERROR: Unexpected value in the type field of PTPIP header, appears corrupt")); + SetState(EReceiveComplete); + iStatus = KErrCorrupt; + } + + // If there is nothing to receive after the header, possible for probe packet. + else if (KPTPIPHeaderSize == iPTPPacketLength ) + { + SetState(EReceiveComplete); + } + + if (iState == EReceiveComplete) + { +#ifdef MTP_DEBUG_FLOG_HEX_DUMP + __FLOG_HEXDUMP((iReceiveChunkData, _L8("Received data "))); +#endif + + // Commit the received data if required. + if (iReceiveDataCommit) + { + __FLOG(_L8("Commiting write data chunk")); + iReceiveDataSink->CommitChunkL(iReceiveChunkData); + } + } + else + { + ResumeReceiveDataStreamL(); + } + + __FLOG(_L8("ProcessFirstReceivedChunkL - Exit")); + } + + + +/** +Called after the first chunk has been received and we are expecting more packets. +This will be called repeatedly until all the packets have been received. +*/ +void CPTPIPSocketHandlerBase::ResumeReceiveDataStreamL() + { + __FLOG(_L8("ResumeReceiveDataStreamL - Entry")); + TBool endStream(EFalse); + MMTPType *needCommit = NULL; + + // Process the received chunk (if any). + iPTPPacketLengthReceived += iReceiveData.Length(); + __FLOG_VA((_L8("Data received = iPTPPacketLengthReceived = %d bytes, Data expected = iPTPPacketLength = %d"), iPTPPacketLengthReceived, iPTPPacketLength)); + + if (iPTPPacketLengthReceived == iPTPPacketLength) + { + SetState(EReceiveComplete); + endStream = ETrue; + + //if type is data then end stream is not true + if (iType == EPTPIPPacketTypeData) + endStream = EFalse; + } + + __FLOG_VA((_L8("Received = %d bytes, write data chunk capacity = %d bytes"), iReceiveChunkData.Length(), iReceiveChunkData.MaxLength())); +#ifdef MTP_DEBUG_FLOG_HEX_DUMP + __FLOG_HEXDUMP((iReceiveChunkData, _L8("Received data "))); +#endif + + + // Commit the received data if required. + if (iReceiveDataCommit) + { + // if the chunk has been read completely. + // or if the end of stream has been reached. + if (iReceiveChunkData.Length() == iReceiveChunkData.MaxLength() + || endStream ) + { + needCommit = iReceiveDataSink->CommitChunkL(iReceiveChunkData); + } + + + } + + // Fetch the next read data chunk. + switch (iState) + { + case EReceiveInProgress: + + // If we're in the middle of receiving a ptp data packet, + // then at this stage we might have already used some of this chunk. + // so reset its length to previously saved value + if (iUseOffset) + + { + iUseOffset = EFalse; + iReceiveChunkData.Set(iCurrentChunkData); + iChunkStatus = KErrNone; + } + + // get the next chunk only if this chunk has been read completely. + if (iReceiveChunkData.Length() == iReceiveChunkData.MaxLength()) + { + + iChunkStatus = iReceiveDataSink->NextWriteChunk(iReceiveChunkData); + + } + __FLOG_VA((_L8("iReceiveChunkData pointer address is %08x"), iReceiveChunkData.Ptr())); + break; + + case EReceiveComplete: + __FLOG(_L8("Write data chunk sequence complet")); + break; + + case EIdle: + default: + __FLOG(_L8("Invalid stream state")); + Panic(EPTPIPBadState); + break; + } + + __FLOG_VA((_L8("Chunk status = %d"), iChunkStatus)); + + + // If necessary, process the next chunk. + if (iState != EReceiveComplete) + { + __FLOG_VA((_L8("Receive chunk capacity = %d bytes, length = %d bytes"), iReceiveChunkData.MaxLength(), iReceiveChunkData.Length())); + __FLOG_VA((_L8("iReceiveChunkData pointer address is %08x"), iReceiveChunkData.Ptr())); + + + // When we reach the end of receiving a PTPIP packet, it is possible that our PTPIP chunk + // length is greater than the actual data that is expected. + // eg when parameters 1to 5 are not set in a PTPIP request. In this case + // we need to read the remaining length which will be less than the max length of the chunk. + TUint32 remainingLen = iPTPPacketLength - iPTPPacketLengthReceived; + if (remainingLen < (iReceiveChunkData.MaxLength() - iReceiveChunkData.Length())) + { + iReceiveData.Set(const_cast(iReceiveChunkData.Ptr() + iReceiveChunkData.Length()), + 0, + remainingLen); + } + else + { + iReceiveData.Set(const_cast(iReceiveChunkData.Ptr() + iReceiveChunkData.Length()), + 0, + iReceiveChunkData.MaxLength() - iReceiveChunkData.Length()); + } + + + + __FLOG_VA((_L8("Length read this time is= %d"), iReceiveData.MaxLength())); + + + iSocket.Recv(iReceiveData, 0, iStatus); +#ifdef MTP_DEBUG_FLOG_HEX_DUMP + __FLOG_HEXDUMP((iReceiveData, _L8("Received data on socket "))); +#endif + SetActive(); + __FLOG(_L8("Request issued")); + } + if(needCommit != NULL) + { + TPtr8 tmp(NULL, 0, 0); + needCommit->CommitChunkL(tmp); + } + __FLOG(_L8("ResumeReceiveDataStreamL - Exit")); + } + +/** +Signals the data transfer controller that an asynchronous data receive sequence +has completed. +@leave One of the system wide error codes, if a processing failure occurs. +@panic EPTPIPNotSupported In debug builds only, if the derived class has not fully +implemented the receive data path. +*/ +void CPTPIPSocketHandlerBase::ReceiveDataCompleteL(TInt /*aError*/, MMTPType& /*aSink*/) + { + __FLOG(_L8("CSocketHandler::ReceiveDataCompleteL - Entry")); + __DEBUG_ONLY(Panic(EPTPIPNotSupported)); + __FLOG(_L8("CSocketHandler::ReceiveDataCompleteL - Exit")); + } + +/** +Forces the completion of a transfer in progress. + +@param aReason error code describing the reason for cancelling. +@leave Any of the system wide error codes. +*/ +void CPTPIPSocketHandlerBase::CancelReceiveL(TInt aReason) + { + __FLOG(_L8("CSocketHandler::CancelReceiveL - Entry")); + + if (DataStreamDirection() == EReceivingState) + { + __FLOG(_L8("Cancel in EReceivingState")); + // Cancel any outstanding request. + Cancel(); + + // Notify the connection and reset the receive data stream. + ResetReceiveDataStream(); + ReceiveDataCompleteL(aReason, *iReceiveDataSink); + } + + __FLOG(_L8("CSocketHandler::CancelReceiveL - Exit")); + } + +// +// Getters , Setters and other helper functions +// + +CPTPIPConnection& CPTPIPSocketHandlerBase::Connection() + { + return iConnection; + } + +RSocket& CPTPIPSocketHandlerBase::Socket() + { + return iSocket; + } + + +void CPTPIPSocketHandlerBase::ResetSendDataStream() + { + __FLOG(_L8("CSocketHandler::ResetSendDataStream - Entry")); + iSendChunkData.Set(NULL, 0); + iSendData.Set(NULL, 0); + iSendDataSource = NULL; + iCancelReceived = EFalse; + SetState(EIdle); + __FLOG(_L8("CSocketHandler::ResetSendDataStream - Exit")); + } + +void CPTPIPSocketHandlerBase::ResetReceiveDataStream() + { + __FLOG(_L8("CSocketHandler::ResetReceiveDataStream - Entry")); + iReceiveChunkData.Set(NULL, 0, 0); + iReceiveData.Set(NULL, 0, 0); + iReceiveDataSink = NULL; + iCancelReceived = EFalse; + SetState(EIdle); + __FLOG(_L8("CSocketHandler::ResetReceiveDataStream - Exit")); + } + + +void CPTPIPSocketHandlerBase::SetState(TSocketState aState) + { + __FLOG(_L8("SetState - Entry")); + iState = aState; + __FLOG_VA((_L8(" state = 0x%08X"), iState)); + __FLOG(_L8("SetState - Exit")); + } + +void CPTPIPSocketHandlerBase::CompleteSelf(TInt aCompletionCode) + { + SetActive(); + TRequestStatus* stat = &iStatus; + User::RequestComplete(stat, aCompletionCode); + } + +/** +Provides the current data stream direction, sending or receiving +*/ +TInt32 CPTPIPSocketHandlerBase::DataStreamDirection() const + { + return (iState & EStateDirection); + } + +void CPTPIPSocketHandlerBase::SetSocket(RSocket& aSocket) + { + iSocket = aSocket; + } + +/** +Ignore any errors in setting the socket options +*/ +void CPTPIPSocketHandlerBase::SetSocketOptions() + { + TInt error=iSocket.SetOpt(KSoTcpKeepAlive,KSolInetTcp,1); + __FLOG_VA((_L8(" setting the keep alive option returned = %d"), error)); + error=iSocket.SetOpt(KSoTcpNoDelay,KSolInetTcp,1); + __FLOG_VA((_L8(" setting the no delay to disable Nagle's algo returned %d"), error)); + }