authenticationservices/authenticationserver/source/server/evaluator.cpp
changeset 29 ece3df019add
equal deleted inserted replaced
19:cd501b96611d 29:ece3df019add
       
     1 /*
       
     2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "authserver_impl.h"
       
    20 
       
    21 
       
    22 using namespace AuthServer;
       
    23 
       
    24 const CAuthExpressionImpl::TType CEvaluator::KAnd = CAuthExpressionImpl::EAnd;
       
    25 const CAuthExpressionImpl::TType CEvaluator::KOr = CAuthExpressionImpl::EOr;
       
    26 const TInt CEvaluator::KRPNGranularity = 4;
       
    27 
       
    28 // -------- (de)allocation --------
       
    29 
       
    30 
       
    31 CEvaluator* CEvaluator::NewL(MEvaluatorPluginInterface* aPluginInterface, MEvaluatorClientInterface* aClientInterface)
       
    32 /**
       
    33 	Factory function allocates and initializes new
       
    34 	instance of CEvaluator.
       
    35 	
       
    36 	@param	aPluginInterface	Used to invoke plugins.
       
    37 	@param	aClientInterface	Used to notify clients when
       
    38 								an evaluation has completed.
       
    39  */
       
    40 	{
       
    41 	CEvaluator* ev = new(ELeave) CEvaluator(aPluginInterface, aClientInterface);
       
    42 	CleanupStack::PushL(ev);
       
    43 	ev->ConstructL();
       
    44 	CleanupStack::Pop(ev);
       
    45 	return ev;
       
    46 	}
       
    47 
       
    48 
       
    49 CEvaluator::CEvaluator(MEvaluatorPluginInterface* aPluginInterface, MEvaluatorClientInterface* aClientInterface)
       
    50 /**
       
    51 	Constructor records the supplied plugin and client interfaces.
       
    52 	
       
    53 	@param	aPluginInterface	Used to invoke plugins.
       
    54 	@param	aClientInterface	Used to notify clients when
       
    55 								an evaluation has completed.
       
    56  */
       
    57 :	CActive(CActive::EPriorityStandard),
       
    58 	iPluginInterface(aPluginInterface),
       
    59 	iClientInterface(aClientInterface)
       
    60 //	,iRpnStack(0)
       
    61 	{
       
    62 	CActiveScheduler::Add(this);
       
    63 	}
       
    64 
       
    65 
       
    66 void CEvaluator::ConstructL()
       
    67 /**
       
    68 	Allocate resources (i.e. RPN stack) used by
       
    69 	this object throughout its lifetime.
       
    70  */
       
    71 	{
       
    72 	iRpnStack = new(ELeave) CArrayFixFlat<TIdentityId>(KRPNGranularity);
       
    73 	}
       
    74 
       
    75 
       
    76 CEvaluator::~CEvaluator()
       
    77 /**
       
    78 	Free any resources (i.e. RPN stack) successfully
       
    79 	allocated by this object.
       
    80  */
       
    81 	{
       
    82 	Cancel();
       
    83 	delete iRpnStack;
       
    84 	}
       
    85 
       
    86 
       
    87 // -------- evaluation --------
       
    88 
       
    89 
       
    90 void CEvaluator::Evaluate(const CAuthExpressionImpl* aExpr)
       
    91 /**
       
    92 	Evaluate the current expression.  This finds
       
    93 	the leftmost leaf node from the supplied expression
       
    94 	and calls the appropriate plugin.
       
    95  */
       
    96 	{
       
    97 	__ASSERT_DEBUG(!IsActive(),
       
    98 					Panic(EBusy));	
       
    99 	// iterate through left branches until find
       
   100 	// a leaf node
       
   101 	
       
   102 	while (aExpr->Type() == KAnd || aExpr->Type() == KOr)
       
   103 		{
       
   104 		aExpr = aExpr->Left();
       
   105 		}
       
   106 	
       
   107 	iCurrentNode = aExpr;
       
   108 	
       
   109 	if (aExpr->Type() == CAuthExpressionImpl::EPluginId)
       
   110 		iPluginInterface->Evaluate(aExpr->PluginId(), iIdentity, aExpr->Type(), iStatus);
       
   111 	else if (aExpr->Type() == CAuthExpressionImpl::ENull)
       
   112 		{
       
   113 		iPluginInterface->Evaluate(0, iIdentity, aExpr->Type(), iStatus);
       
   114 		}
       
   115 	else /* aExpr->Type() == CAuthExpression::EPluginType */
       
   116 		iPluginInterface->Evaluate(aExpr->PluginType(), iIdentity, aExpr->Type(), iStatus);
       
   117 	SetActive();
       
   118 	}
       
   119 
       
   120 
       
   121 void CEvaluator::RunL()
       
   122 /**
       
   123 	Implement CActive by recording the identity
       
   124 	returned by the plugin.  If the individual
       
   125 	plugin failed then fail the entire evaluation.
       
   126  */
       
   127 	{
       
   128 	switch (iStatus.Int())
       
   129 	    {
       
   130 	    case KErrAuthServPluginNotActive:
       
   131 	        // don't break
       
   132 	    case KErrAuthServPluginCancelled:
       
   133 	        iIdentity = KUnknownIdentity;
       
   134 	        // don't break
       
   135 	    case KErrNone:
       
   136 	        EvaluatedNode(iIdentity);
       
   137     		break;
       
   138     	default: 
       
   139     	    NotifyClientFailed(iStatus.Int());
       
   140     	    break;
       
   141 	    }
       
   142 	}
       
   143 
       
   144 
       
   145 void CEvaluator::DoCancel()
       
   146 /**
       
   147 	Implement CActive.  This function does not
       
   148 	currently do anything.
       
   149  */
       
   150 	{
       
   151 	iPluginInterface->CancelEvaluate();
       
   152 
       
   153 	NotifyClientFailed(KErrCancel);
       
   154 	}
       
   155 
       
   156 void CEvaluator::EvaluatedNode(TIdentityId aIdentity)
       
   157 /**
       
   158 	This function is called when the plugin has
       
   159 	returned an identity.
       
   160 	
       
   161 	If it is a root node then complete the client request.
       
   162 
       
   163 	If it is a left node, then push the identity on the
       
   164 	RPN stack and evaluate the right node.
       
   165 	
       
   166 	If it is a right node then combine it with the stacked
       
   167 	left result using the parent node's operator.
       
   168  */
       
   169 	{
       
   170 	CAuthExpressionImpl* parent = iCurrentNode->Parent();
       
   171 	
       
   172 	// If parent node complete client request.
       
   173 	// This path is only used if the expression contains
       
   174 	// a single leaf node.  If the root node is complex
       
   175 	// then EvaluateCompound() calls HaveFinalResult().
       
   176 	if (parent == 0)
       
   177 		{
       
   178 		__ASSERT_DEBUG(RpnDepth() == 0, Panic(EENRpnStackNonZero));
       
   179 		NotifyClientSucceeded(aIdentity);
       
   180 		}
       
   181 	// if left node then push identity and evaluate sibling
       
   182 	else
       
   183 		{	
       
   184 		if (! PushIdentity(aIdentity))
       
   185 			NotifyClientFailed(KErrNoMemory);
       
   186 		else
       
   187 			{
       
   188 			const CAuthExpressionImpl* rhsExpr = parent->Right();
       
   189 			// if just evaluated RHS then compound result
       
   190 			if (rhsExpr == iCurrentNode)
       
   191 				{
       
   192 				EvaluateCompound(parent);
       
   193 				}
       
   194 			else if ( 	(aIdentity == KUnknownIdentity && parent->Type() == KAnd) || 
       
   195 						(aIdentity != KUnknownIdentity && parent->Type() == KOr)
       
   196 					)
       
   197 				{
       
   198 				if (! PushIdentity(aIdentity))
       
   199 					NotifyClientFailed(KErrNoMemory);
       
   200 				else
       
   201 					EvaluateCompound(parent);
       
   202 				}
       
   203 			// can't be short-circuited so evaluate RHS
       
   204 			else
       
   205 				{
       
   206 				Evaluate(rhsExpr);
       
   207 				}
       
   208 			}	// else (! PushIdentity(aIdentity))
       
   209 		}
       
   210 	}
       
   211 
       
   212 
       
   213 void CEvaluator::EvaluateCompound(const CAuthExpressionImpl* aParent)
       
   214 /**
       
   215 	This function is called by EvaluatedNode when
       
   216 	both the left and right identities are on the
       
   217 	RPN stack.
       
   218 	
       
   219 	Those two values are replaced with a single value
       
   220 	from the combining operator.
       
   221  */
       
   222 	{
       
   223 	__ASSERT_DEBUG(RpnDepth() >= 2, Panic(EECRpnStackTooLow));
       
   224 	TIdentityId rhs = PopIdentity();
       
   225 	TIdentityId& lhs = LastIdentity();	// replace this with result
       
   226 	
       
   227 	switch (aParent->Type())
       
   228 		{
       
   229 	case KAnd:
       
   230 		// unknown if left and right don't match.
       
   231 		// These are both unknown for short-circuit.
       
   232 		if (lhs != rhs)
       
   233 			lhs = KUnknownIdentity;
       
   234 		break;
       
   235 	
       
   236 	case KOr:
       
   237 		// only take right value if left unknown.
       
   238 		// Both same non-unknown for short-circuit.
       
   239 		if (lhs == KUnknownIdentity)
       
   240 			lhs = rhs;
       
   241 		break;
       
   242 	
       
   243 	default:
       
   244 		__ASSERT_DEBUG(EFalse, Panic(EECBadParentType));
       
   245 		break;
       
   246 		}
       
   247 	
       
   248 	// combine the parent complex node with _its_ sibling
       
   249 	CAuthExpressionImpl* parent2 = aParent->Parent();
       
   250 
       
   251 	// if parent2 is the root node, then complete the client request
       
   252 	if (parent2 == 0)
       
   253 		{
       
   254 		__ASSERT_DEBUG(RpnDepth() == 1, Panic(EECRpnStackNotOneAtRoot));
       
   255 		// reset stack after notifying client because
       
   256 		// lhs is a reference to the top (only) item.
       
   257 		NotifyClientSucceeded(lhs);
       
   258 		}
       
   259 	
       
   260 	// if parent is parent2's left node then evaluate parent's right
       
   261 	// sibling.  At this point parent's result is on the stack.
       
   262 	else if (parent2->Left() == aParent)
       
   263 		{
       
   264 		// (lhs == unknown && type == AND) || (lhs != unknown && type == OR)
       
   265 		if ((lhs == KUnknownIdentity) == (parent2->Type() == KAnd))
       
   266 			{
       
   267 			if (! PushIdentity(lhs))
       
   268 				NotifyClientFailed(KErrNoMemory);
       
   269 			else
       
   270 				EvaluateCompound(parent2);
       
   271 			}
       
   272 		
       
   273 		else
       
   274 			Evaluate(parent2->Right());
       
   275 		}
       
   276 	
       
   277 	// parent must have been parent2's right child so combine
       
   278 	// its result with its left sibling.
       
   279 	else
       
   280 		{
       
   281 		__ASSERT_DEBUG(parent2->Right() == aParent, Panic(EECBadRightParent));
       
   282 		EvaluateCompound(parent2);
       
   283 		}
       
   284 	}
       
   285 
       
   286 
       
   287 // -------- client notification --------
       
   288 
       
   289 
       
   290 void CEvaluator::NotifyClientSucceeded(TIdentityId aIdentityId)
       
   291 /**
       
   292 	Notify the client that the evaluation has completed
       
   293 	successfully, and free the RPNStack.
       
   294 	
       
   295 	@param	aIdentityId		Identified user.  This can be KUnknownIdentity.
       
   296  */
       
   297 	{
       
   298 	iClientInterface->EvaluationSucceeded(aIdentityId);
       
   299 	ResetRpnStack();
       
   300 	}
       
   301 
       
   302 
       
   303 void CEvaluator::NotifyClientFailed(TInt aReason)
       
   304 /**
       
   305 	Notify the client that the evaluation has failed
       
   306 	and free the RPN stack.
       
   307 	
       
   308 	@param	aReason			Symbian OS error code.
       
   309  */
       
   310 	{
       
   311 	iClientInterface->EvaluationFailed(aReason);
       
   312 	ResetRpnStack();
       
   313 	}
       
   314 
       
   315 
       
   316 // -------- RPN stack --------
       
   317 
       
   318 
       
   319 TBool CEvaluator::PushIdentity(TIdentityId aIdentity)
       
   320 /**
       
   321 	Append the supplied entity to the RPN stack.
       
   322 	
       
   323 	@param	aIdentity		Function to append to the RPN stack.
       
   324 	@return					zero if could not append the item,
       
   325 							i.e. OOM, non-zero otherwise.
       
   326  */
       
   327 	{
       
   328 	TRAPD(r, iRpnStack->AppendL(aIdentity));
       
   329 	return r == KErrNone;
       
   330 	}
       
   331 
       
   332 
       
   333 TIdentityId CEvaluator::PopIdentity()
       
   334 /**
       
   335 	Remove the last identity from the RPN stack
       
   336 	and return it.
       
   337 	
       
   338 	@return					The identity which was the last
       
   339 							item on the RPN stack when this
       
   340 							function was called.
       
   341 	@pre The RPN stack contains at least one identity.
       
   342  */
       
   343 	{
       
   344 	TInt lastIndex = iRpnStack->Count() - 1;
       
   345 	TIdentityId id = iRpnStack->At(lastIndex);
       
   346 	
       
   347 	// This function will not leave because the array
       
   348 	// if not being grown.  It is only trapped to satisfy
       
   349 	// leavescan.
       
   350 	
       
   351 	TRAP_IGNORE(iRpnStack->ResizeL(lastIndex));
       
   352 	return id;
       
   353 	}
       
   354 
       
   355 
       
   356 TIdentityId& CEvaluator::LastIdentity()
       
   357 /**
       
   358 	Return a reference to the last item on the
       
   359 	RPN stack.  This function is defined so
       
   360 	ReplaceComplexIdentity() can efficiently
       
   361 	put a result on the RPN stack without reallocating.
       
   362 	
       
   363 	@return					Reference to last item on the RPN stack.
       
   364 	@pre The RPN stack contains at least one identity.
       
   365  */
       
   366 	{
       
   367 	TInt lastIndex = iRpnStack->Count() - 1;
       
   368 	return iRpnStack->At(lastIndex);	
       
   369 	}
       
   370 
       
   371 
       
   372 void CEvaluator::ResetRpnStack()
       
   373 /**
       
   374 	Clear the RPN stack.
       
   375  */
       
   376 	{
       
   377 	iRpnStack->Reset();
       
   378 	}
       
   379 
       
   380 
       
   381 #ifdef _DEBUG
       
   382 
       
   383 
       
   384 TInt CEvaluator::RpnDepth() const
       
   385 /**
       
   386 	Returns the depth of the RPN stack.  This is
       
   387 	defined for debug builds only to ensure the
       
   388 	stack depth is within an acceptable range.
       
   389  */
       
   390 	{
       
   391 	return iRpnStack->Count();
       
   392 	}
       
   393 
       
   394 
       
   395 void CEvaluator::Panic(CEvaluator::TPanic aPanic)
       
   396 /**
       
   397 	Halt the current thread with the category "AUTHEVAL"
       
   398 	and the supplied reason.
       
   399 	
       
   400 	@param	aPanic			Panic reason.
       
   401  */
       
   402 	{
       
   403 	_LIT(KPanicCat, "AUTHEVAL");
       
   404 	User::Panic(KPanicCat, aPanic);
       
   405 	}
       
   406 
       
   407 
       
   408 #endif	// #ifdef _DEBUG
       
   409 
       
   410