linklayerprotocols/tundriver/src/tundriverflow.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 15 Sep 2010 00:18:51 +0300
branchRCL_3
changeset 63 425d8f4f7fa5
permissions -rw-r--r--
Revision: 201035 Kit: 201035

/**
*   Copyright (c) 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:
*   Flow implementation for data path for tunnel driver.
* 
*
*/

/**
 @file tundriverflow.cpp
 @internalTechnology
*/

#include <e32std.h>
#include <ecom/ecom.h>
#include <ecom/implementationproxy.h>
#include <elements/nm_messages_base.h>
#include <elements/nm_messages_child.h>

#include "ss_subconnflow.h"
#include <comms-infras/ss_log.h>
#include "tundriverflow.h"
#include "tundriverbinder.h"
#include "tundriverprovision.h"

using namespace Messages;
using namespace MeshMachine;
using namespace ESock;

#ifdef SYMBIAN_TRACE_ENABLE
_LIT8(KNif,"tundriver");
#endif

CTunDriverSubConnectionFlowFactory* CTunDriverSubConnectionFlowFactory::NewL(TAny* aConstructionParameters)
/**
* CTunDriverSubConnectionFlowFactory::NewL constructs a Default SubConnection Flow Factory
* @param aConstructionParameters construction data passed by ECOM
* @returns pointer to a constructed factory object.
*/
    {
    CTunDriverSubConnectionFlowFactory* ptr = new (ELeave) CTunDriverSubConnectionFlowFactory(TUid::Uid(KTunDriverFlowImplementationUid), *(reinterpret_cast<CSubConnectionFlowFactoryContainer*>(aConstructionParameters)));
    return ptr;
    }


CTunDriverSubConnectionFlowFactory::CTunDriverSubConnectionFlowFactory(TUid aFactoryId, CSubConnectionFlowFactoryContainer& aParentContainer)
:   CSubConnectionFlowFactoryBase(aFactoryId, aParentContainer)
/**
* CTunDriverSubConnectionFlowFactory::CTunDriverSubConnectionFlowFactory is a Default SubConnection Flow Factory
* @param aFactoryId ECOM Implementation Id
* @param aParentContainer Object Owner
*/
    {
    }

CSubConnectionFlowBase* CTunDriverSubConnectionFlowFactory::DoCreateFlowL(CProtocolIntfBase* aProtocolIntf, TFactoryQueryBase& aQuery)
/**
* CTunDriverSubConnectionFlowFactory::DoCreateFlowL will create SubConnection Flow.
* @param aFactoryId ECOM Implementation Id
* @param aParentContainer Object Owner
*/
    {
    const TDefaultFlowFactoryQuery& query = static_cast<const TDefaultFlowFactoryQuery&>(aQuery);
    return CTunDriverSubConnectionFlow::NewL(*this, query.iSCprId, aProtocolIntf);
    }

CTunDriverSubConnectionFlow::CTunDriverSubConnectionFlow(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf)
:   CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf)
/**
* CTunDriverSubConnectionFlow::CTunDriverSubConnectionFlow is a Default Constructor
* @param aFactoryId ECOM Implementation Id
* @param aParentContainer Object Owner
*/
    {
    __FLOG_OPEN(KCFNodeTag, KNif);
    LOG_NODE_CREATE(KNif, CTunDriverSubConnectionFlow);
    }

CTunDriverSubConnectionFlow::~CTunDriverSubConnectionFlow()
/**
* CTunDriverSubConnectionFlowFactory::~CTunDriverSubConnectionFlow is a Default destructor
* @param aFactoryId ECOM Implementation Id
* @param aParentContainer Object Owner
*/
    {
    delete iBinder4;
    iBinder4 = NULL;
#ifdef IPV6SUPPORT
    delete iBinder6;
    iBinder6 = NULL;
#endif
    LOG_NODE_DESTROY(KNif, CTunDriverSubConnectionFlow);
    __FLOG_CLOSE;
    }

CTunDriverSubConnectionFlow* CTunDriverSubConnectionFlow::NewL(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf)
/**
* CTunDriverSubConnectionFlowFactory::NewL is a first phase Constructor.
* @param aFactoryId ECOM Implementation Id
* @param aParentContainer Object Owner
*/
    {
    CTunDriverSubConnectionFlow* flow = new (ELeave) CTunDriverSubConnectionFlow(aFactory, aSubConnId, aProtocolIntf);
    return flow;
    }

void CTunDriverSubConnectionFlow::FlowDown(TInt aError, TInt aAction /*= MNifIfNotify::EDisconnect*/)
/**
* CTunDriverSubConnectionFlowFactory::FlowDown will post the message.
* @param aError obtained from the upper CF Layer.
* @param aAction and the action message for aError.
*/
    {
    PostFlowDownMessage(aError, aAction);
    }

void CTunDriverSubConnectionFlow::Progress(TInt aStage, TInt aError)
/**
* CTunDriverSubConnectionFlowFactory::Progress Binder requesting a Progress() message be sent to SCPR
* @param aStage and the action message for aError.
* @param aError obtained from the upper CF Layer.
*/
    {
    PostProgressMessage(aStage, aError);
    }

const TTunDriverIp4Provision* CTunDriverSubConnectionFlow::Ip4Provision() const
/**
* CTunDriverSubConnectionFlowFactory::Ip4Provision
* @param 
* @return iIp4Provision.
*/
    {
    ASSERT(iProvision);
    return &iProvision->iIp4Provision;
    }

#ifdef IPV6SUPPORT
const TTunDriverIp6Provision* CTunDriverSubConnectionFlow::Ip6Provision() const
/**
* CTunDriverSubConnectionFlowFactory::Ip6Provision
* @param 
* @return iIp6Provision.
*/
    {
    ASSERT(iProvision);
    return &iProvision->iIp6Provision;
    }
#endif

//-=========================================================
// Messages::ANode methods
//-=========================================================

#define __FRAMEWORK_PRODUCTION_ERRORHANDLING(c,p) (void)((c)||(p,0))
void CTunDriverSubConnectionFlow::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
/**
* CTunDriverSubConnectionFlowFactory::ReceivedL called on incoming SCPR Messages.
* CTunDriverSubConnectionFlow functions will be called Based on message type
* @param aCFMessage message base
*/
    {
    #ifdef __FLOG_ACTIVE
        TAny* senderAddr = NULL;
        const TNodeId* senderNodeId = address_cast<TNodeId>(&aSender);
        __ASSERT_DEBUG(senderNodeId!=NULL,User::LeaveIfError(KErrCorrupt));
        senderAddr = senderNodeId->Ptr();
        __FLOG_4(_L8("CTunDriverSubConnectionFlow(%x):\tReceivedL() Sender Id: %x, Msg Realm: %X, Msg ID: %d"), this, senderAddr, aMessage.MessageId().Realm(), aMessage.MessageId().MessageId());
    #endif

    CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage);
    if (aMessage.IsMessage<TEBase::TError>())
        {
        SubConnectionError(static_cast<TEBase::TError&>(aMessage).iValue);
        }
    else if (TEChild::ERealmId == aMessage.MessageId().Realm())
        {
        switch (aMessage.MessageId().MessageId())
            {
        case TEChild::TCancel::EId:
            CancelFlow(KErrCancel);
        case TEChild::TDestroy::EId :
            Destroy();
            break;
        default:
            ASSERT(EFalse);
            }
        }
    else if (TCFDataClient::ERealmId == aMessage.MessageId().Realm())
        {
        switch (aMessage.MessageId().MessageId())
            {
        case TCFDataClient::TStart::EId :
            StartFlowL();
            break;
        case TCFDataClient::TStop::EId :
            StopFlow(static_cast<TCFDataClient::TStop&>(aMessage).iValue);
            break;
        case TCFDataClient::TProvisionConfig::EId:
            ProvisionConfig(static_cast<TCFDataClient::TProvisionConfig&>(aMessage).iConfig);
            break;
        case TCFDataClient::TBindTo::EId:
            {
            TCFDataClient::TBindTo& bindToReq = message_cast<TCFDataClient::TBindTo>(aMessage);
            __FRAMEWORK_PRODUCTION_ERRORHANDLING(bindToReq.iNodeId.IsNull(),User::LeaveIfError(KErrNotSupported));
            RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete().CRef());
            }
            break;
        default:
            ASSERT(EFalse);
            }
        }
    else
        {
        User::Leave(KErrNotSupported);
        }
    }

void CTunDriverSubConnectionFlow::StartFlowL()
/**
* CTunDriverSubConnectionFlowFactory::StartFlowL starts the flow on receiving the message TStart.
* This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL 
*/
    {
    __FLOG(_L8("CTunDriverSubConnectionFlow:\tStartFlowL()"));
    
    if(iMMState == EStarted)
        {
        //Flow can be started multiple times.
        //For example a start may fail on an upper layer in which case the upper layer will not be able
        //to stop our layer and we need to accept start again.
        PostProgressMessage(KLinkLayerOpen, KErrNone);
        PostDataClientStartedMessage();
        return;
        }
    iMMState = EStarted;

    // If the processing of the ProvisionConfig message failed earlier, send the error response
    // here to the StartFlow message as there is no response to ProvisionConfig.
    User::LeaveIfError(iSavedError);

    PostProgressMessage(KLinkLayerOpen, KErrNone);
    PostDataClientStartedMessage();
    iBinder4->StartSending();
#ifdef IPV6SUPPORT
    if(iBinder6)
        {
        iBinder6->StartSending();
        }
#endif
    }

void CTunDriverSubConnectionFlow::CancelFlow(TInt aError)
/**
* CTunDriverSubConnectionFlowFactory::CancelFlow cancels the flow on receiving the message TCancel.
* It will post the message as KErrCancel.
* This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL 
*/
    {
    __FLOG_1(_L8("CTunDriverSubConnectionFlow:\tCancelFlow(%d)"), aError);

    if(iMMState == EStarted)
        {
        PostFlowDownMessage(aError);
        }
    }

void CTunDriverSubConnectionFlow::StopFlow(TInt aError)
/**
* CTunDriverSubConnectionFlowFactory::StopFlow stops the flow on receiving the message TStop.
* It will post the message as KLinkLayerClosed and KErrCancel.
* This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL 
*/
    {
    __FLOG_1(_L8("CTunDriverSubConnectionFlow:\tStopFlow(%d)"), aError);

    PostProgressMessage(KLinkLayerClosed, aError);
    iMMState = EStopped;
    PostFlowDownMessage(aError);
    }

void CTunDriverSubConnectionFlow::ProvisionConfig(const ESock::RMetaExtensionContainerC& aConfigData)
/**
* CTunDriverSubConnectionFlowFactory::Provisionconfig on receipt of the ProvisionConfig message, the pointer contained within it is stored
* in iAccessPointConfig and the information contained within the iAccessPointConfig  array is validated:
* CTunDriverProtoProvision must be present.  It is added by the TunDriverMCPr and populated from CommsDat.
* It is a 'C' class to take advantage of zero initialisation.
* Any errors are saved in iSavedError - there is no response to ProvisionConfig, 
* so an error response is sent later to StartFlow message.
*
* on receipt of TCFDataClient::TStart:
* iSavedError is checked and, if non-zero, an Error message is sent to the SCPr
* TunDriverAgentProvision must be present.  It is added by the TunDriverAgentHandler and populated via calls
* to the Agent.  It is a 'T' class because it requires no zero initialisation.  If missing,
* an Error message is signalled to the SCPr.
* This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL
* @param aData pointer to provisioning structure 
*/
    {
    __FLOG_0(_L8("CTunDriverSubConnectionFlow:\tProvisionConfig message received"));
    iSavedError = KErrNone;
    iAccessPointConfig.Close();
    iAccessPointConfig.Open(aConfigData);

    const CTunDriverProtoProvision* provision = static_cast<const CTunDriverProtoProvision*>(AccessPointConfig().FindExtension(
            STypeId::CreateSTypeId(CTunDriverProtoProvision::EUid, CTunDriverProtoProvision::ETypeId)));
    __FRAMEWORK_PRODUCTION_ERRORHANDLING(provision!=NULL,iSavedError = KErrCorrupt);
    
    iProvision = provision;
    }

void CTunDriverSubConnectionFlow::Destroy()
/**
* CTunDriverSubConnectionFlowFactory::Destroy
* Request from SCPR to destroy
* This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL 
*/
    {
    DeleteThisFlow();
    }

void CTunDriverSubConnectionFlow::SubConnectionGoingDown()
/**
* CTunDriverSubConnectionFlowFactory::SubConnectionGoingDown
* Request from Agemt SCPR
*/
    {
    __FLOG(_L8("CTunDriverSubConnectionFlow:\tSubConnectionGoingDown"));
    }

void CTunDriverSubConnectionFlow::SubConnectionError(TInt /*aError*/)
/**
* CTunDriverSubConnectionFlowFactory::SubConnectionError
* Request from Agemt SCPR
*/
    {
    __FLOG(_L8("CTunDriverSubConnectionFlow:\tSubConnectionError"));
    }

MFlowBinderControl* CTunDriverSubConnectionFlow::DoGetBinderControlL()
/**
* CTunDriverSubConnectionFlowFactory::DoGetBinderControlL Called by upper layer for binding
* Request from Agemt SCPR
* @return MFlowBinderControl instance
*/
    {
    __FLOG(_L8("CTunDriverSubConnectionFlow::DoGetBinderControlL"));
    return this;
    }

//-=========================================================
// MFlowBinderControl methods
//

MLowerControl* CTunDriverSubConnectionFlow::GetControlL(const TDesC8& aProtocol)
/**
* CTunDriverSubConnectionFlow::GetControlL
* Create and return an MLowerControl instance of the specified binder type.
* Called from upper layer during binding procedure.
* @param aProtocol Protocol type of the binder
* @return MLowerControl instance of the protocol type
*/
    {
    MLowerControl* lowerControl = NULL;
    __FLOG(_L8("CTunDriverSubConnectionFlow:\tGetLowerControlL(KProtocol4)"));
    if(aProtocol.Compare(KProtocol4()) == 0)
    		{
    		iBinder4 = CTunDriverBinder4::NewL(*this);
    		lowerControl = iBinder4;
    		}
#ifdef IPV6SUPPORT
    else
    if (aProtocol.CompareF(KProtocol6()) == 0)
        {
        __FLOG(_L8("CTunDriverSubConnectionFlow::GetLowerControlL(KProtocol6)- Should Return KErrNotSupported"));
        iBinder6 = CTunDriverBinder6::NewL(*this);
        lowerControl = iBinder6;        
        }
#endif
    return lowerControl;
    }

MLowerDataSender* CTunDriverSubConnectionFlow::BindL(const TDesC8& aProtocol, MUpperDataReceiver* aReceiver, MUpperControl* aControl)
/**
* CTunDriverSubConnectionFlow::BindL Create and return an MLowerDataSender instance of the specified protocol type.
* This is bound to the specified upper layer objects.
* Called from upper layer to bind to this layer.
* @param aProtocol Protocol type of the binder (same as in GetControlL())
* @param aReceiver upper layer's MUpperDataReceiver instance for this binder to associate with
* @param aControl upper layer's MUpperControl instance for this binder to associate with
* @return MLowerDataSender instance
*/
    {
    __FLOG(_L8("CTunDriverSubConnectionFlow:\tBindL()"));

    MLowerDataSender* lowerDataSender = NULL;

    if(aProtocol.CompareF(KProtocol4()) == 0)
    		{
    		lowerDataSender = iBinder4->Bind(*aReceiver, *aControl);
    		}
#ifdef IPV6SUPPORT
    else
    if (aProtocol.CompareF(KProtocol6()) == 0)
        {
        lowerDataSender = iBinder6->Bind(*aReceiver, *aControl);
        }
#endif
    if(lowerDataSender != NULL)
        {
        iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TActive().CRef());
        }
    return lowerDataSender;
    }

void CTunDriverSubConnectionFlow::Unbind(MUpperDataReceiver* aReceiver, MUpperControl* aControl)
/**
* CTunDriverSubConnectionFlow::Unbind will Unbind from the upper layer.
* Called from the upper layer during unbinding.
* @param aReceiver
* @param aControl
*/
    {
    __FLOG(_L8("CTunDriverSubConnectionFlow:\tUnbind()"));
    if (iBinder4 && iBinder4->MatchesUpperControl(aControl))
            {
            iBinder4->Unbind(*aReceiver, *aControl);
            delete iBinder4;
            iBinder4 = NULL;
            }
#ifdef IPV6SUPPORT
    if (iBinder6 && iBinder6->MatchesUpperControl(aControl))
            {
            iBinder6->Unbind(*aReceiver, *aControl);
            delete iBinder6;
            iBinder6 = NULL;
            }
#endif
    iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef());
    }

ESock::CSubConnectionFlowBase* CTunDriverSubConnectionFlow::Flow()
/**
* CTunDriverSubConnectionFlow::Flow will Return the flow object corresponding to the MFlowBinderControl
* Called from the UpperLayer get the instance of the flow.
*/
    {
    return this;
    }

void CTunDriverSubConnectionFlow::PostProgressMessage(TInt aStage, TInt aError)
/*
* CTunDriverSubConnectionFlow::PostProgressMessage will send the state change message with the param values.
* 
*/
    {
    iSubConnectionProvider.PostMessage(Id(), TCFMessage::TStateChange(Elements::TStateChange(aStage, aError)).CRef());
    }

void CTunDriverSubConnectionFlow::PostDataClientStartedMessage()
/*
* CTunDriverSubConnectionFlow::PostDataClientStartedMessage will send the started message with the param values.
*/
    {
    iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStarted().CRef());
    }

void CTunDriverSubConnectionFlow::PostFlowDownMessage(TInt aError, TInt aAction /*= MNifIfNotify::EDisconnect*/)
/*
* CTunDriverSubConnectionFlow::PostFlowDownMessage will send the DataClient Down message with the param values.
*/
    {
    if (iMMState == EStarted)
        {
        iMMState = EStopped;
        iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError, aAction).CRef());
        }
    else
        {
        iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStopped(aError).CRef());
        }
    }

void CTunDriverSubConnectionFlow::MaybePostDataClientIdle()
/*
* CTunDriverSubConnectionFlow::MaybePostDataClientIdle will send the Idle message with the param values.
*/
    {
    // Can only send DataClientIdle when the upper layer has unbound and the flow is stopped
    if( iBinder4 == NULL
#ifdef IPV6SUPPORT
        || iBinder6 == NULL
#endif
      )
        {
        iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef());
        }
    }