diff -r 000000000000 -r d0791faffa3f mtpfws/mtpfw/src/cmtpconnection.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mtpfws/mtpfw/src/cmtpconnection.cpp Tue Feb 02 01:11:40 2010 +0200 @@ -0,0 +1,1158 @@ +// Copyright (c) 2006-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: +// + +/** + @file + @internalComponent +*/ + +#include +#include +#include +#include +#include + +#include "cmtpconnection.h" +#include "cmtpconnectionmgr.h" +#include "cmtpdataprovider.h" +#include "cmtpparserrouter.h" +#include "cmtpsession.h" +#include "mmtptransportconnection.h" + +#ifdef MTP_CAPTURE_TEST_DATA +#include "cmtprequestlogger.h" +#endif + +#define UNUSED_VAR(a) (a) = (a) + +__FLOG_STMT(_LIT8(KComponent,"MTPConnection");) + +/** +CMTPConnection panics +*/ +_LIT(KMTPPanicCategory, "CMTPConnection"); +enum TMTPPanicReasons + { + EMTPPanicBusy = 0, + EMTPPanicInvalidSession = 1, + EMTPPanicInvalidState = 2, + EMTPPanicPublishEvent = 3, + }; + +LOCAL_C void Panic(TInt aReason) + { + User::Panic(KMTPPanicCategory, aReason); + } + +/** +CMTPConnection factory method. A pointer to the new CMTPConnection instance is +placed on the cleanup stack. +@param aConnectionId The unique identifier assigned to this connection by the +MTP framework. +@param aTransportConnection The MTP transport layer connection interface to +which the CMTPConnection will bind. +@return Pointer to the new CMTPConnection instance. Ownership IS transfered. +@leave One of the system wide error codes if a processing failure occurs. +*/ +CMTPConnection* CMTPConnection::NewLC(TUint aConnectionId, MMTPTransportConnection& aTransportConnection) + { + CMTPConnection* self = new(ELeave) CMTPConnection(aConnectionId, aTransportConnection); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +/** +Destructor. +*/ +CMTPConnection::~CMTPConnection() + { + __FLOG(_L8("~CMTPConnection - Entry")); + CloseAllSessions(); + + // Remove any events not associated + // with a session + TSglQueIter iter(iEventQ); + iter.SetToFirst(); + CMTPEventLink* link = NULL; + + while ((link = iter++) != NULL) + { + delete link; + } + + if (iTransportConnection != NULL) + { + iTransportConnection->Unbind(*this); + } + iSessions.ResetAndDestroy(); + //close the property + iProperty.Close(); + // delete the ‘name?property + RProcess process; + RProperty::Delete(process.SecureId(), EMTPConnStateKey); + __FLOG(_L8("~CMTPConnection - Exit")); + __FLOG_CLOSE; + } + +/** +Unbinds the Transport Connection +*/ +void CMTPConnection::Unbind(MMTPTransportConnection& /*aConnection*/) + { + iTransportConnection = NULL; + } + +/** +Initiates MTP transaction data phase processing for initiator-to-responder +data flows. This method should only be invoked when the MTP transaction phase +state is ERequestPhase. This is an asynchronous method. +@param aData The MTP data object sink. +@param aRequest The MTP request dataset of the active MTP transaction. +@param aStatus The status used to return asynchronous completion +information regarding the request. +@leave KErrNotFound If the MTP request dataset specifies an invalid SessionID. +@panic CMTPConnection 0 If an asynchronous request is already pending on the +connection. +@panic CMTPConnection 2 If the MTP transaction phase is invalid. +*/ +void CMTPConnection::ReceiveDataL(MMTPType& aData, const TMTPTypeRequest& aRequest, TRequestStatus& aStatus) + { + __FLOG(_L8("ReceiveDataL - Entry")); + iDataReceiveResult = KErrNone; + const TUint KValidPhases(ERequestPhase); + CMTPSession& session(SessionL(aRequest, TMTPTypeRequest::ERequestSessionID)); + + if (ValidFrameworkRequest(&session, KValidPhases, &aStatus)) + { + session.SetTransactionPhase(EDataIToRPhase); + session.SetRequestPending(aStatus); + if(EMTPTypeFile == aData.Type()) + { + ValidateAndPublishConnState(session, State()); + } + + iTransportConnection->ReceiveDataL(aData, aRequest); + } + __FLOG(_L8("ReceiveDataL - Exit")); + } + +/** +Initiates MTP transaction data phase processing for responder-to-initiator +data flows. This method should only be invoked when the MTP transaction phase +state is ERequestPhase. This is an asynchronous method. +@param aData The MTP data object source. +@param aRequest The MTP request dataset of the active MTP transaction. +@param aStatus The status used to return asynchronous completion +information regarding the request. +@leave KErrNotFound If the MTP request dataset specifies an invalid SessionID. +@panic CMTPConnection 0 If an asynchronous request is already pending on the +connection. +@panic CMTPConnection 2 If the MTP transaction phase is invalid. +*/ +void CMTPConnection::SendDataL(const MMTPType& aData, const TMTPTypeRequest& aRequest, TRequestStatus& aStatus) + { + __FLOG(_L8("SendDataL - Entry")); +#ifdef MTP_CAPTURE_TEST_DATA + iRequestLogger->WriteDataPhaseL(aData, EDataRToIPhase); +#endif + + const TUint KValidPhases(ERequestPhase); + CMTPSession& session(SessionL(aRequest, TMTPTypeRequest::ERequestSessionID)); + + if (ValidFrameworkRequest(&session, KValidPhases, &aStatus)) + { + session.SetTransactionPhase(EDataRToIPhase); + session.SetRequestPending(aStatus); + if(EMTPTypeFile == aData.Type()) + { + //In this case we should validate the state based on transaction phase then + //publish the connection state info to the subscriber. + ValidateAndPublishConnState(session, State()); + } + iTransportConnection->SendDataL(aData, aRequest); + } + __FLOG(_L8("SendDataL - Exit")); + } + +/** +Sends an MTP event dataset. +@param aEvent The MTP event dataset source. +@leave KErrNotFound If the MTP event dataset specifies an invalid SessionID. +*/ +void CMTPConnection::SendEventL(const TMTPTypeEvent& aEvent) + { + __FLOG(_L8("SendEventL - Entry")); + const TUint KValidPhases(EIdlePhase | ERequestPhase | EDataIToRPhase| EDataRToIPhase | EResponsePhase | ECompletingPhase); + if (ValidFrameworkRequest(NULL, KValidPhases, NULL)) + { + // Validate the SessionID + TUint32 sessionId(aEvent.Uint32(TMTPTypeEvent::EEventSessionID)); + if (sessionId != KMTPSessionAll) + { + User::LeaveIfError(iSessions.FindInOrder(sessionId, SessionOrder)); + } + + + EnqueueEvent(new (ELeave) CMTPEventLink(aEvent)); + if (iPendingEventCount == 1) + { + // Forward the event to the transport connection layer. + iTransportConnection->SendEventL(iEventQ.First()->iEvent); + } + } + __FLOG(_L8("SendEventL - Exit")); + } + +/** +Initiates MTP transaction response phase processing. This method should only +be invoked when the MTP transaction phase state is either ERequestPhase, or +EResponsePhase. This is an asynchronous method. +@param aResponse The MTP response dataset source. +@param aRequest The MTP request dataset of the active MTP transaction. +@param aStatus The status used to return asynchronous completion +information regarding the request. +@leave KErrNotFound If the MTP response dataset specifies an invalid SessionID. +@leave KErrArgument If the MTP response dataset does not match the specified +request dataset. +@panic CMTPConnection 0 If an asynchronous request is already pending on the +connection. +@panic CMTPConnection 2 If the MTP transaction phase is invalid. +*/ +void CMTPConnection::SendResponseL(const TMTPTypeResponse& aResponse, const TMTPTypeRequest& aRequest, TRequestStatus& aStatus) + { + __FLOG(_L8("SendResponseL - Entry")); +#ifdef MTP_CAPTURE_TEST_DATA + // Running under debug capture mode save this request off to disk. + iRequestLogger->LogResponseL(aResponse); +#endif + + const TUint KValidPhases(ERequestPhase | EResponsePhase ); + CMTPSession& session(SessionL(aResponse, TMTPTypeResponse::EResponseSessionID)); + + if (ValidFrameworkRequest(&session, KValidPhases, &aStatus)) + { + if ((aResponse.Uint32(TMTPTypeResponse::EResponseSessionID) != aRequest.Uint32(TMTPTypeRequest::ERequestSessionID)) || + (aResponse.Uint32(TMTPTypeResponse::EResponseTransactionID) != aRequest.Uint32(TMTPTypeRequest::ERequestTransactionID))) + { + /* + Request/Response mismatch by the originating data provider plug-in. + Fail the transport connection to avoid leaving the current + transaction irrecoverably hanging. + */ + UnrecoverableMTPError(); + User::Leave(KErrArgument); + } + + if (session.TransactionPhase() == ERequestPhase) + { + // Transaction has no data phase. + session.SetTransactionPhase(EResponsePhase); + } + + session.SetRequestPending(aStatus); + + iTransportConnection->SendResponseL(aResponse, aRequest); + } + __FLOG(_L8("SendResponseL - Exit")); + } + +/** +Deletes the session object assigned to the specified session and notifies all +loaded data providers. +@param aMTPId The session identifier assigned by the MTP connection +initiator. +@leave KErrNotFound, if a session with the specified SessionMTPId is not +found. +@leave One of the system wide error codes, if a general processing failure +occurs. +*/ +EXPORT_C void CMTPConnection::SessionClosedL(TUint32 aMTPId) + { + __FLOG(_L8("SessionClosedL - Entry")); + if(0x0FFFFFFF != aMTPId) + { + TInt idx(iSessions.FindInOrder(aMTPId, SessionOrder)); + __ASSERT_DEBUG((idx != KErrNotFound), Panic(EMTPPanicInvalidSession)); + CloseSession(idx); + } + else + { + CMTPSession* session = NULL; + for(TInt i =0;iSessionMTPId()); + if(0 != id) + { + SessionClosedL(id); + } + session = NULL; + } + } + __FLOG(_L8("SessionClosedL - Exit")); + } + +/** +Creates a new session object for the specified session and notifies all loaded +data providers. The session is known by two identifiers: + 1. SessionMTPId - Assigned by the MTP connection initiator and unique only + to the MTP connection on which the session was opened. In a multiple- + connection configuration this identifier may not uniquely identify the + session. + 2. SessionUniqueId - Assigned by the MTP daemon and guaranteed to uniquely + identify the session in a multiple-connection configuration. +Currently the MTP daemon does not support multiple-connection configuration +and both identifiers are assigned the same value. +@param aMTPId The session identifier assigned by the MTP connection +initiator. +@leave KErrAlreadyExists, if a session with the specified SessionMTPId is +already open. +@leave One of the system wide error codes, if a general processing failure +occurs. +*/ +EXPORT_C void CMTPConnection::SessionOpenedL(TUint32 aMTPId) + { + __FLOG(_L8("SessionOpenedL - Entry")); + // Validate the SessionID + if (SessionWithMTPIdExists(aMTPId)) + { + User::Leave(KErrAlreadyExists); + } + + // Create a new session object + CMTPSession* session = CMTPSession::NewLC(aMTPId, aMTPId); + session->SetTransactionPhase(EIdlePhase); + iSessions.InsertInOrder(session, CMTPConnection::SessionOrder); + CleanupStack::Pop(session); + + if (aMTPId != KMTPSessionNone) + { + // Notify the data providers if other than the null session is closing. + TMTPNotificationParamsSessionChange params = {aMTPId, *this}; + iSingletons.DpController().NotifyDataProvidersL(EMTPSessionOpened, ¶ms); + } + __FLOG(_L8("SessionOpenedL - Exit")); + } + +/* + * Signals the connection is suspended, the connection state is set to EStateShutdown which + * means that all the current transaction will not be able to send/receive any data via the + * connection + */ +void CMTPConnection::ConnectionSuspended() + { + __FLOG(_L8("ConnectionSuspended - Entry")); + + TUint currentState = State(); + if (currentState!=EStateShutdown && currentState!=EStateErrorShutdown) + { + SetState(EStateShutdown); + + if (iTransportConnection != NULL) + { + iTransportConnection->Unbind(*this); + iTransportConnection = NULL; + } + PublishConnState(EDisconnectedFromHost); + + if (ActiveSessions() == 0) + { + CloseAllSessions(); + iSessions.Reset(); + iSingletons.Close(); + } + else + { + //some session may be in data or response phase, complete them and set transaction phase to ECompletingPhase. + const TUint count(iSessions.Count()); + for (TUint i(0); (i < count); i++) + { + if (iSessions[i]->TransactionPhase() & (EDataIToRPhase|EDataRToIPhase|EResponsePhase)) + { + iSessions[i]->SetTransactionPhase(ECompletingPhase); + iSessions[i]->CompletePendingRequest(KErrCancel); + } + } + } + } + + __FLOG(_L8("ConnectionSuspended - Exit")); + } + +/* + * Signals that the connection is resumed to EStateOpen state which means that data providers + * can receive requests from host again. + * @aTransportConnection The new transport connection object + * @leave One of the system wide error codes, if a processing failure occurs. + */ +void CMTPConnection::ConnectionResumedL(MMTPTransportConnection& aTransportConnection) + { + __FLOG(_L8("ConnectionResumed - Entry")); + + TUint currentState = State(); + if (currentState != EStateOpen && currentState != EStateErrorRecovery) + { + iSingletons.OpenL(); + + /* + Create the null session object which owns the transaction state for + transaction occuring outside a session (i.e. with SessionID == 0x00000000) + */ + SessionOpenedL(KMTPSessionNone); + + iTransportConnection = &aTransportConnection; + iTransportConnection->BindL(*this); + SetState(EStateOpen); + PublishConnState(EConnectedToHost); + } + + __FLOG(_L8("ConnectionResumed - Exit")); + } + +/** +Signals the completion of the current transaction processing sequence. This +method should only be invoked when the MTP transaction phase state is +ECompletingPhase. +@param aRequest The MTP request dataset of the completed MTP transaction. +@leave KErrNotFound If the MTP request dataset specifies an invalid SessionID. +@panic CMTPConnection 2 If the MTP transaction phase is invalid. +*/ +void CMTPConnection::TransactionCompleteL(const TMTPTypeRequest& aRequest) + { + __FLOG(_L8("TransactionCompleteL - Entry")); + const TUint KValidPhases(ECompletingPhase); + CMTPSession& session(SessionL(aRequest, TMTPTypeRequest::ERequestSessionID)); + + if (ValidFrameworkRequest(&session, KValidPhases, NULL)) + { + session.SetTransactionPhase(EIdlePhase); + if (State() == EStateShutdown) + { + if (ActiveSessions() == 0) + { + CloseAllSessions(); + iSessions.Reset(); + iSingletons.Close(); + + // Move the log here because ShutdownComplete will delete this object. + __FLOG(_L8("TransactionCompleteL - Exit")); + } + } + else + { + iTransportConnection->TransactionCompleteL(aRequest); + __FLOG(_L8("TransactionCompleteL - Exit")); + } + } + } + +TUint CMTPConnection::ConnectionId() const + { + return iConnectionId; + } + +TUint CMTPConnection::SessionCount() const + { + return iSessions.Count(); + } + +TBool CMTPConnection::SessionWithMTPIdExists(TUint32 aMTPId) const + { + return (iSessions.FindInOrder(aMTPId, SessionOrder) != KErrNotFound); + } + +MMTPSession& CMTPConnection::SessionWithMTPIdL(TUint32 aMTPId) const + { + TInt idx(iSessions.FindInOrder(aMTPId, SessionOrder)); + User::LeaveIfError(idx); + return *iSessions[idx]; + } + +TBool CMTPConnection::SessionWithUniqueIdExists(TUint32 aUniqueId) const + { + return SessionWithMTPIdExists(aUniqueId); + } + +MMTPSession& CMTPConnection::SessionWithUniqueIdL(TUint32 aUniqueId) const + { + return SessionWithMTPIdL(aUniqueId); + } + +void CMTPConnection::ReceivedEventL(const TMTPTypeEvent& aEvent) + { + __FLOG(_L8("ReceivedEventL - Entry")); + TInt idx(KErrNotFound); + + // Validate the SessionID. + TUint32 sessionId(aEvent.Uint32(TMTPTypeEvent::EEventSessionID)); + if (sessionId != KMTPSessionAll) + { + idx = iSessions.FindInOrder(sessionId, SessionOrder); + User::LeaveIfError(idx); + } + + // Check that this event is valid. + CMTPSession& session(*iSessions[idx]); + + TMTPTypeRequest request; + TRAPD( err, MMTPType::CopyL(session.ActiveRequestL(), request) ); + + + if( err == KErrNotFound ) + { + session.StorePendingEventL(aEvent); + } + else + { + if (request.Uint32(TMTPTypeRequest::ERequestTransactionID) > + aEvent.Uint32(TMTPTypeEvent::EEventTransactionID) ) + { + // Event to be queued for future use, we can only queue one event at a time + session.StorePendingEventL(aEvent); + } + + if (request.Uint32(TMTPTypeRequest::ERequestTransactionID) == + aEvent.Uint32(TMTPTypeEvent::EEventTransactionID) ) + { + // Event is valid + // Perform transport layer processing. + if (aEvent.Uint16(TMTPTypeEvent::EEventCode) == EMTPEventCodeCancelTransaction) + { + if (sessionId == KMTPSessionAll) + { + const TUint noSessions = iSessions.Count(); + for (TUint i(0); (i < noSessions); i++) + { + InitiateTransactionCancelL(i); + } + } + else + { + InitiateTransactionCancelL(idx); + } + } + + // Forward the event to the DP framework layer. + iSingletons.Router().ProcessEventL(aEvent, *this); + } + } + __FLOG(_L8("ReceivedEventL - Exit")); + } + +void CMTPConnection::ReceivedRequestL(const TMTPTypeRequest& aRequest) + { + __FLOG(_L8("ReceivedRequestL - Entry")); +#ifdef MTP_CAPTURE_TEST_DATA + // Running under debug capture mode save this request off to disk. + iRequestLogger->LogRequestL(aRequest); +#endif + + // Resolve the session + TInt idx(iSessions.FindInOrder(aRequest.Uint32(TMTPTypeRequest::ERequestSessionID), SessionOrder)); + + // Process the request. + if (idx == KErrNotFound) + { + // Invalid SessionID + InitiateMTPErrorRecoveryL(aRequest, EMTPRespCodeSessionNotOpen); + } + else + { + CMTPSession& session(*iSessions[idx]); + + if (session.TransactionPhase() != EIdlePhase) + { + // Initiator violation of the MTP transaction protocol. + UnrecoverableMTPError(); + } + else + { + // Set the session state + session.IncrementExpectedTransactionId(); + session.SetTransactionPhase(ERequestPhase); + session.SetActiveRequestL(aRequest); + + // Forward the request to the DP framework layer. + TRAPD(err,iSingletons.Router().ProcessRequestL(session.ActiveRequestL(), *this)); + if(err!=KErrNone) + { + session.SetTransactionPhase(EIdlePhase); + User::Leave(err); + } + } + } + __FLOG(_L8("ReceivedRequestL - Exit")); + } + +#ifdef MTP_CAPTURE_TEST_DATA +void CMTPConnection::ReceiveDataCompleteL(TInt aErr, const MMTPType& aData, const TMTPTypeRequest& aRequest) +#else +void CMTPConnection::ReceiveDataCompleteL(TInt aErr, const MMTPType& aData, const TMTPTypeRequest& aRequest) +#endif + { + __FLOG(_L8("ReceiveDataCompleteL - Entry")); + CMTPSession& session(SessionL(aRequest, TMTPTypeRequest::ERequestSessionID)); + __ASSERT_DEBUG((session.TransactionPhase() == EDataIToRPhase), Panic(EMTPPanicInvalidState)); + + if(EMTPTypeFile == aData.Type()) + { + //All data transfer is over now we can publish that + //state is connected to host or idle + PublishConnState(EConnectedToHost); + } +#ifdef MTP_CAPTURE_TEST_DATA + iRequestLogger->WriteDataPhaseL(aData, EDataIToRPhase); +#endif + + session.SetTransactionPhase(EResponsePhase); + iDataReceiveResult = aErr; + session.CompletePendingRequest(aErr); + + __FLOG(_L8("ReceiveDataCompleteL - Exit")); + } + +void CMTPConnection::SendDataCompleteL(TInt aErr, const MMTPType& aData, const TMTPTypeRequest& aRequest) + { + __FLOG(_L8("SendDataCompleteL - Entry")); + CMTPSession& session(SessionL(aRequest, TMTPTypeRequest::ERequestSessionID)); + __ASSERT_DEBUG((session.TransactionPhase() == EDataRToIPhase), Panic(EMTPPanicInvalidState)); + + session.SetTransactionPhase(EResponsePhase); + + if(EMTPTypeFile == aData.Type()) + { + //All data transfer is over now we can publish that + //state is connected to host or idle + PublishConnState(EConnectedToHost); + } + + session.CompletePendingRequest(aErr); + + __FLOG(_L8("SendDataCompleteL - Exit")); + } + +void CMTPConnection::SendEventCompleteL(TInt aErr, const TMTPTypeEvent& aEvent) + { + __FLOG(_L8("SendEventCompleteL - Entry")); + + + if (aErr != KErrNone) + { + UnrecoverableMTPError(); + } + else if (aEvent.Uint16(TMTPTypeEvent::EEventCode) == EMTPEventCodeCancelTransaction) + { + TUint32 sessionId(aEvent.Uint32(TMTPTypeEvent::EEventSessionID)); + TInt idx(KErrNotFound); + if (sessionId == KMTPSessionAll) + { + const TUint noSessions = iSessions.Count(); + for (TUint i(0); (i < noSessions); i++) + { + InitiateTransactionCancelL(i); + } + } + else + { + idx = iSessions.FindInOrder(sessionId, SessionOrder); + InitiateTransactionCancelL(idx); + } + } + // Dequeue first since the code below might leave. + DequeueEvent(iEventQ.First()); + if (iPendingEventCount > 0) + { + // Forward the event to the transport connection layer. + __FLOG(_L8("Sending queued event")); + iTransportConnection->SendEventL(iEventQ.First()->iEvent); + } + + __FLOG(_L8("SendEventCompleteL - Exit")); + } + +void CMTPConnection::SendResponseCompleteL(TInt aErr, const TMTPTypeResponse& /*aResponse*/, const TMTPTypeRequest& aRequest) + { + __FLOG(_L8("SendResponseCompleteL - Entry")); + if(iState == EStateErrorRecovery) + { + MTPErrorRecoveryComplete(); + iTransportConnection->TransactionCompleteL(aRequest); + } + else{ + CMTPSession& session(SessionL(aRequest, TMTPTypeRequest::ERequestSessionID)); + __ASSERT_DEBUG((session.TransactionPhase() == EResponsePhase), Panic(EMTPPanicInvalidState)); + session.SetTransactionPhase(ECompletingPhase); + session.CompletePendingRequest(aErr); + } + __FLOG(_L8("SendResponseCompleteL - Exit")); + } + + +TMTPTransactionPhase CMTPConnection::TransactionPhaseL(TUint32 aMTPId) const + { + TInt idx(iSessions.FindInOrder(aMTPId, SessionOrder)); + User::LeaveIfError(idx); + return iSessions[idx]->TransactionPhase(); + } + +/** +Constructor. +*/ +CMTPConnection::CMTPConnection(TUint aConnectionId, MMTPTransportConnection& aTransportConnection) : + iConnectionId(aConnectionId), + iEventQ(_FOFF(CMTPEventLink, iLink)), + iTransportConnection(&aTransportConnection) + { + + } + +/** +Second phase constructor. +@leave One of the system wide error code, if a processing failure occurs. +*/ +void CMTPConnection::ConstructL() + { + __FLOG_OPEN(KMTPSubsystem, KComponent); + __FLOG(_L8("ConstructL - Entry")); + //define the property for publishing connection state. + DefineConnStatePropertyL(); + PublishConnState(EDisconnectedFromHost); +#ifdef MTP_CAPTURE_TEST_DATA + // Running under debug capture mode save this request off to disk. + iRequestLogger = CMTPRequestLogger::NewL(); +#endif + __FLOG(_L8("ConstructL - Exit")); + } + +/** +Initiates an MTP connection level protocol error recovery sequence. This +sequence is invoked when a recoverable protocol error is detected that cannot +be processed above the connection layer, e.g. when a request is made on a +non-existant SessionID, or an out-of-sequence TransactionID is detected. An +appropriate MTP response dataset is formed and sent to the MTP initiator. The +error recovery sequence is concluded by MTPErrorRecoveryComplete when the +connection transport layer signals SendResponseComplete to the MTP connection +protocol layer. +@param aRequest The MTP request dataset of the erroneous MTP transaction. +@param aResponseCode The MTP response datacode to be returned to the MTP +initiator. +@leave One of the system wide error codes, if a processing failure occurs. +@see MTPErrorRecoveryComplete +*/ +void CMTPConnection::InitiateMTPErrorRecoveryL(const TMTPTypeRequest& aRequest, TUint16 aResponseCode) + { + __FLOG(_L8("InitiateMTPErrorRecoveryL - Entry")); + // Populate error response. + iResponse.Reset(); + iResponse.SetUint16(TMTPTypeResponse::EResponseCode, aResponseCode); + iResponse.SetUint32(TMTPTypeResponse::EResponseSessionID, aRequest.Uint32(TMTPTypeRequest::ERequestSessionID)); + iResponse.SetUint32(TMTPTypeResponse::EResponseTransactionID, aRequest.Uint32(TMTPTypeRequest::ERequestTransactionID)); + + // Set the connection state pending completion, and send the response. + SetState(EStateErrorRecovery); + iTransportConnection->SendResponseL(iResponse, aRequest); + __FLOG(_L8("InitiateMTPErrorRecoveryL - Exit")); + } + +/** +Concludes an MTP connection level protocol error recovery sequence. +@see InitiateMTPErrorRecoveryL +*/ +void CMTPConnection::MTPErrorRecoveryComplete() + { + __FLOG(_L8("MTPErrorRecoveryComplete - Entry")); + SetState(EStateOpen); + PublishConnState(EConnectedToHost); + __FLOG(_L8("MTPErrorRecoveryComplete - Exit")); + } + +/** +Forces the immediate shutdown of the MTP connection. This is invoked when a +protocol error is detected that cannot be recovered from, e.g. if an attempt +is detected to initiate an MTP transaction before a previous transaction has +concluded. +*/ +void CMTPConnection::UnrecoverableMTPError() + { + __FLOG(_L8("UnrecoverableMTPError - Entry")); + SetState(EStateErrorShutdown); + PublishConnState(EDisconnectedFromHost); + iTransportConnection->CloseConnection(); + __FLOG(_L8("UnrecoverableMTPError - Entry")); + } + +/** +Signals the MTP connection transport to terminate any in-progress data phase +processing on the specified session. +@param aidx The sessions table index of the required session. +@leave One of the system wide error codes, if a processing failure occurs. +*/ +void CMTPConnection::InitiateTransactionCancelL(TInt aIdx) + { + __FLOG(_L8("InitiateTransactionCancelL - Entry")); + // Initiate transport connection level termination of the active data phase. + CMTPSession& session(*iSessions[aIdx]); + + switch (session.TransactionPhase()) + { + case EIdlePhase: + case ECompletingPhase: + case ERequestPhase: + break; + + case EDataIToRPhase: + iTransportConnection->ReceiveDataCancelL(session.ActiveRequestL()); + break; + + case EResponsePhase: + case EDataRToIPhase: + iTransportConnection->SendDataCancelL(session.ActiveRequestL()); + break; + } + __FLOG(_L8("InitiateTransactionCancelL - Exit")); + } + +/** +Provides a count of the number of sessions with transactions in-progress. +*/ +TUint CMTPConnection::ActiveSessions() const + { + __FLOG(_L8("ActiveSessions - Entry")); + TUint active(0); + const TUint count(iSessions.Count()); + for (TUint i(0); (i < count); i++) + { + if (iSessions[i]->TransactionPhase() > EIdlePhase) + { + active++; + } + } + __FLOG_VA((_L8("Active sessions = %d"), active)); + __FLOG(_L8("ActiveSessions - Exit")); + return active; + } + +/** +Closes all sessions which have been opened on the connection. +*/ +void CMTPConnection::CloseAllSessions() + { + __FLOG(_L8("CloseAllSessions - Entry")); + + TInt count = iSessions.Count(); + __FLOG_VA((_L8("Sessions number to be closed = %d"), count)); + for (TInt i(count - 1); i>=0; i--) + { + CloseSession(i); + } + + __FLOG(_L8("CloseAllSessions - Exit")); + } + +/** +Closes the sessions with the specified session index. +@param aIdx The session index. +*/ +void CMTPConnection::CloseSession(TUint aIdx) + { + __FLOG(_L8("CloseSession - Entry")); + + __FLOG_VA((_L8("Session index to be closed = %d"), aIdx)); + CMTPSession* session(iSessions[aIdx]); + + TUint id(session->SessionMTPId()); + if (id != KMTPSessionNone) + { + // Notify the data providers if other than the null session is closing. + TMTPNotificationParamsSessionChange params = {id, *this}; + TRAPD(err, iSingletons.DpController().NotifyDataProvidersL(EMTPSessionClosed, ¶ms)); + UNUSED_VAR(err); + } + + // Remove any queued events for session + RemoveEventsForSession(id); + + // Delete the session object. + iSessions.Remove(aIdx); + delete session; + + __FLOG(_L8("CloseSession - Exit")); + } + +/** +Provides a reference to the session with the MTP connection assigned identifier +specified in the supplied MTP dataset. +@param aDataset The MTP dataset. +@param aSessionIdElementNo The element number in the MTP dataset of the MTP +connection assigned identifier. +@leave KErrNotFound If the specified session identifier is not currently +active on the connection. +@return The reference of the session with the specified MTP connection +assigned identifier. +*/ +CMTPSession& CMTPConnection::SessionL(const TMTPTypeFlatBase& aDataset, TInt aSessionIdElementNo) const + { + return static_cast(SessionWithMTPIdL(aDataset.Uint32(aSessionIdElementNo))); + } + +/** +Implements an order relation for CMTPSession objects based on relative MTP +connection assigned session IDs. +@param aL The first MTP connection assigned session ID. +@param aR The second object. +@return Zero, if the two objects are equal; a negative value, if the aFirst +is less than aSecond, or; a positive value, if the aFirst is greater than +aSecond. +*/ +TInt CMTPConnection::SessionOrder(const TUint32* aL, const CMTPSession& aR) + { + return *aL - aR.SessionMTPId(); + } + +/** +Implements a TLinearOrder relation for CMTPSession objects based on relative +MTP connection assigned session IDs. +@param aL The first object. +@param aR The second object. +@return Zero, if the two objects are equal; a negative value, if the first +object is less than second, or; a positive value, if the first object is +greater than the second. +*/ +TInt CMTPConnection::SessionOrder(const CMTPSession& aL, const CMTPSession& aR) + { + return aL.SessionMTPId() - aR.SessionMTPId(); + } + +/** +Get the data receive result. +@return the data recevice result. +*/ +EXPORT_C TInt CMTPConnection::GetDataReceiveResult() const + { + __FLOG(_L8("GetDataReceiveResult - Entry")); + __FLOG_VA((_L8("Data receive result = %d"), iDataReceiveResult)); + __FLOG(_L8("GetDataReceiveResult - Exit")); + return iDataReceiveResult; + } + +/** +Sets the MTP connection state variable. +@param aState The new MTP connection state value. +*/ +void CMTPConnection::SetState(TUint aState) + { + __FLOG(_L8("SetState - Entry")); + __FLOG_VA((_L8("Setting state = %d"), aState)); + iState = aState; + __FLOG(_L8("SetState - Exit")); + } + + +/** +Provide the current MTP connection state. +@return The current MTP connection state. +*/ +TUint CMTPConnection::State() const + { + __FLOG(_L8("State - Entry")); + __FLOG_VA((_L8("State = %d"), iState)); + __FLOG(_L8("State - Exit")); + return iState; + } + +/** +Performs common validation processing for requests initiated from the data +provider framework layer. The following validation checks are performed. + 1. Attempt to initiate concurrent asynchronous requests to the same + connection. This will result in a panic. + 2. Attempt to initiate a request that is invalid for the current + transaction phase. This will result in a panic. + 3. Attempt to initiate a request when the connection is in an + unrecoverable error shutdown mode. This will result in the immediate + cancellation of the request. +@return ETrue if the request is valid to proceed, otherwise EFalse. +@panic CMTPConnection 0 If an asynchronous request is already pending on the +connection. +@panic CMTPConnection 2 If the MTP transaction phase is invalid. +*/ +TBool CMTPConnection::ValidFrameworkRequest(CMTPSession* aSession, TUint aValidPhases, TRequestStatus* aStatus) + { + __FLOG(_L8("ValidFrameworkRequest - Entry")); + __ASSERT_ALWAYS((!aSession || (aSession->TransactionPhase() & aValidPhases)), Panic(EMTPPanicInvalidState)); + __ASSERT_ALWAYS((!aStatus || (!aSession->RequestPending())), Panic(EMTPPanicBusy)); + + TBool ret(ETrue); + switch (State()) + { + case EStateUnknown: + case EStateErrorRecovery: + default: + Panic(EMTPPanicInvalidState); + break; + + case EStateOpen: + break; + + case EStateShutdown: + case EStateErrorShutdown: + // Shutdown in progress. + if (aSession != NULL) //Transaction is still alive during shutdown + { + ret = (aSession->TransactionPhase() == ECompletingPhase); + aSession->SetTransactionPhase(ECompletingPhase); + PublishConnState(EDisconnectedFromHost); + if (aStatus) + { + User::RequestComplete(aStatus, KErrCancel); + } + } + else //SendEventL happens during shutdown + { + ret = EFalse; + } + break; + } + + __FLOG(_L8("ValidFrameworkRequest - Exit")); + return ret; + } + +void CMTPConnection::RemoveEventsForSession(TUint32 aMTPId) + { + __FLOG(_L8("RemoveEventsForSession - Entry")); + + TSglQueIter iter(iEventQ); + iter.SetToFirst(); + CMTPEventLink* link = NULL; + + while ((link = iter++) != NULL) + { + if (link->iEvent.Uint32(TMTPTypeEvent::EEventSessionID) == aMTPId) + { + DequeueEvent(link); + } + } + + __FLOG(_L8("RemoveEventsForSession - Exit")); + } + +void CMTPConnection::DequeueEvent(CMTPEventLink* aLink) + { + iEventQ.Remove(*aLink); + delete aLink; + --iPendingEventCount; + } + +void CMTPConnection::EnqueueEvent(CMTPEventLink* aLink) + { + iEventQ.AddLast(*aLink); + ++iPendingEventCount; + } + +CMTPConnection::CMTPEventLink::CMTPEventLink(const TMTPTypeEvent& aEvent) : + iEvent(aEvent) + { + } + +/** + * This method define and attach the property for publishing connection state + * events. + */ +void CMTPConnection::DefineConnStatePropertyL() + { + + __FLOG(_L8("DefineConnStatePropertyL - Entry")); + RProcess process; + TUid tSid = process.SecureId(); + //Property can read by anyone who subscribe for it. + _LIT_SECURITY_POLICY_PASS(KAllowReadAll); + _LIT_SECURITY_POLICY_S0(KAllowWrite, (TSecureId )KMTPPublishConnStateCat); + + TInt error = RProperty::Define(tSid, EMTPConnStateKey, RProperty::EInt, KAllowReadAll, KAllowReadAll); + if (KErrAlreadyExists != error) + { + User::LeaveIfError(error); + } + User::LeaveIfError(iProperty.Attach(tSid, EMTPConnStateKey, EOwnerThread)); + __FLOG(_L8("DefineConnStatePropertyL - Exit")); + } + +/** + * This method is to publish various connection state. + */ +void CMTPConnection::PublishConnState(TMTPConnStateType aConnState) + { + __FLOG_VA((_L8("PublishConnState - Entry \n publishing state = %d"), (TInt)aConnState)); + RProcess process; + TInt error = iProperty.Set(process.SecureId(), EMTPConnStateKey, (TInt)aConnState); + __ASSERT_DEBUG((error == KErrNone), Panic(EMTPPanicPublishEvent));; + __FLOG(_L8("PublishConnState - Exit")); + } + +/** + * This method is used to publish the events based on the TransactionPhase. + * + */ +void CMTPConnection::ValidateAndPublishConnState(CMTPSession& aSession, TInt aState) + { + __FLOG_VA((_L8("ValidateAndPublishConnState - Entry \n publishing state = %d"), aState)); + + TMTPConnStateType conState = EConnectedToHost; + switch((TStates)aState) + { + case EStateOpen: + { + TMTPTransactionPhase tPhase = aSession.TransactionPhase(); + switch(tPhase) + { + case EDataRToIPhase: + conState = ESendingDataToHost; + break; + + case EDataIToRPhase: + conState = EReceiveDataFromHost; + break; + + case EIdlePhase: + case EUndefined: + case ERequestPhase: + case EResponsePhase: + case ECompletingPhase: + default: + conState = EConnectedToHost; + break; + } + } + break; + case EStateShutdown: + case EStateErrorShutdown: + conState = EDisconnectedFromHost; + break; + + case EStateErrorRecovery: + case EStateUnknown: + default: + conState = EConnectedToHost; + break; + } + PublishConnState(conState); + __FLOG(_L8("ValidateAndPublishConnStateL - Exit")); + } + +void CMTPConnection::DisconnectionNotifyL() + { + iSingletons.DpController().NotifyDataProvidersL(EMTPDisconnected,this); + }