--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/networkcontrol/ipnetworklayer/src/flow.cpp Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,971 @@
+// Copyright (c) 2005-2009 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:
+// IP Shim Flow Base class.
+// This class is derived from by the separate IP4 and IP6 shim flow classes.
+//
+//
+
+/**
+ @file flow.cpp
+*/
+
+#include <e32std.h>
+#include <e32test.h>
+#include <ecom/ecom.h>
+#include <ecom/implementationproxy.h>
+#include <comms-infras/ss_metaconnprov.h>
+#include <comms-infras/ss_subconnflow.h>
+#include "flow.h"
+#include "nif.h"
+#include "panic.h"
+#include "ItfInfoConfigExt.h"
+#include "IPProtoMessages.h" // TCFIPProtoMessage
+#include "IPProtoCPR.h"
+#include "idletimer.h"
+#include <networking/ipaddrinfoparams.h>
+#include "IPProtoDeMux.h"
+#include <comms-infras/ss_log.h>
+#include <es_prot_internal.h>
+
+using namespace Messages;
+using namespace MeshMachine;
+using namespace ESock;
+using namespace IpProtoCpr;
+//
+// CIPShimSubConnectionFlow
+//
+
+CIPShimSubConnectionFlow::CIPShimSubConnectionFlow(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf)
+: CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf), iCleanupError(KErrUnknown),
+ iAsyncBinderClose(*this)
+ {
+ LOG_NODE_CREATE(KIPProtoTag1, CIPShimSubConnectionFlow);
+ }
+
+CIPShimSubConnectionFlow::~CIPShimSubConnectionFlow()
+ {
+ ASSERT(iBinderList.Count() == 0);
+ iConnectionInfo.Close();
+ // iIntf doesn't need to be deleted explicitly, as it will be deleted
+ // when the last Close() is issued on it (i.e. either by us or by the TCP/IP
+ // stack). At the time of writing, our call to Close() is the last one and
+ // will delete it.
+ LOG_NODE_DESTROY(KIPProtoTag1, CIPShimSubConnectionFlow);
+ }
+
+MFlowBinderControl* CIPShimSubConnectionFlow::DoGetBinderControlL()
+ {
+ return this;
+ }
+
+
+void CIPShimSubConnectionFlow::InitialiseDataMonitoringL(CIPShimIfBase* intf)
+ {
+ const TPacketActivity* packetActivity =
+ static_cast<const TPacketActivity*>(AccessPointConfig().FindExtension(TPacketActivity::TypeId()));
+ if (packetActivity)
+ {
+ intf->ShimNotify()->SetPacketActivityFlag(packetActivity->iPacketActivity);
+ }
+ else
+ {
+ __CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("Packet activity provisioning information missing")));
+ User::Leave(KErrNotReady);
+ }
+
+ const TDataMonitoringConnProvisioningInfo* connProvisioningInfo =
+ static_cast<const TDataMonitoringConnProvisioningInfo*>(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(TDataMonitoringConnProvisioningInfo::iUid, TDataMonitoringConnProvisioningInfo::iId)));
+
+ const TDataMonitoringSubConnProvisioningInfo* subConnProvisioningInfo =
+ static_cast<const TDataMonitoringSubConnProvisioningInfo*>(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(TDataMonitoringSubConnProvisioningInfo::iUid, TDataMonitoringSubConnProvisioningInfo::iId)));
+
+ if(connProvisioningInfo && subConnProvisioningInfo)
+ {
+ intf->ShimNotify()->SetDataVolumePtrs(connProvisioningInfo->iDataVolumesPtr, subConnProvisioningInfo->iDataVolumesPtr);
+ intf->ShimNotify()->SetNotificationThresholdPtrs(connProvisioningInfo->iThresholdsPtr, subConnProvisioningInfo->iThresholdsPtr);
+ }
+ else
+ {
+ __CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("Data monitoring provisioning information missing")));
+ User::Leave(KErrNotReady);
+ }
+ }
+
+
+// ============================================================================
+//
+// from Messages::ANode
+
+void CIPShimSubConnectionFlow::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
+/**
+Receive function for incoming messages from SCPR.
+
+@param aCFMessage message from SCPR
+*/
+ {
+ CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage);
+ if(aMessage.IsMessage<TEBase::TCancel>())
+ {
+ if (iStarting )
+ {
+ StopFlow(KErrCancel);
+ }
+ }
+ else if(aMessage.IsMessage<TEChild::TDestroy>())
+ {
+ Destroy();
+ }
+ else if(aMessage.IsMessage<TCFDataClient::TBindTo>())
+ {
+ TCFDataClient::TBindTo& msg = message_cast<TCFDataClient::TBindTo>(aMessage);
+ BindToL(msg.iNodeId);
+ ASSERT(iSubConnectionProvider == aSender);
+ iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TBindToComplete().CRef());
+ }
+ else if(aMessage.IsMessage<TCFDataClient::TStart>())
+ {
+ StartFlowL();
+ }
+ else if(aMessage.IsMessage<TCFDataClient::TStop>())
+ {
+ StopFlow(static_cast<TCFDataClient::TStop&>(aMessage).iValue);
+ }
+ else if(aMessage.IsMessage<TCFDataClient::TProvisionConfig>())
+ {
+ iAccessPointConfig.Close();
+ iAccessPointConfig.Open(static_cast<TCFDataClient::TProvisionConfig&>(aMessage).iConfig);
+ ProcessProvisionConfigL();
+ }
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+ else if(aMessage.IsMessage<TCFScpr::TSetParamsRequest>())
+ {
+ UpdateIpAddressInfoL(static_cast<TCFScpr::TSetParamsRequest&>(aMessage));
+ }
+#else
+ else if(aMessage.IsMessage<TCFScpr::TParamsRequest>())
+ {
+ UpdateIpAddressInfoL(static_cast<TCFScpr::TParamsRequest&>(aMessage));
+ }
+#endif // SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+ else
+ {
+ Panic(EUnexpectedSubConnectionMsg);
+ }
+ }
+
+
+//
+// Dispatch functions for messages from SCPR
+//
+
+__CFLOG_STMT
+(
+void LOG_ADDRESS(TSockAddr addr)
+ {
+ TBuf<KMaxSockAddrSize> buff;
+ TInetAddr iaddr(addr);
+ iaddr.Output(buff);
+
+ __CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L("CIPShimSubConnectionFlow::UpdateIpAddressInfoL %S %d"), &buff, addr.Port()));
+ }
+)
+
+//helper function
+CIPProtoBinder * FindBinderForProtocol(const TDesC8& proto, RPointerArray<CIPProtoBinder> &array)
+ {
+ TInt count= array.Count();
+ for (TInt i = 0; i < count; i++)
+ {
+ if (array[i]->ProtocolName().Compare(proto) == 0)
+ {
+ return array[i];
+ }
+ }
+ return 0;
+ }
+
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+void CIPShimSubConnectionFlow::UpdateIpAddressInfoL(TCFScpr::TSetParamsRequest& aParamReq)
+#else
+void CIPShimSubConnectionFlow::UpdateIpAddressInfoL(TCFScpr::TParamsRequest& aParamReq)
+#endif // SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+ {
+
+ //[401TODO] DL: deal with the granted also.
+ const RCFParameterFamilyBundleC& newParamBundle = aParamReq.iFamilyBundle;
+
+ CSubConIPAddressInfoParamSet* IPAddressInfoSet;
+ RParameterFamily family = newParamBundle.FindFamily(KSubConIPAddressInfoFamily);
+ if ( family.IsNull() )
+ {
+ IPAddressInfoSet = NULL;
+ }
+ else
+ {
+ IPAddressInfoSet = static_cast<CSubConIPAddressInfoParamSet*>
+ (family.FindParameterSet(
+ STypeId::CreateSTypeId(CSubConIPAddressInfoParamSet::EUid,
+ CSubConIPAddressInfoParamSet::ETypeId)
+ ,RParameterFamily::ERequested));
+ }
+
+ if (IPAddressInfoSet)
+ {
+ TUint aParamSetNum = IPAddressInfoSet->GetParamNum();
+ /** TODO: It should be only one in the queue, so remove the loop */
+ for (TUint i=0; i<aParamSetNum; ++i)
+ {
+
+ CSubConIPAddressInfoParamSet::TSubConIPAddressInfo paramInfo(IPAddressInfoSet->GetParamInfoL(i));
+
+ //The only protocol we are going to deal with is TCP/IP
+ //as the flow association gets lost in when it goes through the current stack.
+ if (paramInfo.iCliDstAddr.Family() == KAfInet6 ||
+ paramInfo.iCliDstAddr.Family() == KAfInet)
+ {
+ __CFLOG_STMT(LOG_ADDRESS(paramInfo.iCliDstAddr);)
+ __CFLOG_STMT(LOG_ADDRESS(paramInfo.iCliSrcAddr);)
+
+ TInetAddr addr(paramInfo.iCliDstAddr);
+ TUint32 ipv4Addr = addr.Address();
+
+ if (iBinderList.Count())
+ {
+ CIPShimIfBase* nif = iBinderList[0]->iNif;
+ ASSERT(nif);
+ CIPProtoBinder *binder = 0;
+ if(ipv4Addr)
+ {
+ //find ip4 binder
+ binder = FindBinderForProtocol(KProtocolIp, iBinderList);
+ }
+ else
+ {
+ //find ip6 binder
+ binder = FindBinderForProtocol(KProtocolIp6, iBinderList);
+ }
+
+ if (IPAddressInfoSet->GetOperationCode() == CSubConIPAddressInfoParamSet::EDelete)
+ {
+ nif->RemoveIpAddrInfo(binder, paramInfo);
+ }
+ else
+ {
+ nif->AddIpAddrInfoL(binder, paramInfo);
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+class TCleanupNifPair {
+public:
+ TCleanupNifPair(CIPShimIfBase* aNif) : iNif(aNif), iBinder(NULL) {}
+
+ void Cleanup();
+ static void CleanupReleaseNif(TAny* aThis);
+
+ CIPShimIfBase* iNif;
+ CIPProtoBinder* iBinder;
+ };
+
+void TCleanupNifPair::Cleanup()
+ {
+ ASSERT(iNif);
+
+ if (iBinder)
+ {
+ iNif->UnbindFrom(iBinder);
+ iBinder->UnbindFromLowerFlow();
+ }
+ iNif->Release(KErrAbort);
+ }
+
+void TCleanupNifPair::CleanupReleaseNif(TAny* aThis)
+ {
+ TCleanupNifPair* pair = static_cast<TCleanupNifPair*>(aThis);
+ pair->Cleanup();
+ }
+
+void CIPShimSubConnectionFlow::BindToL(const Messages::TNodeId& aCommsBinder)
+ {
+ // Assumption that TCommsBinder object contains pointer to Flow
+ if (aCommsBinder.IsNull())
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ ANode& mcfNode = aCommsBinder.Node();
+#if !defined(__GCCXML__)
+ CSubConnectionFlowBase& flow = mcfnode_cast<CSubConnectionFlowBase>(mcfNode);
+#else
+ CSubConnectionFlowBase& flow = reinterpret_cast<CSubConnectionFlowBase&>(mcfNode);
+#endif
+
+ __CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("CIPShimSubConnectionFlow %08x:\tBindToL(): flow 0x%08x, protocol list '%S'"),
+ this, &flow, &iProtocolList));
+
+ MFlowBinderControl* binderControl = flow.GetBinderControlL();
+ ASSERT(binderControl);
+
+ // Loop through all the protocols in the list and create binders for them
+ TPtrC8 protoList(iProtocolList);
+ TPtrC8 proto;
+ TInt pos = KErrNotFound;
+
+ do
+ {
+ pos = protoList.LocateF(',');
+ if (pos == KErrNotFound)
+ {
+ proto.Set(protoList);
+ }
+ else
+ {
+ proto.Set(protoList.Left(pos));
+ protoList.Set(protoList.Mid(pos + 1));
+ }
+
+ if (proto.Length() > 0)
+ {
+ CIPProtoBinder* protoBinder = CIPProtoBinder::NewL(*this, proto);
+ CleanupStack::PushL(protoBinder);
+
+ CIPShimIfBase* nif = ProtocolIntf()->FindOrCreateNifL(proto,
+ reinterpret_cast<const TConnectionInfo&>(*iConnectionInfo.Ptr()));
+ TCleanupNifPair cleanuppair(nif);
+ CleanupStack::PushL(TCleanupItem(TCleanupNifPair::CleanupReleaseNif, &cleanuppair));
+
+ __CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("CIPShimSubConnectionFlow %08x:\tBindToL(): nif 0x%08x, binder 0x%08x"), this, nif, protoBinder));
+ nif->BindToL(protoBinder);
+ cleanuppair.iBinder = protoBinder;
+
+ protoBinder->BindToLowerFlowL(*binderControl);
+
+ iBinderList.AppendL(protoBinder);
+
+ CleanupStack::Pop(2);
+
+ InitialiseDataMonitoringL(nif);
+ }
+ }
+ while (pos != KErrNotFound);
+
+ NM_LOG((KIPProtoTag1, _L8("CIPShimSubConnectionFlow %08x:\tSynchronous call: From=%08x To=%08x Func=BindToL"), this, static_cast<Messages::ANode*>(this), &mcfNode));
+
+ TInt binderCount = iBinderList.Count();
+ for (TInt i = 0; i < binderCount; i++)
+ {
+ iBinderList[i]->StartL();
+ }
+ }
+
+
+
+void CIPShimSubConnectionFlow::StartFlowL()
+/**
+Message from SCPR to start.
+*/
+ {
+ ASSERT(!iStarting);
+
+ iStarting = ETrue;
+
+ PostDataClientStartedIfReady();
+ }
+
+void CIPShimSubConnectionFlow::StopFlow(TInt aError)
+/**
+Message from SCPR to stop.
+
+The aError reason code is stored to be passed to the TCP/IP stack via IfUserInterfaceDown().
+
+@param aError Reason code.
+*/
+ {
+ ASSERT(aError != KErrNone);
+ iStopCode = aError;
+
+ for(TInt i =0; i < iBinderList.Count(); i++)
+ {
+ MarkBinderForClosure(iBinderList[i]);
+ }
+ CloseMarkedBinders();
+
+ PostDataClientStoppedIfReady();
+ }
+
+
+
+void CIPShimSubConnectionFlow::ProcessProvisionConfigL()
+/**
+Message from SCPR providing configuration information.
+*/
+ {
+ const TItfInfoConfigExt* ext = static_cast<const TItfInfoConfigExt*>(AccessPointConfig().FindExtension(
+ STypeId::CreateSTypeId(KIpProtoConfigExtUid, EItfInfoConfigExt)));
+ if (ext)
+ {
+ TInt err = SetConnectionInfo(ext->iConnectionInfo);
+ if (err == KErrNone)
+ {
+ err = SetProtocolList(ext->iProtocolList);
+ }
+ if (err != KErrNone)
+ {
+ User::Leave(err);
+ }
+ }
+ }
+
+
+
+TInt CIPShimSubConnectionFlow::SetProtocolList(const TDesC8& aProtocolList)
+/**
+Save a pointer to the protocol list string in the provisioning information
+*/
+ {
+ if (aProtocolList.Length() > 0)
+ {
+ iProtocolList.Set(aProtocolList);
+ return KErrNone;
+ }
+ else
+ {
+ return KErrArgument;
+ }
+ }
+
+void CIPShimSubConnectionFlow::Destroy()
+/**
+Message from SCPR to self destruct.
+*/
+ {
+ // No-one should be bound to us from above if we are about to disappear.
+ ASSERT(iBindCallCount == 0);
+
+ MarkAllBindersForClosure();
+
+ if (iAsyncBinderClose.IsActive())
+ {
+ // Can't destroy ourselves whilst an asynchronous binder close is pending.
+ // Arrange for it to close all binders and initiate the destroy.
+ //
+ // Note that the async binder close may have been originally invoked with
+ // just a single binder marked for closure, and we are now marking them all
+ // for closure and requesting a destroy. This is the main reason for using
+ // the "marked for closure" flag - to deal with events that require further
+ // binders to be closed whilst the async binder close is still pending.
+ iDestroyPending = ETrue;
+ }
+ else
+ {
+ // No async binder close pending - close binders and destroy ourselves here.
+ CloseMarkedBinders();
+ DeleteThisFlow();
+ }
+ }
+
+//
+// Utility functions for sending messages to SCPR
+//
+
+void CIPShimSubConnectionFlow::PostDataClientStartedIfReady()
+ {
+ if (iBinderReady && iStarting)
+ {
+ iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TStarted().CRef());
+ iStarting = EFalse;
+ iStarted = ETrue;
+ }
+ }
+
+void CIPShimSubConnectionFlow::PostDataClientStoppedIfReady()
+ {
+ if (iStopCode != KErrNone)
+ {
+ iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TStopped(iStopCode).CRef());
+ iStopCode = KErrNone;
+ iStarted = EFalse;
+
+ MarkAllBindersForClosure();
+
+ if (!iAsyncBinderClose.IsActive())
+ {
+ // No async binder close pending - close binders
+ CloseMarkedBinders();
+ }
+ }
+ }
+
+void CIPShimSubConnectionFlow::Error(TInt aError)
+ {
+ ASSERT(iStarted || iStarting);
+ ASSERT(iSubConnectionProvider.IsOpen());
+ if (iStarting)
+ {
+ iSubConnectionProvider.PostMessage(Id(), TEBase::TError(TCFDataClient::TStart::Id(), aError).CRef());
+ }
+ else
+ {
+ iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError, MNifIfNotify::EDisconnect).CRef());
+ }
+
+ iStopCode = aError;
+ iStarting = EFalse;
+ }
+
+MLowerControl* CIPShimSubConnectionFlow::GetControlL(const TDesC8& aProtocol)
+ {
+ if (aProtocol.Length())
+ {
+ User::Leave(KErrNotSupported);
+ }
+ return this;
+ }
+
+MLowerDataSender* CIPShimSubConnectionFlow::BindL(const TDesC8& /*aProtocol*/, MUpperDataReceiver* /*aReceiver*/, MUpperControl* /*aControl*/)
+ {
+ iBindCallCount++;
+ if (iBindCallCount == 1)
+ {
+ iSubConnectionProvider.RNodeInterface::PostMessage(Id(), TCFControlProvider::TActive().CRef());
+ }
+ return NULL;
+ }
+
+void CIPShimSubConnectionFlow::Unbind( MUpperDataReceiver* /*aReceiver*/, MUpperControl* /*aControl*/)
+ {
+ iBindCallCount--;
+ if (iBindCallCount <= 0)
+ {
+ ASSERT(iBindCallCount == 0);
+ PostClientIdleIfIdle();
+ }
+ }
+
+CSubConnectionFlowBase* CIPShimSubConnectionFlow::Flow()
+ {
+ return this;
+ }
+
+void CIPShimSubConnectionFlow::OpenRoute()
+ {
+ // Post directly to cpr bypassing the scpr purely for efficiency
+ __CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimSubConnectionFlow %08x:\tOpenRoute()"), this);
+
+ RClientInterface::OpenPostMessageClose(Id(), TNodeCtxId(ECFActivityOpenCloseRoute, iProtocolIntf->ControlProviderId()),
+ TCFIPProtoMessage::TOpenCloseRoute(ETrue).CRef());
+ }
+
+
+void CIPShimSubConnectionFlow::CloseRoute()
+ {
+ // Post directly to cpr bypassing the scpr purely for efficiency
+ __CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimSubConnectionFlow %08x:\tCloseRoute()"), this);
+
+ RClientInterface::OpenPostMessageClose(Id(), TNodeCtxId(ECFActivityOpenCloseRoute, iProtocolIntf->ControlProviderId()),
+ TCFIPProtoMessage::TOpenCloseRoute(EFalse).CRef());
+ }
+
+void CIPShimSubConnectionFlow::PostClientIdleIfIdle()
+ {
+ if (iBindCallCount == 0)
+ {
+ iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef());
+ }
+ }
+
+
+TInt CIPShimSubConnectionFlow::Control(TUint aLevel, TUint aName, TDes8& aOption)
+ {
+ TInt err = KErrNotSupported;
+
+ //It returns interface info alias TConnectionInfo in a form of an old fashioned descriptor
+ //for SetOption
+ if (aLevel == (TUint)KSOLProvider && aName == (TUint)KSoConnectionInfo)
+ {
+ // Get the connection info from the config if it has not been stored yet in case the
+ // CTransportFlowShim locks the connection info for a host resolver and calls StartSending()
+ // on the host resolver before CIPShimSubConnectionFlow::ProcessProvisionConfigL() is called.
+ // Otherwise, if ProcessProvisionConfigL() is not called in time the CTransportFlowShim will
+ // lock to empty connection info. ProcessProvisionConfigL() is called when the
+ // CIPShimSubConnectionFlow receives the request to bind to the bearer SCPR which is not
+ // synchronised in any way with the request to bind the CIPShimSubConnectionFlow to the
+ // CTransportFlowShim which triggers the call to StartSending(). We still return
+ // KErrNotReady when we are not bound so that a socket does not try to flow on too early
+ // (this was causing failures in te_spudnetworkside). A host resolver does not check the
+ // error code when calling KSoConnectionInfo and simply uses the info if it's there anyway.
+ //
+ // See DEF128574.
+ if(iConnectionInfo.Length() == 0)
+ {
+ const TItfInfoConfigExt* ext = static_cast<const TItfInfoConfigExt*>(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(KIpProtoConfigExtUid, EItfInfoConfigExt)));
+ if (ext)
+ {
+ aOption.Copy((const TUint8*)&ext->iConnectionInfo, sizeof(TConnectionInfo));
+ err = KErrNotReady;
+ }
+ }
+ else
+ {
+ if(iConnectionInfo.Length() == 0)
+ {
+ err = KErrNotReady;
+ }
+ else
+ {
+ aOption.Copy(iConnectionInfo);
+ err = KErrNone;
+ }
+ }
+ }
+
+ return err;
+ }
+
+TInt CIPShimSubConnectionFlow::SetConnectionInfo(const TConnectionInfo& aInfo)
+ {
+ iConnectionInfo.Close();
+ TInt ret = iConnectionInfo.Create(sizeof(TConnectionInfo));
+ if (ret == KErrNone)
+ {
+ iConnectionInfo.Copy((TUint8*)&aInfo, sizeof(TConnectionInfo));
+ }
+ return ret;
+ }
+
+void CIPShimSubConnectionFlow::BinderReady()
+/**
+Called from binder to indicate that it is ready.
+*/
+ {
+ iBinderReady = ETrue;
+ PostDataClientStartedIfReady();
+ }
+
+/**
+Called from lower binder to indicate an error that renders the binder unusable
+
+Ensure that the TCP/IP stack is notified and the binder closed down.
+
+@param aError error code
+@param aIf CIPShimIfBase object associated with the binder
+*/
+#ifdef _DEBUG
+void CIPShimSubConnectionFlow::BinderError(TInt aError, CIPProtoBinder* aBinder)
+#else
+void CIPShimSubConnectionFlow::BinderError(TInt /*aError*/, CIPProtoBinder* aBinder)
+#endif
+ {
+ __CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("CIPShimSubConnectionFlow %08x:\tBinderError(%d)"), this, aError));
+
+ // NOTE:
+ // - We are currently in the stack frame of the lower binder as it makes the Error() upcall.
+ // - Calling CloseBinder() directly here will result in a recursive Unbind() and destructor
+ // downcall back into the binder. Consequently, schedule asynchronous closure of the binder
+ // to ensure that the binder does not have the burden of dealing with this recursion.
+ // - Note that CloseBinder() will also Close() the CIPShimIfBase, which may cause it to be destructed
+ // (if all other references on it are gone, in particular the TCP/IP stack)
+ MarkBinderForClosure(aBinder);
+ if (!iAsyncBinderClose.IsActive())
+ {
+ iAsyncBinderClose.Call();
+ }
+ }
+
+
+void CIPShimSubConnectionFlow::SendMessageToSubConnProvider(const Messages::TSignatureBase& aCFMessage)
+ {
+ iSubConnectionProvider.PostMessage(Id(), aCFMessage);
+ }
+
+const Messages::TNodeId& CIPShimSubConnectionFlow::GetCommsId()
+ {
+ return NodeId();
+ }
+
+
+// MIpDataMonitoringNotifications
+
+void CIPShimSubConnectionFlow::PostConnDataReceivedThresholdReached(TUint aVolume)
+ {
+ RClientInterface::OpenPostMessageClose(Id(), iProtocolIntf->ControlProviderId(),
+ TCFDataMonitoringNotification::TDataMonitoringNotification(EReceived, aVolume).CRef());
+ }
+
+void CIPShimSubConnectionFlow::PostConnDataSentThresholdReached(TUint aVolume)
+ {
+ RClientInterface::OpenPostMessageClose(Id(), iProtocolIntf->ControlProviderId(),
+ TCFDataMonitoringNotification::TDataMonitoringNotification(ESent, aVolume).CRef());
+ }
+
+void CIPShimSubConnectionFlow::PostSubConnDataReceivedThresholdReached(TUint aVolume)
+ {
+ iSubConnectionProvider.PostMessage(Id(),
+ TCFDataMonitoringNotification::TDataMonitoringNotification(EReceived, aVolume).CRef());
+ }
+
+void CIPShimSubConnectionFlow::PostSubConnDataSentThresholdReached(TUint aVolume)
+ {
+ iSubConnectionProvider.PostMessage(Id(),
+ TCFDataMonitoringNotification::TDataMonitoringNotification(ESent, aVolume).CRef());
+ }
+
+//
+// Asynchronous Binder Close routines
+//
+// Class used to asynchronously unbind/destroy a binder from outside of the binder's call stack.
+//
+
+CAsyncBinderClose::CAsyncBinderClose(CIPShimSubConnectionFlow& aFlow)
+ : CAsyncOneShot(EPriorityStandard), iFlow(aFlow)
+ {
+ }
+
+void CAsyncBinderClose::RunL()
+ {
+ iFlow.AsyncBinderClose();
+ }
+
+void CIPShimSubConnectionFlow::AsyncBinderClose()
+/**
+Main method of asynchronous binder close callback.
+*/
+ {
+ CloseMarkedBinders();
+ if (iDestroyPending)
+ {
+ // Deal with a pending Destroy() that happened whilst the asynchronous binder close was pending.
+ iDestroyPending = EFalse;
+ DeleteThisFlow();
+ }
+ }
+
+void CIPShimSubConnectionFlow::MarkAllBindersForClosure()
+/**
+Mark all binders for closure in the asynchronous binder close callback
+*/
+ {
+ for (TInt index = 0 ; index < iBinderList.Count() ; ++index)
+ {
+ MarkBinderForClosure(iBinderList[index]);
+ }
+ }
+
+void CIPShimSubConnectionFlow::MarkBinderForClosure(CIPProtoBinder* aBinder)
+ {
+ __CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("CIPShimSubConnectionFlow %08x:\tMarkBinderForClosure(%08x)"), this, aBinder));
+ aBinder->iMarkedForClosure = ETrue;
+ }
+
+void CIPShimSubConnectionFlow::CloseMarkedBinders()
+ {
+ TInt count = iBinderList.Count();
+ TBool reset = count > 0 ? ETrue : EFalse;
+ for (TInt index = count -1 ; index >= 0; --index)
+ {
+ CIPProtoBinder* binder = iBinderList[index];
+ if (binder->iMarkedForClosure)
+ {
+ CIPShimIfBase *nif = binder->iNif;
+ if (nif) // nif may have unbound itself
+ {
+ nif->RemoveIpAddrInfo(binder);
+ // The removal of interface name has to be extracted from Release() and
+ // performed before UnbindFrom() as otherwise Release() would have no CIPProtoBinders
+ // to navigate up to the Flow, which is required to remove the interface name.
+ nif->RemoveInterfaceName(binder);
+ nif->UnbindFrom(binder);
+ nif->Release(iStopCode);
+ }
+ binder->UnbindFromLowerFlow();
+
+ iBinderList.Remove(index);
+ delete binder;
+ }
+ else
+ {
+ reset = EFalse;
+ }
+ }
+
+ if (reset)
+ {
+ // If we've closed all binders in the list, and the list is non-empty, then reset it.
+ iBinderList.Reset();
+ }
+ }
+
+// Utility functions
+
+GLDEF_C void Panic(TIPShimPanic aReason)
+ {
+ _LIT(KPanicCategory, "IPShim");
+
+ User::Panic(KPanicCategory(), aReason);
+ }
+
+// =================================================================================
+//
+// Flow Factory methods
+//
+
+CIPShimFlowFactory* CIPShimFlowFactory::NewL(TAny* aConstructionParameters)
+/**
+Constructs a Default SubConnection Flow Factory
+
+@param aConstructionParameters construction data passed by ECOM
+
+@returns pointer to a constructed factory
+*/
+ {
+ CIPShimFlowFactory* ptr = new (ELeave) CIPShimFlowFactory(TUid::Uid(KIPShimFlowImplUid), *(reinterpret_cast<CSubConnectionFlowFactoryContainer*>(aConstructionParameters)));
+ return ptr;
+ }
+
+CIPShimFlowFactory::~CIPShimFlowFactory()
+ {
+ }
+
+
+CIPShimFlowFactory::CIPShimFlowFactory(TUid aFactoryId, CSubConnectionFlowFactoryContainer& aParentContainer)
+ : CSubConnectionFlowFactoryBase(aFactoryId, aParentContainer)
+/**
+Default SubConnection Flow Factory Constructor
+
+@param aFactoryId ECOM Implementation Id
+@param aParentContainer Object Owner
+*/
+ {
+ }
+
+
+CSubConnectionFlowBase* CIPShimFlowFactory::DoCreateFlowL(ESock::CProtocolIntfBase* aProtocolIntf, TFactoryQueryBase& aQuery)
+ {
+ const TDefaultFlowFactoryQuery& query = static_cast<const TDefaultFlowFactoryQuery&>(aQuery);
+ return new (ELeave) CIPShimSubConnectionFlow(*this, query.iSCprId, aProtocolIntf);
+ }
+
+CProtocolIntfFactoryBase* CIPShimFlowFactory::CreateProtocolIntfFactoryL(CProtocolIntfFactoryContainer& aParentContainer)
+ {
+ CProtocolIntfFactoryBase* factory = CIPShimProtocolIntfFactory::NewL(TUid::Uid(KIPShimFlowImplUid),
+ aParentContainer);
+ return factory;
+ }
+
+CIPShimProtocolIntf::CIPShimProtocolIntf(CProtocolIntfFactoryBase& aFactory,const Messages::TNodeId& aCprId)
+ :CProtocolIntfBase(aFactory,aCprId)
+ {
+ }
+
+CIPShimProtocolIntf::~CIPShimProtocolIntf()
+ {
+ // if there is still a nif open, then one of the ipshimflows
+ // is not being cleaned up correctly
+ ASSERT(iNifs.Count() == 0);
+ iNifs.Close();
+ }
+
+void CIPShimProtocolIntf::DoFlowCreated(ESock::CSubConnectionFlowBase& /*aFlow*/)
+ {
+ // do nothing
+ }
+
+void CIPShimProtocolIntf::DoFlowBeingDeleted(ESock::CSubConnectionFlowBase& /*aFlow*/)
+ {
+ // do nothing
+ }
+
+CIPShimIfBase* CIPShimProtocolIntf::FindOrCreateNifL(const TDesC8& aProtocol, const TConnectionInfo& aConnectionInfo)
+ {
+ CIPShimIfBase* shim = NULL;
+
+ for (TInt i = 0; i < iNifs.Count(); i++)
+ {
+ if (iNifs[i]->ProtocolName().Compare(aProtocol) == 0)
+ {
+ shim = iNifs[i];
+ break;
+ }
+ }
+ if (shim == NULL)
+ {
+ shim = CIPShimIfBase::NewL(aProtocol, this);
+
+ CleanupStack::PushL(shim);
+ iNifs.AppendL(shim);
+ CleanupStack::Pop(shim);
+
+ shim->SetConnectionInfo(aConnectionInfo);
+ }
+
+ return shim;
+ }
+
+void CIPShimProtocolIntf::NifDisappearing(CIPShimIfBase* aNif)
+ {
+ TInt index = iNifs.Find(aNif);
+ // index can be KErrNotFound if there was an OOM whilst trying to append a CIPShimIfBase to iNifs.
+ ASSERT(index >= KErrNotFound);
+ if (index >= 0)
+ {
+ iNifs.Remove(index);
+ }
+ }
+
+//TNodeCtxId(ECFActivityOpenCloseRoute, ControlProviderId())
+void CIPShimProtocolIntf::OpenRoute()
+ {
+ // Post directly to cpr bypassing the scpr purely for efficiency
+ __CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimProtocolIntf %08x:\tOpenRoute()"), this);
+
+ RClientInterface::OpenPostMessageClose(ControlProviderId(), ControlProviderId(),
+ TCFIPProtoMessage::TOpenCloseRoute(ETrue).CRef());
+ }
+
+//TNodeCtxId(ECFActivityOpenCloseRoute, ControlProviderId())
+void CIPShimProtocolIntf::CloseRoute()
+ {
+ // Post directly to cpr bypassing the scpr purely for efficiency
+ __CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimProtocolIntf %08x:\tCloseRoute()"), this);
+
+ RClientInterface::OpenPostMessageClose(ControlProviderId(), ControlProviderId(),
+ TCFIPProtoMessage::TOpenCloseRoute(EFalse).CRef());
+ }
+
+
+CIPShimProtocolIntfFactory* CIPShimProtocolIntfFactory::NewL(TUid aFactoryId,
+ ESock::CProtocolIntfFactoryContainer& aParentContainer)
+ {
+ CIPShimProtocolIntfFactory *fact = new(ELeave) CIPShimProtocolIntfFactory(aFactoryId, aParentContainer);
+ CleanupStack::PushL(fact);
+ fact->ConstructL();
+ CleanupStack::Pop(fact);
+ return fact;
+ }
+
+CProtocolIntfBase* CIPShimProtocolIntfFactory::DoCreateProtocolIntfL(TFactoryQueryBase& aQuery)
+ {
+ const TDefaultProtocolIntfFactoryQuery& query = static_cast<const TDefaultProtocolIntfFactoryQuery&>(aQuery);
+ return new(ELeave) CIPShimProtocolIntf(*this, query.iCprId);
+ }
+
+CIPShimProtocolIntfFactory::CIPShimProtocolIntfFactory(TUid aFactoryId,
+ ESock::CProtocolIntfFactoryContainer& aParentContainer)
+ :CProtocolIntfFactoryBase(aFactoryId, aParentContainer)
+ {
+ }