diff -r 4096754ee773 -r 52a167391590 localconnectivityservice/dun/utils/src/DunDownstream.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/localconnectivityservice/dun/utils/src/DunDownstream.cpp Wed Sep 01 12:20:40 2010 +0100 @@ -0,0 +1,468 @@ +/* +* Copyright (c) 2009-2010 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: Definitions needed for one "stream" of CDunTransporter +* +*/ + + +/* + * TODO: When local media is of type RComm, listening on it is started with + * RComm::NotifyDataAvailable() call. Check that USB ACM port and Irda RCOMM + * (and any other new media in the future) behaves correctly so that when + * RComm::ReadOneOrMore() is issued, the read is issued immediately without + * checking for new data. If waiting for new data happens in this + * NotifyDataAvailable/ReadOneOrMore combination, raise a defect to Symbian. + */ + +#include "DunTransporter.h" +#include "DunDownstream.h" +#include "DunUpstream.h" +#include "DunDebug.h" + +// --------------------------------------------------------------------------- +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CDunDownstream* CDunDownstream::NewL( MDunTransporterUtilityAux* aUtility ) + { + CDunDownstream* self = new (ELeave) CDunDownstream( aUtility ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// Destructor. +// --------------------------------------------------------------------------- +// +CDunDownstream::~CDunDownstream() + { + FTRACE(FPrint( _L("CDunDownstream::~CDunDownstream()" ))); + ResetData(); + FTRACE(FPrint( _L("CDunDownstream::~CDunDownstream() complete" ))); + } + +// --------------------------------------------------------------------------- +// Resets data to initial values +// --------------------------------------------------------------------------- +// +void CDunDownstream::ResetData() + { + // APIs affecting this: + // IssueRequest() + Stop(); + // InitializeForDataPushing() + delete iPushData.iDataPusher; + iPushData.iDataPusher = NULL; + // AddConnMonCallbackL() + iCallbacksR.Close(); + iCallbacksW.Close(); + // AddSkippedErrorL() + iOkErrorsR.Close(); + iOkErrorsW.Close(); + // Internal + Initialize(); + } + +// --------------------------------------------------------------------------- +// Initializes this stream for AT command notifications +// --------------------------------------------------------------------------- +// +TInt CDunDownstream::InitializeForDataPushing( + MDunAtCmdHandler* aAtCmdHandler ) + { + FTRACE(FPrint( _L("CDunDownstream::InitializeForDataPushing()" ) )); + if ( iPushData.iDataPusher || iPushData.iAtCmdHandler ) // optional + { + FTRACE(FPrint( _L("CDunDownstream::InitializeForDataPushing() (already exists) complete" ) )); + return KErrAlreadyExists; + } + if ( !aAtCmdHandler ) + { + FTRACE(FPrint( _L("CDunDownstream::InitializeForDataPushing() (aAtCmdHandler) not initialized!" ) )); + return KErrGeneral; + } + CDunDataPusher* dataPusher = NULL; + TRAPD( retTrap, dataPusher = CDunDataPusher::NewL(*this,this) ); + if ( retTrap != KErrNone ) + { + FTRACE(FPrint( _L("CDunDownstream::InitializeForDataPushing() (trapped!) complete" ) )); + return retTrap; + } + if ( iComm ) + { + dataPusher->SetMedia( iComm ); + } + else if ( iSocket ) + { + dataPusher->SetMedia( iSocket ); + } + iPushData.iDataPusher = dataPusher; + iPushData.iAtCmdHandler = aAtCmdHandler; + FTRACE(FPrint( _L("CDunDownstream::InitializeForDataPushing() complete" ) )); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Checks if data is in queue +// --------------------------------------------------------------------------- +// +TBool CDunDownstream::IsDataInQueue( const TDesC8* aDataToPush ) + { + FTRACE(FPrint( _L("CDunDownstream::IsDataInQueue()" ) )); + if ( !iPushData.iDataPusher ) + { + FTRACE(FPrint( _L("CDunDownstream::IsDataInQueue() (iPushData.iDataPusher not initialized!) complete" ))); + return EFalse; + } + TInt foundIndex = iPushData.iDataPusher->FindEventFromQueue( aDataToPush ); + FTRACE(FPrint( _L("CDunDownstream::IsDataInQueue() complete" ) )); + return ( foundIndex >= 0 ) ? ETrue : EFalse; + } + +// --------------------------------------------------------------------------- +// Adds data to event queue and starts sending if needed +// --------------------------------------------------------------------------- +// +TInt CDunDownstream::AddToQueueAndSend( const TDesC8* aDataToPush, + MDunCompletionReporter* aCallback ) + { + FTRACE(FPrint( _L("CDunDownstream::AddToQueueAndSend()" ) )); + if ( !iPushData.iDataPusher ) + { + FTRACE(FPrint( _L("CDunDownstream::AddToQueueAndSend() (iPushData.iDataPusher not initialized!) complete" ))); + return KErrGeneral; + } + // Add to event queue. If something went wrong, just return + TInt retTemp = iPushData.iDataPusher->AddToEventQueue( aDataToPush, aCallback ); + if ( retTemp != KErrNone ) + { + FTRACE(FPrint( _L("CDunDownstream::AddToQueueAndSend() (ERROR) complete" ))); + return retTemp; + } + // Now push the data. If already active, push will start later, if not + // active it will start immediately. + iPushData.iDataPusher->SendQueuedData(); + FTRACE(FPrint( _L("CDunDownstream::AddToQueueAndSend() complete" ) )); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Starts downstream by issuing read request +// --------------------------------------------------------------------------- +// +TInt CDunDownstream::StartStream() + { + FTRACE(FPrint( _L("CDunDownstream::StartStream()" ) )); + FTRACE(FPrint( _L("CDunDownstream::StartStream() (buffer=0x%08X)" ), iBufferPtr )); + // Note: only start URC here. + // The downstream read request is started when command mode ends. + // This is done to make the data arrive in the correct order (reply vs. + // data) with "ATD" command. + TInt retVal = KErrNone; + if ( iPushData.iAtCmdHandler ) + { + retVal = iPushData.iAtCmdHandler->StartUrc(); + } + FTRACE(FPrint( _L("CDunDownstream::StartStream() complete" ) )); + return retVal; + } + +// --------------------------------------------------------------------------- +// Stops transfer for read or write endpoints +// --------------------------------------------------------------------------- +// +TInt CDunDownstream::Stop( TBool aStopMplex ) + { + FTRACE(FPrint( _L("CDunDownstream::Stop() (Dir=%d)" ), iDirection)); + if ( !iPushData.iDataPusher ) + { + FTRACE(FPrint( _L("CDunDownstream::Stop() (iPushData.iDatapusher not initialized!) complete" ))); + return KErrGeneral; + } + // Stop the downstream related AT command handling functionality + if ( aStopMplex ) // optional + { + if ( iPushData.iAtCmdHandler ) + { + iPushData.iAtCmdHandler->StopAtCmdHandling(); + } + // Stop the multiplexer separately + iPushData.iDataPusher->Stop(); + } + if ( iTransferState != EDunStateTransferring ) + { + FTRACE(FPrint( _L("CDunDownstream::Stop() (not ready) complete" ))); + return KErrNotReady; + } + // Stop only current operation + if ( iOperationType == EDunOperationTypeRead ) + { + if ( iNetwork ) + { + iNetwork->ReadCancel(); + Cancel(); + FTRACE(FPrint( _L("CDunDownstream::Stop() (Network) cancelled" ))); + } + } + else if ( iOperationType == EDunOperationTypeWrite ) + { + iPushData.iDataPusher->StopOneEvent( iBufferPtr ); + } + iTransferState = EDunStateIdle; + FTRACE(FPrint( _L("CDunDownstream::Stop() complete" ))); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// CDunDownstream::CDunDownstream +// --------------------------------------------------------------------------- +// +CDunDownstream::CDunDownstream( MDunTransporterUtilityAux* aUtility ) : + iUtility( aUtility ) + { + Initialize(); + } + +// --------------------------------------------------------------------------- +// CDunDownstream::ConstructL +// --------------------------------------------------------------------------- +// +void CDunDownstream::ConstructL() + { + FTRACE(FPrint( _L("CDunDownstream::ConstructL()" ) )); + if ( !iUtility ) + { + User::Leave( KErrGeneral ); + } + FTRACE(FPrint( _L("CDunDownstream::ConstructL() complete" ) )); + } + +// --------------------------------------------------------------------------- +// Initializes this class +// --------------------------------------------------------------------------- +// +void CDunDownstream::Initialize() + { + // Don't initialize iUtility here (it is set through NewL) + iPushData.iDataMode = EFalse; + iPushData.iDataPusher = NULL; + iPushData.iAtCmdHandler = NULL; + } + +// --------------------------------------------------------------------------- +// Issues transfer request for this stream +// --------------------------------------------------------------------------- +// +TInt CDunDownstream::IssueRequest() + { + // Set direction + iDirection = static_cast( EDunStreamTypeDownstream | iOperationType ); + + FTRACE(FPrint( _L("CDunDownstream::IssueRequest() (Dir=%d)" ), iDirection)); + if ( !iPushData.iDataPusher ) + { + FTRACE(FPrint( _L("CDunDownstream::IssueRequest() (iPushData.iDataPusher not initialized!) complete" ) )); + return KErrGeneral; + } + + if ( iTransferState != EDunStateIdle ) + { + FTRACE(FPrint( _L("CDunDownstream::IssueRequest() (not ready) complete" ) )); + return KErrNotReady; + } + + if ( iOperationType == EDunOperationTypeRead ) + { + iBufferPtr->SetLength( iBufferPtr->MaxLength() ); + FTRACE(FPrint( _L("CDunDownstream::IssueRequest() trying to read %d bytes... (Dir=%d)" ), iBufferPtr->Length(), iDirection)); + } + else // iOperationType == EDunOperationTypeWrite + { + FTRACE(FPrint( _L("CDunDownstream::IssueRequest() writing %d bytes... (Dir=%d)" ), iBufferPtr->Length(), iDirection)); + } + + switch ( iDirection ) + { + case EDunReaderDownstream: + iStatus = KRequestPending; + iNetwork->ReadOneOrMore( iStatus, *iBufferPtr ); + SetActive(); + FTRACE(FPrint( _L("CDunDownstream::IssueRequest() RComm ReadOneOrMore() requested" ) )); + break; + case EDunWriterDownstream: + AddToQueueAndSend( iBufferPtr, this ); + break; + default: + FTRACE(FPrint( _L("CDunDownstream::IssueRequest() (ERROR) complete" ) )); + return KErrGeneral; + } + + iTransferState = EDunStateTransferring; + + FTRACE(FPrint( _L("CDunDownstream::IssueRequest() (Dir=%d) complete" ), iDirection)); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// From class CActive. +// Gets called when endpoint data read complete +// --------------------------------------------------------------------------- +// +void CDunDownstream::RunL() + { + FTRACE(FPrint( _L("CDunDownstream::RunL() (Dir=%d)" ), iDirection)); + iTransferState = EDunStateIdle; + if ( iOperationType != EDunOperationTypeRead ) + { + FTRACE(FPrint( _L("CDunDownstream::RunL() (wrong operation type!) complete" ))); + return; + } + + TBool isError; + TInt retTemp = iStatus.Int(); + TInt stop = ProcessErrorCondition( retTemp, isError ); + + if ( !stop ) // no real error detected -> continue + { + if ( !isError ) + { + // Operation type was read so now set to write + iOperationType = EDunOperationTypeWrite; + } // if ( !isError ) + + IssueRequest(); + + } // if ( !stop ) + else // stop -> tear down connection + { + // Now CDunDataPusher notifies to write case so here we just notify the + // read case. + TDunConnectionReason connReason; + connReason.iReasonType = EDunReasonTypeRW; + connReason.iContext = GetMediaContext( EDunStreamTypeDownstream ); + connReason.iSignalType = 0; + connReason.iSignalHigh = EFalse; + connReason.iDirection = iDirection; + connReason.iErrorCode = retTemp; + iUtility->DoNotifyConnectionNotOk( iComm, + iSocket, + connReason, + iCallbacksR ); + FTRACE(FPrint( _L("CDunDownstream::RunL() stop" ))); + } // else + + FTRACE(FPrint( _L("CDunDownstream::RunL() complete" ))); + } + +// --------------------------------------------------------------------------- +// From class CActive. +// Gets called on cancel +// --------------------------------------------------------------------------- +// +void CDunDownstream::DoCancel() + { + } + +// --------------------------------------------------------------------------- +// From class MDunStreamManipulator. +// Gets called when outside party wants to push data to the existing stream +// --------------------------------------------------------------------------- +// +TInt CDunDownstream::NotifyDataPushRequest( const TDesC8* aDataToPush, + MDunCompletionReporter* aCallback ) + { + FTRACE(FPrint( _L("CDunDownstream::NotifyDataPushRequest()" ))); + // If in data mode push the reply anyway as "CONNECT" or "NO CARRIER" + // reply could arrive before/after the command mode information itself. + TInt retVal = AddToQueueAndSend( aDataToPush, aCallback ); + FTRACE(FPrint( _L("CDunDownstream::NotifyDataPushRequest() complete" ))); + return retVal; + } + +// --------------------------------------------------------------------------- +// From class MDunCompletionReporter. +// Gets called when data push is complete +// --------------------------------------------------------------------------- +// +void CDunDownstream::NotifyDataPushComplete( TBool aAllPushed ) + { + FTRACE(FPrint( _L("CDunDownstream::NotifyDataPushComplete()" ))); + // Next just skip the notifications of atomic operations because also this + // class initiates the pushing of atomic data. + if ( !aAllPushed ) + { + FTRACE(FPrint( _L("CDunDownstream::NotifyDataPushComplete() (continue) complete" ))); + return; + } + iTransferState = EDunStateIdle; + iOperationType = EDunOperationTypeUndefined; + if ( !iPushData.iDataPusher ) + { + FTRACE(FPrint( _L("CDunDownstream::NotifyDataPushComplete() (iPushData.iDataPusher not initialized!) complete" ))); + return; + } + // Now the multiplexer might have pushed the contained data in this class + // or it might have pushed only the external data. If the pushed data + // contains this classes data then reissue request, otherwise just clear + // the queue. + TInt foundIndex = iPushData.iDataPusher->FindEventFromQueue( iBufferPtr ); + iPushData.iDataPusher->SignalCompletionAndClearQueue(); + FTRACE(FPrint( _L("CDunDownstream::NotifyDataPushComplete() (find event)" ))); + if ( foundIndex >= 0 ) + { + // Restart the reading from Dataport only if in data mode + FTRACE(FPrint( _L("CDunDownstream::NotifyDataPushComplete() (issue request)" ))); + if ( iPushData.iDataMode ) + { + iOperationType = EDunOperationTypeRead; + IssueRequest(); + } + } + FTRACE(FPrint( _L("CDunDownstream::NotifyDataPushComplete() complete" ))); + } + +// --------------------------------------------------------------------------- +// From class MDunCmdModeMonitor. +// Notifies about command mode start +// --------------------------------------------------------------------------- +// +void CDunDownstream::NotifyCommandModeStart() + { + FTRACE(FPrint( _L("CDunDownstream::NotifyCommandModeStart()" ))); + iPushData.iDataMode = EFalse; + // Now the data mode has ended. + // If read operation then cancel it. + if ( iOperationType == EDunOperationTypeRead ) + { + Stop( EFalse ); + } + FTRACE(FPrint( _L("CDunDownstream::NotifyCommandModeStart() complete" ))); + } + +// --------------------------------------------------------------------------- +// From class MDunCmdModeMonitor. +// Notifies about command mode end +// --------------------------------------------------------------------------- +// +void CDunDownstream::NotifyCommandModeEnd() + { + FTRACE(FPrint( _L("CDunDownstream::NotifyCommandModeEnd()" ))); + iPushData.iDataMode = ETrue; + // Command mode ends here so start reading from Dataport + iOperationType = EDunOperationTypeRead; + IssueRequest(); + FTRACE(FPrint( _L("CDunDownstream::NotifyCommandModeEnd() complete" ))); + }