localconnectivityservice/dun/utils/src/DunDownstream.cpp
branchRCL_3
changeset 19 0aa8cc770c8a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/localconnectivityservice/dun/utils/src/DunDownstream.cpp	Tue Aug 31 16:03:15 2010 +0300
@@ -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<TDunDirection>( 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" )));
+    }