diff -r 453dfc402455 -r 0aa8cc770c8a localconnectivityservice/dun/utils/src/DunDataPusher.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/localconnectivityservice/dun/utils/src/DunDataPusher.cpp Tue Aug 31 16:03:15 2010 +0300 @@ -0,0 +1,450 @@ +/* +* 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: Pushes data to existing stream from outside +* +*/ + + +#include "DunDataPusher.h" +#include "DunDownstream.h" +#include "DunDebug.h" + +// --------------------------------------------------------------------------- +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CDunDataPusher* CDunDataPusher::NewL( CDunDownstream& aParent, + MDunCompletionReporter* aStreamCallback ) + { + CDunDataPusher* self = new (ELeave) CDunDataPusher( aParent, + aStreamCallback ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// Destructor. +// --------------------------------------------------------------------------- +// +CDunDataPusher::~CDunDataPusher() + { + FTRACE(FPrint( _L("CDunDataPusher::~CDunDataPusher()" ))); + ResetData(); + FTRACE(FPrint( _L("CDunDataPusher::~CDunDataPusher() complete" ))); + } + +// --------------------------------------------------------------------------- +// Resets data to initial values +// --------------------------------------------------------------------------- +// +void CDunDataPusher::ResetData() + { + // APIs affecting this: + // SendQueuedData() + Stop(); + // AddToEventQueue() + iEventQueue.Close(); + // Internal + Initialize(); + } + +// --------------------------------------------------------------------------- +// Sets media to be used for this endpoint +// --------------------------------------------------------------------------- +// +TInt CDunDataPusher::SetMedia( RComm* aComm ) + { + FTRACE(FPrint( _L("CDunDataPusher::SetMedia() (RComm)" ))); + if ( !aComm ) + { + FTRACE(FPrint( _L("CDunDataPusher::SetMedia() (RComm) (not initialized!) complete" ))); + return KErrGeneral; + } + iComm = aComm; + FTRACE(FPrint( _L("CDunDataPusher::SetMedia() (RComm) complete" ))); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Sets media to be used for this endpoint +// --------------------------------------------------------------------------- +// +TInt CDunDataPusher::SetMedia( RSocket* aSocket ) + { + FTRACE(FPrint( _L("CDunDataPusher::SetMedia() (RSocket)" ))); + if ( !aSocket ) + { + FTRACE(FPrint( _L("CDunDataPusher::SetMedia() (RSocket) (not initialized!) complete" ))); + return KErrGeneral; + } + iSocket = aSocket; + FTRACE(FPrint( _L("CDunDataPusher::SetMedia() (RSocket) complete" ))); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Adds event notification to queue +// --------------------------------------------------------------------------- +// +TInt CDunDataPusher::AddToEventQueue( const TDesC8* aDataToPush, + MDunCompletionReporter* aCallback ) + { + FTRACE(FPrint( _L("CDunDataPusher::AddToQueue()" ))); + if ( !aDataToPush || aDataToPush->Length()<0 ) + { + FTRACE(FPrint( _L("CDunDataPusher::AddToQueue() (unknown data) complete" ))); + return KErrGeneral; + } + // Check if identical pointer to data already exists + TInt foundIndex = FindEventFromQueue( aDataToPush ); + if ( foundIndex >= 0 ) + { + FTRACE(FPrint( _L("CDunDataPusher::AddToQueue() (already exists) complete" ))); + return KErrAlreadyExists; + } + // Unique pointer -> add to event queue + TDunDataPush dataPush; + dataPush.iDataToPush = aDataToPush; + dataPush.iCallback = aCallback; + TInt retTemp = iEventQueue.Append( dataPush ); + if ( retTemp != KErrNone ) + { + FTRACE(FPrint( _L("CDunDataPusher::AddToQueue() (append failed!) complete" ))); + return retTemp; + } + FTRACE(FPrint( _L("CDunDataPusher::AddToQueue() complete (count=%d)" ), iEventQueue.Count() )); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Finds an event from queue +// --------------------------------------------------------------------------- +// +TInt CDunDataPusher::FindEventFromQueue( const TDesC8* aDataToPush ) + { + FTRACE(FPrint( _L("CDunDataPusher::FindEventFromQueue()" ))); + TInt i; + TInt count = iEventQueue.Count(); + for ( i=0; i= 0 ) + { + if ( iEventIndex == foundIndex ) + { + Stop(); + } + FTRACE(FPrint( _L("CDunDataPusher::StopOneEvent() complete" ))); + return KErrNone; + } + FTRACE(FPrint( _L("CDunDataPusher::StopOneEvent() (not found) complete" ))); + return KErrNotFound; + } + +// --------------------------------------------------------------------------- +// Sends queued data in round robin +// --------------------------------------------------------------------------- +// +TBool CDunDataPusher::SendQueuedData() + { + FTRACE(FPrint( _L("CDunDataPusher::SendQueuedData()" ))); + if ( iPushState!=EDunStateIdle || iEventQueue.Count()==0 ) + { + FTRACE(FPrint( _L("CDunDataPusher::SendQueuedData() (not ready) complete" ))); + return EFalse; + } + TInt retTemp = ManageOneEvent(); + if ( retTemp != KErrNone ) + { + FTRACE(FPrint( _L("CDunDataPusher::SendQueuedData() (ERROR) complete" ))); + return EFalse; + } + iPushState = EDunStateDataPushing; + FTRACE(FPrint( _L("CDunDataPusher::SendQueuedData() complete (%d)" ), iEventQueue.Count() )); + return ETrue; + } + +// --------------------------------------------------------------------------- +// Stops sending for write endpoint +// --------------------------------------------------------------------------- +// +TInt CDunDataPusher::Stop() + { + FTRACE(FPrint( _L("CDunDataPusher::Stop()" ))); + if ( iPushState != EDunStateDataPushing ) + { + FTRACE(FPrint( _L("CDunDataPusher::Stop() (not ready) complete" ))); + return KErrNotReady; + } + // As the EDunStateDataPushing can be on even with multiple requests, + // cancel the actual operation in DoCancel() + Cancel(); + iPushState = EDunStateIdle; + FTRACE(FPrint( _L("CDunDataPusher::Stop() complete" ))); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Stops sending for write endpoint and clears event queue +// --------------------------------------------------------------------------- +// +TInt CDunDataPusher::StopAndClearQueue() + { + FTRACE(FPrint( _L("CDunDataPusher::StopAndClearQueue()" ))); + TInt retVal = Stop(); + iEventQueue.Reset(); + iEventIndex = 0; + FTRACE(FPrint( _L("CDunDataPusher::StopAndClearQueue() complete" ))); + return retVal; + } + +// --------------------------------------------------------------------------- +// Signals completion status in round robin and clears event queue +// --------------------------------------------------------------------------- +// +TInt CDunDataPusher::SignalCompletionAndClearQueue() + { + FTRACE(FPrint( _L("CDunDataPusher::SignalCompletionAndClearQueue()" ))); + // First copy the event queue to temporary notitication queue and + // reset the real event queue before notifications. This is done because + // implementor of NotifyDataPushComplete() can call AddToEventQueue() + // (and KErrAlreadyExists will happen there) + TInt i; + TInt retTemp; + RPointerArray notify; + TInt count = iEventQueue.Count(); + for ( i=0; iNotifyDataPushComplete( EFalse ); + } + notify.Close(); + FTRACE(FPrint( _L("CDunDataPusher::SignalCompletionAndClearQueue() complete (%d)" ), count )); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// CDunDataPusher::CDunDataPusher +// --------------------------------------------------------------------------- +// +CDunDataPusher::CDunDataPusher( CDunDownstream& aParent, + MDunCompletionReporter* aStreamCallback ) : + CActive( EPriorityHigh ), + iParent( aParent ), + iStreamCallback( aStreamCallback ) + { + Initialize(); + } + +// --------------------------------------------------------------------------- +// CDunDataPusher::ConstructL +// --------------------------------------------------------------------------- +// +void CDunDataPusher::ConstructL() + { + FTRACE(FPrint( _L("CDunDataPusher::ConstructL()" ))); + if ( !iStreamCallback ) + { + User::Leave( KErrGeneral ); + } + CActiveScheduler::Add( this ); + FTRACE(FPrint( _L("CDunDataPusher::ConstructL() complete" ))); + } + +// --------------------------------------------------------------------------- +// Initializes this class +// --------------------------------------------------------------------------- +// +void CDunDataPusher::Initialize() + { + // Don't initialize iUtility here (it is set through NewL) + // Don't initialize iStreamCallback here (it is set through NewL) + iPushState = EDunStateIdle; + iEventIndex = 0; + iSocket = NULL; + iComm = NULL; + } + +// --------------------------------------------------------------------------- +// Manages one event's data push +// --------------------------------------------------------------------------- +// +TInt CDunDataPusher::ManageOneEvent() + { + FTRACE(FPrint( _L("CDunDataPusher::ManageOneEvent()" ))); + if ( IsActive() ) + { + FTRACE(FPrint( _L("CDunDataPusher::ManageOneEvent() (not ready) complete" ))); + return KErrNotReady; + } + if ( iEventIndex < 0 || + iEventIndex >= iEventQueue.Count() ) + { + FTRACE(FPrint( _L("CDunDataPusher::ManageOneEvent() (buffer mismatch) complete" ))); + return KErrGeneral; + } + const TDesC8* dataToPush = iEventQueue[iEventIndex].iDataToPush; + if ( iComm ) + { + iStatus = KRequestPending; + iComm->Write( iStatus, *dataToPush ); + FTRACE(FPrint( _L("CDunDataPusher::ManageOneEvent() RComm Write() requested (buffer=0x%08X)" ), dataToPush )); + } + else if ( iSocket ) + { + iStatus = KRequestPending; + iSocket->Send( *dataToPush, 0, iStatus ); + FTRACE(FPrint( _L("CDunDataPusher::ManageOneEvent() RSocket Send() requested (buffer=0x%08X)" ), dataToPush )); + } + else + { + FTRACE(FPrint( _L("CDunDataPusher::ManageOneEvent() (ERROR) complete" ))); + return KErrGeneral; + } + SetActive(); + FTRACE(FPrint( _L("CDunDataPusher::ManageOneEvent() complete" ))); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Check whether an error code is severe error or not +// --------------------------------------------------------------------------- +// +TInt CDunDataPusher::ProcessErrorCondition( TInt aError, TBool& aIsError ) + { + FTRACE(FPrint( _L("CDunDataPusher::ProcessErrorCondition() (Dir=%d)" ), EDunWriterDownstream)); + aIsError = EFalse; + if ( aError != KErrNone ) + { + aIsError = ETrue; + TInt retTemp = iParent.iOkErrorsW.Find( aError ); + if ( retTemp == KErrNotFound ) + { + FTRACE(FPrint( _L("CDunDataPusher::ProcessErrorCondition() (Dir=%d) (%d=ETrue) complete" ), EDunWriterDownstream, aError)); + return ETrue; + } + } + FTRACE(FPrint( _L("CDunDataPusher::ProcessErrorCondition() (Dir=%d) (%d=EFalse) complete" ), EDunWriterDownstream, aError)); + return EFalse; + } + +// --------------------------------------------------------------------------- +// From class CActive. +// Gets called when endpoint data write complete +// --------------------------------------------------------------------------- +// +void CDunDataPusher::RunL() + { + FTRACE(FPrint( _L("CDunDataPusher::RunL() (buffer=0x%08X)" ), iEventQueue[iEventIndex].iDataToPush )); + + TBool isError; + TInt retTemp = iStatus.Int(); + TInt stop = ProcessErrorCondition( retTemp, isError ); + + if ( !stop ) // no real error detected -> continue + { + if ( !isError ) + { + iEventIndex++; + } + if ( iEventIndex < iEventQueue.Count() ) + { + // More to serve so start again + ManageOneEvent(); + } + else + { + // Last was served so stop processing and notify + iPushState = EDunStateIdle; + iStreamCallback->NotifyDataPushComplete( ETrue ); + } + } // if ( !stop ) + else // stop -> tear down connection + { + TDunConnectionReason connReason; + connReason.iReasonType = EDunReasonTypeRW; + connReason.iContext = EDunMediaContextLocal; + connReason.iSignalType = 0; + connReason.iSignalHigh = EFalse; + connReason.iDirection = EDunWriterDownstream; + connReason.iErrorCode = retTemp; + iParent.iUtility->DoNotifyConnectionNotOk( iComm, + iSocket, + connReason, + iParent.iCallbacksW ); + } // else + + FTRACE(FPrint( _L("CDunDataPusher::RunL() complete" ))); + } + +// --------------------------------------------------------------------------- +// From class CActive. +// Gets called on cancel +// --------------------------------------------------------------------------- +// +void CDunDataPusher::DoCancel() + { + FTRACE(FPrint( _L("CDunDataPusher::DoCancel()" ))); + if ( iComm ) + { + iComm->WriteCancel(); + FTRACE(FPrint( _L("CDunDataPusher::DoCancel() (RComm) cancelled" ))); + } + else if ( iSocket ) + { + iSocket->CancelWrite(); + FTRACE(FPrint( _L("CDunDataPusher::DoCancel() (RSocket) cancelled" ))); + } + FTRACE(FPrint( _L("CDunDataPusher::DoCancel() complete" ))); + }