localconnectivityservice/dun/utils/src/DunUpstream.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 16:03:15 +0300
branchRCL_3
changeset 19 0aa8cc770c8a
permissions -rw-r--r--
Revision: 201032 Kit: 201035

/*
* 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" )));
    }