telephonyprotocols/secondarypdpcontextumtsdriver/spudman/src/bindman.cpp
changeset 0 3553901f7fa8
equal deleted inserted replaced
-1:000000000000 0:3553901f7fa8
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // SPUD binder manager
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20  @internalComponent
       
    21 */
       
    22 
       
    23 #include "bindman.h"
       
    24 #include "spudnotify.h"
       
    25 #include "mux.h"
       
    26 #include <nifman.h>
       
    27 
       
    28 /** Default name of lower NIF */
       
    29 _LIT(KDefaultLowerNifName, "rawip");
       
    30 
       
    31 #ifdef __FLOG_ACTIVE
       
    32 #define BINDMAN_LOG(x) SpudMan()->x
       
    33 #else
       
    34 #define BINDMAN_LOG(x)
       
    35 #endif
       
    36 
       
    37 //*****************************************************************************
       
    38 // CBindMan
       
    39 //*****************************************************************************
       
    40 
       
    41 /**
       
    42 Constructs BindMan. Ownership of aMux and aProto is transferred to this object.
       
    43 
       
    44 @param aSpudMan Reference to SpudMan object
       
    45 @param aMux Pointer to SpudMux object (ownership is transferred)
       
    46 @param aProto Pointer to SpudProtocol object (ownership is transferred)
       
    47 */
       
    48 CBindMan::CBindMan(CSpudMan& aSpudMan, CSpudMux* aMux, CSpudProtocol* aProto)
       
    49 	: iSpudMan(aSpudMan), iMux(aMux), iDeleteMux(ETrue), iSpudProtocol(aProto)
       
    50     {
       
    51     ReadLowerNifName();
       
    52 	}
       
    53 
       
    54 CBindMan::~CBindMan()
       
    55     {
       
    56     BINDMAN_LOG(__FLOG(_L("BindMan::~BindMan")));
       
    57     
       
    58     #ifdef __FLOG_ACTIVE // Log for diagnostic purposes
       
    59     TInt idx;
       
    60     for(idx = 0; idx < iBinders.Count(); ++idx)
       
    61     	{
       
    62     	if(iBinders[idx] && iBinders[idx]->IsBound())
       
    63 			{
       
    64 			BINDMAN_LOG(__FLOG_1(_L("~BindMan: deleting bound lower NIF binding for context[%d]"), idx));			
       
    65    			}
       
    66     	}
       
    67     #endif
       
    68 
       
    69     iBinders.DeleteAll();
       
    70     delete iSpudProtocol;
       
    71     if (iDeleteMux)
       
    72     	{
       
    73     	delete iMux;
       
    74     	}
       
    75 	}
       
    76 
       
    77 /**
       
    78 Reads the lower NIF name from CommDb.
       
    79 
       
    80 @todo This function incorrectly returns the default value when IfParams is of the form:
       
    81  "notlowernif=UNWANTED,lowernif=IGNORED".
       
    82  This defect is also present in CPppLcp::InitL.
       
    83 */
       
    84 void CBindMan::ReadLowerNifName(void)
       
    85 	{
       
    86 	TBuf<KCommsDbSvrMaxFieldLength> params;
       
    87 	_LIT(KInterfaceIdentifier,"lowernif=");
       
    88 	const TInt KLinkEqualsLength = 9;	// length of "lowernif="
       
    89 	ASSERT(static_cast<const TDesC&>(KInterfaceIdentifier).Length() == KLinkEqualsLength);
       
    90 
       
    91 	// Read IfParams field
       
    92 	iSpudMan.Notify()->ReadDes(TPtrC(ISP_IF_PARAMS), params);
       
    93 
       
    94 	TInt paramStartMarker = params.Find(KInterfaceIdentifier);
       
    95 
       
    96 	if (paramStartMarker == KErrNotFound)
       
    97 		{
       
    98 		// "lowernif=" not found in the string - use default lower layer
       
    99 		iLowerNifName = KDefaultLowerNifName;
       
   100 		BINDMAN_LOG(__FLOG_1(_L("Lower NIF name not configured; defaulting to %S"), &iLowerNifName));
       
   101 		}
       
   102 	else
       
   103 		{
       
   104 		// "lowernif=<nifname>" found in the string - extract the lower layer Nif name
       
   105 
       
   106 		if (paramStartMarker > 0 && params[paramStartMarker-1] != ',')
       
   107 			{
       
   108 			// "xyzlowernif=<xxx>" found rather than "lowernif=<xxx>" - use default lower layer
       
   109 			iLowerNifName = KDefaultLowerNifName;
       
   110 			BINDMAN_LOG(__FLOG_1(_L("Lower NIF name not configured; defaulting to %S"), &iLowerNifName));
       
   111 			}
       
   112 		else
       
   113 			{
       
   114 			// String of the form "[...,]lowernif=<nifname>[,...]" found - extract the Nif name
       
   115 			TPtrC postfix(params.Mid(paramStartMarker + KLinkEqualsLength));
       
   116 			TInt comma = postfix.Locate(',');
       
   117 			if (comma != KErrNotFound)
       
   118 				{
       
   119 				postfix.Set(postfix.Ptr(), comma);
       
   120 				}
       
   121 			iLowerNifName = postfix;
       
   122 			}
       
   123 		}
       
   124 	}
       
   125 
       
   126 /**
       
   127 Informs CSpudProtocol of the CProtocolBase pointer from the L3 protocol.
       
   128 */
       
   129 void CBindMan::SetProtocolBaseL(CProtocolBase* aProtocolBase) const
       
   130 	{
       
   131 	iSpudProtocol->SetProtocolBaseL(aProtocolBase);
       
   132 	}
       
   133 
       
   134 /**
       
   135 Returns the binder for the given context ID.
       
   136 @param aContextId context ID
       
   137 @return Pointer to binder object
       
   138 @leave KErrBadHandle or KErrNotReady if context ID is invalid or not found
       
   139 */
       
   140 CSpudBinderRef* CBindMan::GetRefL(TContextId aContextId) const
       
   141     {
       
   142     if (aContextId < 0 || aContextId >= iBinders.Count())
       
   143     	{
       
   144 		BINDMAN_LOG(__FLOG_1(_L("CBindMan::GetRefL invalid context ID %d"), aContextId));
       
   145 	    User::Leave(KErrBadHandle);
       
   146     	}
       
   147 	CSpudBinderRef* ref = iBinders[aContextId];
       
   148 	if (ref == NULL)
       
   149 		{
       
   150 		// This situation can frequently occur when looping through all binders
       
   151 	    User::Leave(KErrNotReady);
       
   152 		}
       
   153 	return ref;
       
   154 	}
       
   155 
       
   156 /**
       
   157 Returns the binder for any lower NIF that is available and bound.
       
   158 @return Pointer to binder object
       
   159 @leave KErrNotReady if no lower NIF is found
       
   160 */
       
   161 CSpudBinderRef* CBindMan::GetAnyRefL() const
       
   162 	{
       
   163     TInt index;
       
   164     for (index=0; index < iBinders.Count(); ++index)
       
   165     	{
       
   166     	CSpudBinderRef* ref = iBinders[index];
       
   167     	if (ref && ref->IsBound() && ref->State() != ESpudWaitBinderDelete)
       
   168     		{
       
   169     		return ref;
       
   170     		}
       
   171     	}
       
   172 	BINDMAN_LOG(__FLOG_0(_L("CBindMan::GetAnyRefL Can't find any bound NIF")));
       
   173     User::Leave(KErrNotReady);
       
   174     return NULL;	// never reached
       
   175 	}
       
   176 
       
   177 /**
       
   178 Returns the context ID the given lower NIF.
       
   179 @param aNifBase pointer to lower NIF
       
   180 @return context ID
       
   181 @leave KErrNotReady if lower NIF is not found
       
   182 */
       
   183 TContextId CBindMan::FindContextIdL(const CNifIfBase* aNifBase) const
       
   184 	{
       
   185     TContextId index;
       
   186     for (index=0; index < iBinders.Count(); ++index)
       
   187     	{
       
   188     	CSpudBinderRef* ref = iBinders[index];
       
   189     	if (ref && ref->MatchBase(aNifBase))
       
   190     		{
       
   191     		return index;
       
   192     		}
       
   193     	}
       
   194 	BINDMAN_LOG(__FLOG_1(_L("CBindMan::FindContextIdL Can't find aNifBase %x"), aNifBase));
       
   195     User::Leave(KErrNotReady);
       
   196     return KAllContexts;	// never reached
       
   197 	}
       
   198 
       
   199 /**
       
   200 Returns the number of bound contexts.
       
   201 @return Number of bound contexts
       
   202 */
       
   203 TUint CBindMan::NumContexts() const
       
   204 	{
       
   205     TInt index;
       
   206     TUint count = 0;
       
   207     for (index=0; index < iBinders.Count(); ++index)
       
   208     	{
       
   209     	CSpudBinderRef* ref = iBinders[index];
       
   210     	if (ref && ref->IsBound())
       
   211     		{
       
   212     		++count;
       
   213     		}
       
   214     	}
       
   215 	return count;
       
   216 	}
       
   217 	
       
   218 /**
       
   219 Checks if this is is the last 'valid' context in SPUD, i.e. it is bound and not marked for deletion.
       
   220 
       
   221 @param aContextID the ID of the context to check
       
   222 @return ETrue if and only if aContextId (the subject bindre) is the only valid, bound, unmarked binder.
       
   223 */
       
   224 TBool CBindMan::IsLastContext(TContextId aContextId)const
       
   225 	{
       
   226 	ASSERT(aContextId >= 0 && NumContexts() > 0); // we shouldn't be called unless we have at least 1 ctx
       
   227 	
       
   228 	TUint numLiveBoundBinders(0); 
       
   229 	TBool isTargetBinderFound(EFalse); // The binder for the subject context exists, is bound, and not marked for deletion.
       
   230 	
       
   231 	TInt binderIdx;
       
   232 	for(binderIdx = 0; binderIdx < iBinders.Count(); ++binderIdx) // sift through all the binders
       
   233 		{
       
   234 		if(iBinders[binderIdx] && // binder exists
       
   235 		   iBinders[binderIdx]->IsBound() &&  // is bound
       
   236 		   ESpudWaitBinderDelete != iBinders[binderIdx]->State() // not marked for deletion
       
   237 		)
       
   238 			{
       
   239 			++numLiveBoundBinders;
       
   240 			
       
   241 			if(binderIdx == aContextId)
       
   242 				{
       
   243 				isTargetBinderFound = ETrue;
       
   244 				}											
       
   245 			}
       
   246 		}
       
   247 	ASSERT(isTargetBinderFound); // sanity check: we have a referene to the subject binder,
       
   248 	                             // and it is 'valid': bound and not marked for deletion.	
       
   249 	
       
   250 	if(0 == numLiveBoundBinders) // No valid bound binders remain.
       
   251 		{
       
   252 		ASSERT(EFalse); // spudman thinks it has valid binders, when there are none.
       
   253 		
       
   254 		// In release builds, we can't say that there are more binders, because we have no
       
   255 		// references to them. 
       
   256 		return ETrue; // EFalse implies that we have at least 1 binder
       
   257 		}
       
   258 	else if(1 == numLiveBoundBinders) 
       
   259 		{
       
   260 		// In release builds: if live binder is not the subject context, we can't claim that the 
       
   261 		// subject context is the last one, or SPUD may shutdown when it has a context.
       
   262 		return isTargetBinderFound; // Is there another valid binder beside the subject?
       
   263 		}
       
   264 	else // > 1 
       
   265 		{
       
   266 		// Regardless of whether the subject context was found, we have more.
       
   267 		return EFalse;
       
   268 		}
       
   269 	}
       
   270 	
       
   271 /**
       
   272 Creates and returns a pointer to a new binder object. Ownership remains with BindMan;
       
   273 DeleteRef() must be called to delete the binder reference object.
       
   274 
       
   275 @param aContextId Holds the new context ID on return
       
   276 @return Pointer to binder object
       
   277 @leave KErrNotSupported if we are out of PDP contexts, or KErrNoMemory if out of RAM
       
   278 */
       
   279 CSpudBinderRef* CBindMan::GetNewRefForSecondaryL(TContextId& aContextId)
       
   280     {
       
   281     // Reusing the slot of the primary context is not allowed.
       
   282     static const TContextId KFirst2ndaryCtxIdx(KPrimaryContextId + 1);
       
   283     TContextId index;
       
   284     for (index = KFirst2ndaryCtxIdx; index < iBinders.Count(); ++index)
       
   285     	{
       
   286     	CSpudBinderRef*& ref = iBinders[index];
       
   287     	if (ref == NULL)
       
   288     		{
       
   289     		// Create a binder in this new slot
       
   290     		aContextId = index;
       
   291     		// ref is a reference to a pointer that is owned by Bindman. It will be deleted in the
       
   292     		// destructor. There is no need for CleanupStack.
       
   293     		ref = new (ELeave) CSpudBinderRef(*iSpudMan.BindMan());
       
   294     		ref->ConstructL(iSpudMan.Notify(), aContextId);
       
   295     		return ref;
       
   296     		}
       
   297     	else if (!ref->IsBound())
       
   298 			{
       
   299 			// This binder was previously constructed but unbound
       
   300 			ASSERT(ref->Notify() == iSpudMan.Notify());
       
   301     		aContextId = index;
       
   302     		return ref;
       
   303 			}
       
   304     	}
       
   305 	BINDMAN_LOG(__FLOG_0(_L("CBindMan::GetNewRefForSecondaryL No room for new binder reference")));
       
   306     User::Leave(KErrNotSupported);
       
   307     return NULL;	// never reached
       
   308 	}
       
   309 
       
   310 
       
   311 
       
   312 /** 
       
   313 Creates and returns a pointer to the new binder for the Primary PDP context.
       
   314 The primary is a special case, because it can be created only once, and it uses a special
       
   315 ID = 0.  If the primary fails then a secondary can be promoted to primary status 
       
   316 even in this case ID = 0 is not re-used because GetNewRefForSecondaryL prevents this.
       
   317 This means that KPrimaryContextId is only significant once at startup time!
       
   318 
       
   319 Ownership remains with BindMan;
       
   320 DeleteRef() must be called to delete the binder reference object.
       
   321 
       
   322 @return the pointer to the binder object for the primary pdp context.
       
   323 @leave if the construction of the binder leaves.
       
   324 */
       
   325 CSpudBinderRef* CBindMan::GetNewRefForPrimaryL()
       
   326 	{
       
   327 	CSpudBinderRef*& primRef = iBinders[KPrimaryContextId];
       
   328 	if(primRef) // We must not try to create the primary more than once.
       
   329 		{
       
   330 		ASSERT(EFalse);
       
   331 		User::Leave(KErrAlreadyExists); // Release builds
       
   332 		}
       
   333 	// primRef is a reference to a pointer that is owned by Bindman. It will be deleted in the
       
   334     // destructor. There is no need for CleanupStack.
       
   335 	primRef = new (ELeave) CSpudBinderRef(*iSpudMan.BindMan());
       
   336 	primRef->ConstructL(iSpudMan.Notify(), KPrimaryContextId);
       
   337 	return primRef;
       
   338 	}
       
   339 
       
   340 
       
   341 
       
   342 /**
       
   343 Loads a new lower NIF and bind to the binder ref
       
   344 
       
   345 @param aName Protocol name desired
       
   346 @param aBinder the binder to bind the lower NIF into.
       
   347 @see CNifAgentRef::ServiceStarted()
       
   348 */
       
   349 void CBindMan::LoadNifL(const TDesC& aName, CSpudBinderRef& aBinder)
       
   350 	{
       
   351 	BINDMAN_LOG(__FLOG_2(_L("CBindMan::LoadNifL loading NIF %S for protocol %S"), &iLowerNifName, &aName));
       
   352 	
       
   353 	CNifIfLink* lowerNif=static_cast<CNifIfLink*>(Nif::CreateInterfaceL(iLowerNifName, aBinder.Notify()));
       
   354 
       
   355 	// Increment reference count
       
   356 	lowerNif->Open();
       
   357 
       
   358 	CleanupClosePushL(*lowerNif);
       
   359 	// Create CNifIfBase and bind it
       
   360 	// Maybe binding should be left to CSpudBinderRef
       
   361 	CNifIfBase* nifBase = lowerNif->GetBinderL(aName);
       
   362 	CleanupStack::Pop();
       
   363 	
       
   364 	// Increment reference count
       
   365 	nifBase->Open();
       
   366 	
       
   367 	// Bind the lower NIF into the SPUD
       
   368 	aBinder.Bind(lowerNif, nifBase);
       
   369 	
       
   370 	// Bind the lower NIF to SpudProtocol
       
   371 	nifBase->BindL(iSpudProtocol);
       
   372 	}
       
   373 
       
   374 
       
   375 /** Deletes the dead (marked for deletion) references to lower NIF bindings..
       
   376 
       
   377 @return the number of contexts remaining after the deletion
       
   378 */
       
   379 TUint CBindMan::SweepBinders()
       
   380 	{
       
   381 	TUint liveContexts(0);
       
   382 	TInt binderIdx;
       
   383 	for(binderIdx = 0; binderIdx < iBinders.Count(); ++binderIdx) // Sift through all the binders
       
   384 		{
       
   385 		if(iBinders[binderIdx] && iBinders[binderIdx]->IsBound()) // Binder exists and is bound to a lower NIF 
       
   386 			{
       
   387 			if(ESpudWaitBinderDelete == iBinders[binderIdx]->State()) //Must be deleted
       
   388 				{
       
   389 				BINDMAN_LOG(__FLOG_1(_L("CBindMan::SweepBinders: deleting binder for context[%d]"), binderIdx));
       
   390 				delete iBinders[binderIdx];
       
   391 				iBinders[binderIdx] = NULL;
       
   392 				}
       
   393 			else // Binder exists and is bound, but is not eligible for deletion. 
       
   394 				{
       
   395 				BINDMAN_LOG(__FLOG_1(_L("CBindMan::SweepBinders: context[%d] is alive."), binderIdx));
       
   396 				++liveContexts;
       
   397 				}
       
   398 			}
       
   399 		// Binder is not bound. We don't care. It will be taken care of in the destructor.
       
   400 		}		 
       
   401 	return liveContexts; 
       
   402 	}
       
   403 
       
   404 //*****************************************************************************
       
   405 // CSpudBinderRef
       
   406 //*****************************************************************************
       
   407 
       
   408 
       
   409 CSpudBinderRef::CSpudBinderRef(CBindMan& aBindMan)
       
   410 	:iBindMan(aBindMan)
       
   411 	{
       
   412 	}
       
   413 
       
   414 CSpudBinderRef::~CSpudBinderRef()
       
   415 	{
       
   416 	if (IsBound())
       
   417 		{
       
   418 	   	// This call causes the NIF base to delete itself
       
   419 	   	iNifBase->Close();
       
   420 
       
   421 	   	// This call causes the NIF link to delete itself
       
   422 	   	iNifLink->Close();
       
   423 		}
       
   424 
       
   425    	delete iNotify;
       
   426 	}
       
   427 
       
   428 /**
       
   429 Creates a SpudNotify object.
       
   430 @leave KErrNoMemory if out of RAM
       
   431 */
       
   432 void CSpudBinderRef::ConstructL(MNifIfNotify* aNotify, TContextId aContextId)
       
   433 	{
       
   434 	iNotify = new (ELeave) CSpudNotify(iBindMan, aNotify, aContextId);
       
   435 	}