--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyprotocols/secondarypdpcontextumtsdriver/spudman/src/bindman.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,435 @@
+// Copyright (c) 2004-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:
+// SPUD binder manager
+//
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include "bindman.h"
+#include "spudnotify.h"
+#include "mux.h"
+#include <nifman.h>
+
+/** Default name of lower NIF */
+_LIT(KDefaultLowerNifName, "rawip");
+
+#ifdef __FLOG_ACTIVE
+#define BINDMAN_LOG(x) SpudMan()->x
+#else
+#define BINDMAN_LOG(x)
+#endif
+
+//*****************************************************************************
+// CBindMan
+//*****************************************************************************
+
+/**
+Constructs BindMan. Ownership of aMux and aProto is transferred to this object.
+
+@param aSpudMan Reference to SpudMan object
+@param aMux Pointer to SpudMux object (ownership is transferred)
+@param aProto Pointer to SpudProtocol object (ownership is transferred)
+*/
+CBindMan::CBindMan(CSpudMan& aSpudMan, CSpudMux* aMux, CSpudProtocol* aProto)
+ : iSpudMan(aSpudMan), iMux(aMux), iDeleteMux(ETrue), iSpudProtocol(aProto)
+ {
+ ReadLowerNifName();
+ }
+
+CBindMan::~CBindMan()
+ {
+ BINDMAN_LOG(__FLOG(_L("BindMan::~BindMan")));
+
+ #ifdef __FLOG_ACTIVE // Log for diagnostic purposes
+ TInt idx;
+ for(idx = 0; idx < iBinders.Count(); ++idx)
+ {
+ if(iBinders[idx] && iBinders[idx]->IsBound())
+ {
+ BINDMAN_LOG(__FLOG_1(_L("~BindMan: deleting bound lower NIF binding for context[%d]"), idx));
+ }
+ }
+ #endif
+
+ iBinders.DeleteAll();
+ delete iSpudProtocol;
+ if (iDeleteMux)
+ {
+ delete iMux;
+ }
+ }
+
+/**
+Reads the lower NIF name from CommDb.
+
+@todo This function incorrectly returns the default value when IfParams is of the form:
+ "notlowernif=UNWANTED,lowernif=IGNORED".
+ This defect is also present in CPppLcp::InitL.
+*/
+void CBindMan::ReadLowerNifName(void)
+ {
+ TBuf<KCommsDbSvrMaxFieldLength> params;
+ _LIT(KInterfaceIdentifier,"lowernif=");
+ const TInt KLinkEqualsLength = 9; // length of "lowernif="
+ ASSERT(static_cast<const TDesC&>(KInterfaceIdentifier).Length() == KLinkEqualsLength);
+
+ // Read IfParams field
+ iSpudMan.Notify()->ReadDes(TPtrC(ISP_IF_PARAMS), params);
+
+ TInt paramStartMarker = params.Find(KInterfaceIdentifier);
+
+ if (paramStartMarker == KErrNotFound)
+ {
+ // "lowernif=" not found in the string - use default lower layer
+ iLowerNifName = KDefaultLowerNifName;
+ BINDMAN_LOG(__FLOG_1(_L("Lower NIF name not configured; defaulting to %S"), &iLowerNifName));
+ }
+ else
+ {
+ // "lowernif=<nifname>" found in the string - extract the lower layer Nif name
+
+ if (paramStartMarker > 0 && params[paramStartMarker-1] != ',')
+ {
+ // "xyzlowernif=<xxx>" found rather than "lowernif=<xxx>" - use default lower layer
+ iLowerNifName = KDefaultLowerNifName;
+ BINDMAN_LOG(__FLOG_1(_L("Lower NIF name not configured; defaulting to %S"), &iLowerNifName));
+ }
+ else
+ {
+ // String of the form "[...,]lowernif=<nifname>[,...]" found - extract the Nif name
+ TPtrC postfix(params.Mid(paramStartMarker + KLinkEqualsLength));
+ TInt comma = postfix.Locate(',');
+ if (comma != KErrNotFound)
+ {
+ postfix.Set(postfix.Ptr(), comma);
+ }
+ iLowerNifName = postfix;
+ }
+ }
+ }
+
+/**
+Informs CSpudProtocol of the CProtocolBase pointer from the L3 protocol.
+*/
+void CBindMan::SetProtocolBaseL(CProtocolBase* aProtocolBase) const
+ {
+ iSpudProtocol->SetProtocolBaseL(aProtocolBase);
+ }
+
+/**
+Returns the binder for the given context ID.
+@param aContextId context ID
+@return Pointer to binder object
+@leave KErrBadHandle or KErrNotReady if context ID is invalid or not found
+*/
+CSpudBinderRef* CBindMan::GetRefL(TContextId aContextId) const
+ {
+ if (aContextId < 0 || aContextId >= iBinders.Count())
+ {
+ BINDMAN_LOG(__FLOG_1(_L("CBindMan::GetRefL invalid context ID %d"), aContextId));
+ User::Leave(KErrBadHandle);
+ }
+ CSpudBinderRef* ref = iBinders[aContextId];
+ if (ref == NULL)
+ {
+ // This situation can frequently occur when looping through all binders
+ User::Leave(KErrNotReady);
+ }
+ return ref;
+ }
+
+/**
+Returns the binder for any lower NIF that is available and bound.
+@return Pointer to binder object
+@leave KErrNotReady if no lower NIF is found
+*/
+CSpudBinderRef* CBindMan::GetAnyRefL() const
+ {
+ TInt index;
+ for (index=0; index < iBinders.Count(); ++index)
+ {
+ CSpudBinderRef* ref = iBinders[index];
+ if (ref && ref->IsBound() && ref->State() != ESpudWaitBinderDelete)
+ {
+ return ref;
+ }
+ }
+ BINDMAN_LOG(__FLOG_0(_L("CBindMan::GetAnyRefL Can't find any bound NIF")));
+ User::Leave(KErrNotReady);
+ return NULL; // never reached
+ }
+
+/**
+Returns the context ID the given lower NIF.
+@param aNifBase pointer to lower NIF
+@return context ID
+@leave KErrNotReady if lower NIF is not found
+*/
+TContextId CBindMan::FindContextIdL(const CNifIfBase* aNifBase) const
+ {
+ TContextId index;
+ for (index=0; index < iBinders.Count(); ++index)
+ {
+ CSpudBinderRef* ref = iBinders[index];
+ if (ref && ref->MatchBase(aNifBase))
+ {
+ return index;
+ }
+ }
+ BINDMAN_LOG(__FLOG_1(_L("CBindMan::FindContextIdL Can't find aNifBase %x"), aNifBase));
+ User::Leave(KErrNotReady);
+ return KAllContexts; // never reached
+ }
+
+/**
+Returns the number of bound contexts.
+@return Number of bound contexts
+*/
+TUint CBindMan::NumContexts() const
+ {
+ TInt index;
+ TUint count = 0;
+ for (index=0; index < iBinders.Count(); ++index)
+ {
+ CSpudBinderRef* ref = iBinders[index];
+ if (ref && ref->IsBound())
+ {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+/**
+Checks if this is is the last 'valid' context in SPUD, i.e. it is bound and not marked for deletion.
+
+@param aContextID the ID of the context to check
+@return ETrue if and only if aContextId (the subject bindre) is the only valid, bound, unmarked binder.
+*/
+TBool CBindMan::IsLastContext(TContextId aContextId)const
+ {
+ ASSERT(aContextId >= 0 && NumContexts() > 0); // we shouldn't be called unless we have at least 1 ctx
+
+ TUint numLiveBoundBinders(0);
+ TBool isTargetBinderFound(EFalse); // The binder for the subject context exists, is bound, and not marked for deletion.
+
+ TInt binderIdx;
+ for(binderIdx = 0; binderIdx < iBinders.Count(); ++binderIdx) // sift through all the binders
+ {
+ if(iBinders[binderIdx] && // binder exists
+ iBinders[binderIdx]->IsBound() && // is bound
+ ESpudWaitBinderDelete != iBinders[binderIdx]->State() // not marked for deletion
+ )
+ {
+ ++numLiveBoundBinders;
+
+ if(binderIdx == aContextId)
+ {
+ isTargetBinderFound = ETrue;
+ }
+ }
+ }
+ ASSERT(isTargetBinderFound); // sanity check: we have a referene to the subject binder,
+ // and it is 'valid': bound and not marked for deletion.
+
+ if(0 == numLiveBoundBinders) // No valid bound binders remain.
+ {
+ ASSERT(EFalse); // spudman thinks it has valid binders, when there are none.
+
+ // In release builds, we can't say that there are more binders, because we have no
+ // references to them.
+ return ETrue; // EFalse implies that we have at least 1 binder
+ }
+ else if(1 == numLiveBoundBinders)
+ {
+ // In release builds: if live binder is not the subject context, we can't claim that the
+ // subject context is the last one, or SPUD may shutdown when it has a context.
+ return isTargetBinderFound; // Is there another valid binder beside the subject?
+ }
+ else // > 1
+ {
+ // Regardless of whether the subject context was found, we have more.
+ return EFalse;
+ }
+ }
+
+/**
+Creates and returns a pointer to a new binder object. Ownership remains with BindMan;
+DeleteRef() must be called to delete the binder reference object.
+
+@param aContextId Holds the new context ID on return
+@return Pointer to binder object
+@leave KErrNotSupported if we are out of PDP contexts, or KErrNoMemory if out of RAM
+*/
+CSpudBinderRef* CBindMan::GetNewRefForSecondaryL(TContextId& aContextId)
+ {
+ // Reusing the slot of the primary context is not allowed.
+ static const TContextId KFirst2ndaryCtxIdx(KPrimaryContextId + 1);
+ TContextId index;
+ for (index = KFirst2ndaryCtxIdx; index < iBinders.Count(); ++index)
+ {
+ CSpudBinderRef*& ref = iBinders[index];
+ if (ref == NULL)
+ {
+ // Create a binder in this new slot
+ aContextId = index;
+ // ref is a reference to a pointer that is owned by Bindman. It will be deleted in the
+ // destructor. There is no need for CleanupStack.
+ ref = new (ELeave) CSpudBinderRef(*iSpudMan.BindMan());
+ ref->ConstructL(iSpudMan.Notify(), aContextId);
+ return ref;
+ }
+ else if (!ref->IsBound())
+ {
+ // This binder was previously constructed but unbound
+ ASSERT(ref->Notify() == iSpudMan.Notify());
+ aContextId = index;
+ return ref;
+ }
+ }
+ BINDMAN_LOG(__FLOG_0(_L("CBindMan::GetNewRefForSecondaryL No room for new binder reference")));
+ User::Leave(KErrNotSupported);
+ return NULL; // never reached
+ }
+
+
+
+/**
+Creates and returns a pointer to the new binder for the Primary PDP context.
+The primary is a special case, because it can be created only once, and it uses a special
+ID = 0. If the primary fails then a secondary can be promoted to primary status
+even in this case ID = 0 is not re-used because GetNewRefForSecondaryL prevents this.
+This means that KPrimaryContextId is only significant once at startup time!
+
+Ownership remains with BindMan;
+DeleteRef() must be called to delete the binder reference object.
+
+@return the pointer to the binder object for the primary pdp context.
+@leave if the construction of the binder leaves.
+*/
+CSpudBinderRef* CBindMan::GetNewRefForPrimaryL()
+ {
+ CSpudBinderRef*& primRef = iBinders[KPrimaryContextId];
+ if(primRef) // We must not try to create the primary more than once.
+ {
+ ASSERT(EFalse);
+ User::Leave(KErrAlreadyExists); // Release builds
+ }
+ // primRef is a reference to a pointer that is owned by Bindman. It will be deleted in the
+ // destructor. There is no need for CleanupStack.
+ primRef = new (ELeave) CSpudBinderRef(*iSpudMan.BindMan());
+ primRef->ConstructL(iSpudMan.Notify(), KPrimaryContextId);
+ return primRef;
+ }
+
+
+
+/**
+Loads a new lower NIF and bind to the binder ref
+
+@param aName Protocol name desired
+@param aBinder the binder to bind the lower NIF into.
+@see CNifAgentRef::ServiceStarted()
+*/
+void CBindMan::LoadNifL(const TDesC& aName, CSpudBinderRef& aBinder)
+ {
+ BINDMAN_LOG(__FLOG_2(_L("CBindMan::LoadNifL loading NIF %S for protocol %S"), &iLowerNifName, &aName));
+
+ CNifIfLink* lowerNif=static_cast<CNifIfLink*>(Nif::CreateInterfaceL(iLowerNifName, aBinder.Notify()));
+
+ // Increment reference count
+ lowerNif->Open();
+
+ CleanupClosePushL(*lowerNif);
+ // Create CNifIfBase and bind it
+ // Maybe binding should be left to CSpudBinderRef
+ CNifIfBase* nifBase = lowerNif->GetBinderL(aName);
+ CleanupStack::Pop();
+
+ // Increment reference count
+ nifBase->Open();
+
+ // Bind the lower NIF into the SPUD
+ aBinder.Bind(lowerNif, nifBase);
+
+ // Bind the lower NIF to SpudProtocol
+ nifBase->BindL(iSpudProtocol);
+ }
+
+
+/** Deletes the dead (marked for deletion) references to lower NIF bindings..
+
+@return the number of contexts remaining after the deletion
+*/
+TUint CBindMan::SweepBinders()
+ {
+ TUint liveContexts(0);
+ TInt binderIdx;
+ for(binderIdx = 0; binderIdx < iBinders.Count(); ++binderIdx) // Sift through all the binders
+ {
+ if(iBinders[binderIdx] && iBinders[binderIdx]->IsBound()) // Binder exists and is bound to a lower NIF
+ {
+ if(ESpudWaitBinderDelete == iBinders[binderIdx]->State()) //Must be deleted
+ {
+ BINDMAN_LOG(__FLOG_1(_L("CBindMan::SweepBinders: deleting binder for context[%d]"), binderIdx));
+ delete iBinders[binderIdx];
+ iBinders[binderIdx] = NULL;
+ }
+ else // Binder exists and is bound, but is not eligible for deletion.
+ {
+ BINDMAN_LOG(__FLOG_1(_L("CBindMan::SweepBinders: context[%d] is alive."), binderIdx));
+ ++liveContexts;
+ }
+ }
+ // Binder is not bound. We don't care. It will be taken care of in the destructor.
+ }
+ return liveContexts;
+ }
+
+//*****************************************************************************
+// CSpudBinderRef
+//*****************************************************************************
+
+
+CSpudBinderRef::CSpudBinderRef(CBindMan& aBindMan)
+ :iBindMan(aBindMan)
+ {
+ }
+
+CSpudBinderRef::~CSpudBinderRef()
+ {
+ if (IsBound())
+ {
+ // This call causes the NIF base to delete itself
+ iNifBase->Close();
+
+ // This call causes the NIF link to delete itself
+ iNifLink->Close();
+ }
+
+ delete iNotify;
+ }
+
+/**
+Creates a SpudNotify object.
+@leave KErrNoMemory if out of RAM
+*/
+void CSpudBinderRef::ConstructL(MNifIfNotify* aNotify, TContextId aContextId)
+ {
+ iNotify = new (ELeave) CSpudNotify(iBindMan, aNotify, aContextId);
+ }