diff -r 000000000000 -r af10295192d8 networkcontrol/ipnetworklayer/src/flow.cpp --- /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 +#include +#include +#include +#include +#include +#include "flow.h" +#include "nif.h" +#include "panic.h" +#include "ItfInfoConfigExt.h" +#include "IPProtoMessages.h" // TCFIPProtoMessage +#include "IPProtoCPR.h" +#include "idletimer.h" +#include +#include "IPProtoDeMux.h" +#include +#include + +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(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(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(TDataMonitoringConnProvisioningInfo::iUid, TDataMonitoringConnProvisioningInfo::iId))); + + const TDataMonitoringSubConnProvisioningInfo* subConnProvisioningInfo = + static_cast(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()) + { + if (iStarting ) + { + StopFlow(KErrCancel); + } + } + else if(aMessage.IsMessage()) + { + Destroy(); + } + else if(aMessage.IsMessage()) + { + TCFDataClient::TBindTo& msg = message_cast(aMessage); + BindToL(msg.iNodeId); + ASSERT(iSubConnectionProvider == aSender); + iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TBindToComplete().CRef()); + } + else if(aMessage.IsMessage()) + { + StartFlowL(); + } + else if(aMessage.IsMessage()) + { + StopFlow(static_cast(aMessage).iValue); + } + else if(aMessage.IsMessage()) + { + iAccessPointConfig.Close(); + iAccessPointConfig.Open(static_cast(aMessage).iConfig); + ProcessProvisionConfigL(); + } +#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW + else if(aMessage.IsMessage()) + { + UpdateIpAddressInfoL(static_cast(aMessage)); + } +#else + else if(aMessage.IsMessage()) + { + UpdateIpAddressInfoL(static_cast(aMessage)); + } +#endif // SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW + else + { + Panic(EUnexpectedSubConnectionMsg); + } + } + + +// +// Dispatch functions for messages from SCPR +// + +__CFLOG_STMT +( +void LOG_ADDRESS(TSockAddr addr) + { + TBuf 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 &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 + (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; iGetParamInfoL(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(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(mcfNode); +#else + CSubConnectionFlowBase& flow = reinterpret_cast(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(*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(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(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(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(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(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(aQuery); + return new(ELeave) CIPShimProtocolIntf(*this, query.iCprId); + } + +CIPShimProtocolIntfFactory::CIPShimProtocolIntfFactory(TUid aFactoryId, + ESock::CProtocolIntfFactoryContainer& aParentContainer) + :CProtocolIntfFactoryBase(aFactoryId, aParentContainer) + { + }