localconnectivityservice/dun/utils/src/DunUpstream.cpp
branchRCL_3
changeset 19 0aa8cc770c8a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/localconnectivityservice/dun/utils/src/DunUpstream.cpp	Tue Aug 31 16:03:15 2010 +0300
@@ -0,0 +1,576 @@
+/*
+* Copyright (c) 2008-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 "DunUpstream.h"
+#include "DunDebug.h"
+
+// ---------------------------------------------------------------------------
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CDunUpstream* CDunUpstream::NewL( MDunTransporterUtilityAux* aUtility )
+    {
+    CDunUpstream* self = new (ELeave) CDunUpstream( aUtility );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CDunUpstream::~CDunUpstream()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::~CDunUpstream()" )));
+    ResetData();
+    FTRACE(FPrint( _L("CDunUpstream::~CDunUpstream() complete" )));
+    }
+
+// ---------------------------------------------------------------------------
+// Resets data to initial values
+// ---------------------------------------------------------------------------
+//
+void CDunUpstream::ResetData()
+    {
+    // APIs affecting this:
+    // IssueRequest()
+    Stop();
+    // InitializeForAtParsing()
+    delete iParseData.iAtCmdHandler;
+    iParseData.iAtCmdHandler = NULL;
+    // AddConnMonCallbackL()
+    iCallbacksR.Close();
+    iCallbacksW.Close();
+    // AddSkippedErrorL()
+    iOkErrorsR.Close();
+    iOkErrorsW.Close();
+    // Internal
+    Initialize();
+    }
+
+// ---------------------------------------------------------------------------
+// Sets activity callback for this stream
+// ---------------------------------------------------------------------------
+//
+TInt CDunUpstream::SetActivityCallback(
+    MDunActivityManager* aActivityCallback )
+    {
+    if ( !aActivityCallback )
+        {
+        FTRACE(FPrint( _L("CDunUpstream::SetActivityCallback() (aActivityCallback) not initialized!" ) ));
+        return KErrGeneral;
+        }
+    if ( iActivityData.iActivityCallback )
+        {
+        FTRACE(FPrint( _L("CDunUpstream::SetActivityCallback() (already exists) complete" ) ));
+        return KErrAlreadyExists;
+        }
+    iActivityData.iActivityCallback = aActivityCallback;
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Initializes this stream for AT command notifications
+// ---------------------------------------------------------------------------
+//
+TInt CDunUpstream::InitializeForAtParsing(
+    MDunStreamManipulator* aStreamCallback,
+    const TDesC8* aConnectionName,
+    MDunCmdModeMonitor* aCallbackUp,
+    MDunCmdModeMonitor* aCallbackDown )
+    {
+    FTRACE(FPrint( _L("CDunUpstream::InitializeForAtParsing()" ) ));
+    if ( iParseData.iAtCmdHandler )
+        {
+        FTRACE(FPrint( _L("CDunUpstream::InitializeForAtParsing() (already exists) complete" ) ));
+        return KErrAlreadyExists;
+        }
+    TInt retTrap = KErrNone;
+    CDunAtCmdHandler* atCmdHandler = NULL;
+    TRAP( retTrap, atCmdHandler = CDunAtCmdHandler::NewL(this,
+                                                         aStreamCallback,
+                                                         aConnectionName) );
+    if ( retTrap != KErrNone )
+        {
+        FTRACE(FPrint( _L("CDunUpstream::InitializeForAtParsing() (trapped!) complete" ) ));
+        return retTrap;
+        }
+    atCmdHandler->AddCmdModeCallback( aCallbackUp );
+    atCmdHandler->AddCmdModeCallback( aCallbackDown );
+    iParseData.iDataMode = EFalse;
+    iParseData.iAtCmdHandler = atCmdHandler;
+    FTRACE(FPrint( _L("CDunUpstream::InitializeForAtParsing() complete" ) ));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Starts upstream by issuing read request
+// ---------------------------------------------------------------------------
+//
+TInt CDunUpstream::StartStream()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::StartStream()" ) ));
+    if ( !iNetwork )
+        {
+        FTRACE(FPrint( _L("CDunUpstream::StartStream() (iNetwork) not initialized!" ) ));
+        return KErrGeneral;
+        }
+    if ( !iComm && !iSocket )
+        {
+        FTRACE(FPrint( _L("CDunUpstream::StartStream() (iComm&iSocket) not initialized!" ) ));
+        return KErrGeneral;
+        }
+    iOperationType = EDunOperationTypeRead;
+    TInt retVal = IssueRequest();
+    FTRACE(FPrint( _L("CDunUpstream::StartStream() complete" ) ));
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// Stops transfer for read or write endpoints
+// ---------------------------------------------------------------------------
+//
+TInt CDunUpstream::Stop()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::Stop() (Dir=%d)" ), iDirection));
+    // Don't stop CDunAtCmdHandler here as it is downstream related!
+    if ( iTransferState != EDunStateTransferring )
+        {
+        FTRACE(FPrint( _L("CDunUpstream::Stop() (not ready) complete" )));
+        return KErrNotReady;
+        }
+    // Stop only current operation
+    if ( iOperationType == EDunOperationTypeRead )
+        {
+        if ( iComm )
+            {
+            iComm->ReadCancel();
+            FTRACE(FPrint( _L("CDunUpstream::Stop() (RComm) cancelled" )));
+            }
+        else if ( iSocket )
+            {
+            iSocket->CancelRecv();
+            FTRACE(FPrint( _L("CDunUpstream::Stop() (RSocket) cancelled" )));
+            }
+        }
+    else if ( iOperationType == EDunOperationTypeWrite )
+        {
+        if ( iNetwork )
+            {
+            iNetwork->WriteCancel();
+            FTRACE(FPrint( _L("CDunUpstream::Stop() (Network) cancelled" )));
+            }
+        }
+    Cancel();
+    iTransferState = EDunStateIdle;
+    // Notify parent about inactivity
+    if ( iActivityData.iActivityCallback && iActivityData.iNotified )
+        {
+        iActivityData.iActivityCallback->NotifyChannelInactivity();
+        iActivityData.iNotified = EFalse;
+        }
+    FTRACE(FPrint( _L("CDunUpstream::Stop() complete" )));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Data transmission state (if read completed)
+// ---------------------------------------------------------------------------
+//
+TBool CDunUpstream::DataReadStatus()
+    {
+    return iActivityData.iDataRead;
+    }
+
+// ---------------------------------------------------------------------------
+// CDunUpstream::CDunUpstream
+// ---------------------------------------------------------------------------
+//
+CDunUpstream::CDunUpstream( MDunTransporterUtilityAux* aUtility ) :
+    iUtility( aUtility )
+    {
+    Initialize();
+    }
+
+// ---------------------------------------------------------------------------
+// CDunUpstream::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CDunUpstream::ConstructL()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::ConstructL()" ) ));
+    if ( !iUtility )
+        {
+        User::Leave( KErrGeneral );
+        }
+    FTRACE(FPrint( _L("CDunUpstream::ConstructL() complete" ) ));
+    }
+
+// ---------------------------------------------------------------------------
+// Initializes this class
+// ---------------------------------------------------------------------------
+//
+void CDunUpstream::Initialize()
+    {
+    // Don't initialize iUtility here (it is set through NewL)
+    iActivityData.iActivityCallback = NULL;
+    iActivityData.iDataRead = EFalse;
+    iActivityData.iNotified = EFalse;
+    iParseData.iDataMode = EFalse;
+    iParseData.iAtCmdHandler = NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// Issues transfer request for this stream
+// ---------------------------------------------------------------------------
+//
+TInt CDunUpstream::IssueRequest()
+    {
+    // Set direction
+    iDirection = static_cast<TDunDirection>( EDunStreamTypeUpstream | iOperationType );
+
+    FTRACE(FPrint( _L("CDunUpstream::IssueRequest() (Dir=%d)" ), iDirection));
+
+    if ( iTransferState != EDunStateIdle )
+        {
+        FTRACE(FPrint( _L("CDunUpstream::IssueRequest() (not ready) complete" ) ));
+        return KErrNotReady;
+        }
+
+    if ( iOperationType == EDunOperationTypeRead )
+        {
+        iBufferPtr->SetLength( iBufferPtr->MaxLength() );
+        FTRACE(FPrint( _L("CDunUpstream::IssueRequest() trying to read %d bytes... (Dir=%d)" ), iBufferPtr->Length(), iDirection));
+        }
+    else // iOperationType == EDunOperationTypeWrite
+        {
+        FTRACE(FPrint( _L("CDunUpstream::IssueRequest() writing %d bytes... (Dir=%d)" ), iBufferPtr->Length(), iDirection));
+        }
+
+    switch ( iDirection )
+        {
+        case EDunReaderUpstream:
+            if ( iComm )
+                {
+                iStatus = KRequestPending;
+                iComm->ReadOneOrMore( iStatus, *iBufferPtr );
+                FTRACE(FPrint( _L("CDunUpstream::IssueRequest() RComm ReadOneOrMore() requested" ) ));
+                }
+            else if ( iSocket )
+                {
+                iStatus = KRequestPending;
+                iSocket->RecvOneOrMore( *iBufferPtr, 0, iStatus, iReadLengthSocket );
+                FTRACE(FPrint( _L("CDunUpstream::IssueRequest() RSocket RecvOneOrMore() requested" ) ));
+                }
+            else
+                {
+                FTRACE(FPrint( _L("CDunUpstream::IssueRequest() (ERROR) complete" ) ));
+                return KErrGeneral;
+                }
+            break;
+        case EDunWriterUpstream:
+            iStatus = KRequestPending;
+            iNetwork->Write( iStatus, *iBufferPtr );
+            FTRACE(FPrint( _L("CDunUpstream::IssueRequest() RComm Write() requested" ) ));
+            break;
+        default:
+            FTRACE(FPrint( _L("CDunUpstream::IssueRequest() (ERROR) complete" ) ));
+            return KErrGeneral;
+        }
+
+    SetActive();
+    iTransferState = EDunStateTransferring;
+
+    FTRACE(FPrint( _L("CDunUpstream::IssueRequest() (Dir=%d) complete" ), iDirection));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// Processes data that was read
+// ---------------------------------------------------------------------------
+//
+TBool CDunUpstream::ProcessReadData()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::ProcessReadData()" )));
+    // The following will be transferred to Dataport
+    if ( iParseData.iDataMode )
+        {
+        iOperationType = EDunOperationTypeWrite;
+        FTRACE(FPrint( _L("CDunUpstream::ProcessReadData() (next write) complete" )));
+        return ETrue;
+        }
+    if ( !iParseData.iAtCmdHandler )  // optional
+        {
+        FTRACE(FPrint( _L("CDunUpstream::ProcessReadData() (no handler) complete" )));
+        return ETrue;
+        }
+    // The following will be transferred to parser
+    TInt retTemp = KErrNone;
+    TBool moreNeeded = EFalse;
+    retTemp = iParseData.iAtCmdHandler->AddDataForParsing( *iBufferPtr,
+                                                           moreNeeded );
+    if ( retTemp!=KErrNone || !moreNeeded )
+        {
+        // If error or no error but no more data needed, don't reissue
+        FTRACE(FPrint( _L("CDunUpstream::ProcessReadData() (no reissue) complete" )));
+        return EFalse;
+        }
+    // If no error and more data needed, reissue
+    FTRACE(FPrint( _L("CDunUpstream::ProcessReadData() (reissue) complete" )));
+    return ETrue;
+    }
+
+// ---------------------------------------------------------------------------
+// Manages activity in a channel
+// ---------------------------------------------------------------------------
+//
+TInt CDunUpstream::ManageChannelActivity()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::ManageChannelActivity()" )));
+    if ( iActivityData.iDataRead )
+        {
+        FTRACE(FPrint( _L("CDunUpstream::ManageChannelActivity() (not ready) complete" )));
+        return KErrNotReady;
+        }
+    iActivityData.iDataRead = ETrue;
+    if ( iActivityData.iActivityCallback && !iActivityData.iNotified )
+        {
+        iActivityData.iActivityCallback->NotifyChannelActivity();
+        iActivityData.iNotified = ETrue;
+        }
+    FTRACE(FPrint( _L("CDunUpstream::ManageChannelActivity() complete" )));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// From class CActive.
+// Gets called when endpoint data read/write complete
+// ---------------------------------------------------------------------------
+//
+void CDunUpstream::RunL()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::RunL() (Dir=%d)" ), iDirection));
+    iTransferState = EDunStateIdle;
+
+    TBool isError;
+    TInt retTemp = iStatus.Int();
+    TInt stop = ProcessErrorCondition( retTemp, isError );
+
+    if ( !stop )  // no real error detected -> continue
+        {
+        TBool reIssue = ETrue;
+        if ( !isError )
+            {
+            if ( iOperationType == EDunOperationTypeRead )
+                {
+                ManageChannelActivity();
+                reIssue = ProcessReadData();
+                }  // if ( iOperationType == EDunOperationTypeRead )
+            else // iOperationType == EDunOperationTypeWrite
+                {
+                iOperationType = EDunOperationTypeRead;
+                }
+            }  // if ( !isError )
+
+        if ( reIssue )
+            {
+            IssueRequest();
+            }
+
+        }  // if ( !stop )
+    else  // stop -> tear down connection
+        {
+        FTRACE(FPrint( _L("CDunUpstream::RunL() stop" )));
+        TDunConnectionReason connReason;
+        connReason.iReasonType = EDunReasonTypeRW;
+        connReason.iContext = GetMediaContext( EDunStreamTypeUpstream );
+        connReason.iSignalType = 0;
+        connReason.iSignalHigh = EFalse;
+        connReason.iDirection = iDirection;
+        connReason.iErrorCode = retTemp;
+        if ( iOperationType == EDunOperationTypeRead )
+            {
+            iUtility->DoNotifyConnectionNotOk( iComm,
+                                               iSocket,
+                                               connReason,
+                                               iCallbacksR );
+            }
+        else  // iOperationType == EDunOperationTypeWrite
+            {
+            iUtility->DoNotifyConnectionNotOk( iComm,
+                                               iSocket,
+                                               connReason,
+                                               iCallbacksW );
+            }
+        }  // else
+
+    FTRACE(FPrint( _L("CDunUpstream::RunL() complete" )));
+    }
+
+// ---------------------------------------------------------------------------
+// From class CActive.
+// Gets called on cancel
+// ---------------------------------------------------------------------------
+//
+void CDunUpstream::DoCancel()
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunAtCmdStatusReporter
+// Notifies about parser's need to get more data
+// ---------------------------------------------------------------------------
+//
+void CDunUpstream::NotifyParserNeedsMoreData()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::NotifyParserNeedsMoreData()" )));
+    IssueRequest();  // iOperationType must be read here (don't set)
+    FTRACE(FPrint( _L("CDunUpstream::NotifyParserNeedsMoreData() complete" )));
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunAtCmdStatusReporter
+// Notifies about editor mode reply
+// ---------------------------------------------------------------------------
+//
+void CDunUpstream::NotifyEditorModeReply( TBool aStart )
+    {
+    FTRACE(FPrint( _L("CDunUpstream::NotifyEditorModeReply()" )));
+    if ( iParseData.iDataMode )
+        {
+        FTRACE(FPrint( _L("CDunUpstream::NotifyEditorModeReply() (not ready) complete" )));
+        return;
+        }
+    // If start of editor mode then just reissue the read request
+    // If continuation then echo and reissue the read request
+    if ( aStart )
+        {
+        IssueRequest();
+        FTRACE(FPrint( _L("CDunUpstream::NotifyEditorModeReply() (start) complete" )));
+        return;
+        }
+    iParseData.iAtCmdHandler->SendEchoCharacter( iBufferPtr, this );
+    FTRACE(FPrint( _L("CDunUpstream::NotifyEditorModeReply() complete" )));
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunAtCmdHandler
+// Starts URC message handling
+// ---------------------------------------------------------------------------
+//
+TInt CDunUpstream::StartUrc()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::StartUrc()" )));
+    TInt retVal = KErrNone;
+    if ( iParseData.iAtCmdHandler )  // optional
+        {
+        retVal = iParseData.iAtCmdHandler->StartUrc();
+        }
+    FTRACE(FPrint( _L("CDunUpstream::StartUrc() complete" )));
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunAtCmdHandler
+// Stops AT command handling downstream related activity (also URC)
+// ---------------------------------------------------------------------------
+//
+TInt CDunUpstream::StopAtCmdHandling()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::StopAtCmdHandling()" )));
+    TInt retVal = KErrNone;
+    if ( iParseData.iAtCmdHandler )  // optional
+        {
+        retVal = iParseData.iAtCmdHandler->StopUrc();
+        if ( retVal != KErrNone )
+            {
+            iParseData.iAtCmdHandler->Stop();
+            FTRACE(FPrint( _L("CDunUpstream::StopAtCmdHandling() (iAtCmdHandler) complete" )));
+            return retVal;
+            }
+        retVal = iParseData.iAtCmdHandler->Stop();
+        }
+    FTRACE(FPrint( _L("CDunUpstream::StopAtCmdHandling() complete" )));
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunCmdModeMonitor.
+// Notifies about command mode start
+// ---------------------------------------------------------------------------
+//
+void CDunUpstream::NotifyCommandModeStart()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::NotifyCommandModeStart()" )));
+    iParseData.iDataMode = EFalse;
+    // Stop processing (just to be sure).
+    // This will stop any possibly pending operations of
+    // CDunAtCmdHandler and CDunAtUrcHandler. CDunDownstream will take care of
+    // clearing (and stopping) non-callback write queues.
+    StopAtCmdHandling();
+    // Also restart the URC handling after the data mode
+    StartUrc();
+    FTRACE(FPrint( _L("CDunUpstream::NotifyCommandModeStart() complete" )));
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunCmdModeMonitor.
+// Notifies about command mode end
+// ---------------------------------------------------------------------------
+//
+void CDunUpstream::NotifyCommandModeEnd()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::NotifyCommandModeEnd()" )));
+    iParseData.iDataMode = ETrue;
+    // Stop processing (mandatory).
+    // This will stop any possibly pending operations of
+    // CDunAtCmdHandler and CDunAtUrcHandler. CDunDownstream will take care of
+    // clearing (and stopping) non-callback write queues.
+    StopAtCmdHandling();
+    // The follow is needed because stopping the AT command handling here
+    // prevents the subsequent AT command handling notification to reach the
+    // NotifyAtCmdHandlingEnd() in this class (the notification starts from
+    // CDunAtCmdPusher's SetToIdleAndNotifyEnd()).
+    // So here we have to do the block "if ( aStartIndex < 0 )" in function
+    // NotifyAtCmdHandlingEnd().
+    IssueRequest();
+    FTRACE(FPrint( _L("CDunUpstream::NotifyCommandModeEnd() complete" )));
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDunAtCmdEchoer.
+// Notifies about command mode end
+// ---------------------------------------------------------------------------
+//
+void CDunUpstream::NotifyEchoComplete()
+    {
+    FTRACE(FPrint( _L("CDunUpstream::NotifyEchoComplete()" )));
+    IssueRequest();
+    FTRACE(FPrint( _L("CDunUpstream::NotifyEchoComplete() complete" )));
+    }