commsfwsupport/commselements/meshmachine/src/mm_node.cpp
changeset 0 dfb7c4ff071f
child 1 21d2ab05f085
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     1 // Copyright (c) 2006-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 //
       
    15 
       
    16 /**
       
    17  @file
       
    18 */
       
    19 
       
    20 #include "mm_node.h"
       
    21 #include "mm_nodepeer.h"
       
    22 #include "mm_activities.h"
       
    23 #include <elements/mm_context_internal.h>
       
    24 #include <elements/mm_log.h>
       
    25 
       
    26 #include <elements/nm_messages_base.h>
       
    27 #include <elements/nm_messages_child.h>
       
    28 
       
    29 
       
    30 #ifdef _DEBUG
       
    31 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
       
    32 // (if it could happen through user error then you should give it an explicit, documented, category + code)
       
    33 _LIT(KSpecAssert_ElemMeshMachNodC, "ElemMeshMachNodC");
       
    34 #endif
       
    35 
       
    36 using namespace Messages;
       
    37 using namespace MeshMachine;
       
    38 using namespace NetStateMachine;
       
    39 
       
    40 //By default we reserve the space generously, to fit even a synchronised activity preallocating space for up to 4 originators.
       
    41 //Any node, hosting specific activities that may need the preallocation mechanism can choose a more optimal amounts.
       
    42 //For efficiency reasons it is strongly recommended that any node (or family of nodes) is revisited and an optimal
       
    43 //amount of space is specified (could be specified in the base class for those nodes or in every type of node separatelly).
       
    44 static const TUint KDefaultMaxPreallocatedActivityCount = 1;
       
    45 static const TUint KMaxPreallocatedActivitySize = sizeof(CNodeRetryParallelActivity) + sizeof(APreallocatedOriginators<4>);
       
    46 static const TUint KDefaultPreallocatedActivityBufferSize = KDefaultMaxPreallocatedActivityCount * KMaxPreallocatedActivitySize;
       
    47 
       
    48 //-=========================================================
       
    49 //
       
    50 //Panics
       
    51 //
       
    52 //-=========================================================
       
    53 _LIT (KMMNodePanic,"MMNodePanic");
       
    54 enum
       
    55 	{
       
    56 	EPanicPreallocatedSpaceAlreadyTaken = 1,
       
    57 	EPanicPreallocatedSpaceReturnedOther = 2,
       
    58 	EPanicInvalidClientId = 3,
       
    59 	EPanicOriginatorIsNotAPeer = 4,
       
    60 	EPanicNotSynchronisedActivity = 5,
       
    61 	};
       
    62 
       
    63 //-=========================================================
       
    64 //
       
    65 //AMMNodeBase
       
    66 //
       
    67 //-=========================================================
       
    68 EXPORT_C AMMNodeBase::AMMNodeBase(const TNodeActivityMap& aActivityMap, const TNodeId& aNodeId)
       
    69 :	ANodeBase(aNodeId),
       
    70 	TIfStaticFetcherNearestInHierarchy(this),
       
    71 	iActivityMap(aActivityMap),
       
    72 	iPreallocatedSpace(NULL)
       
    73 	{
       
    74 	};
       
    75 
       
    76 EXPORT_C void AMMNodeBase::ReturnInterfacePtrL(AMMNodeBase*& aInterface)
       
    77     {
       
    78     aInterface = this;
       
    79     }
       
    80 
       
    81 EXPORT_C TUint AMMNodeBase::CountActivities(TUint8 aActivitySigId) const
       
    82     {
       
    83 	TInt i = iActivities.Count();
       
    84 	TUint count = 0;
       
    85 	while (i>0)
       
    86 		{
       
    87 		CNodeActivityBase* a = iActivities[--i];
       
    88 		if (aActivitySigId == a->ActivitySigId() && !a->IsIdle())
       
    89 			{
       
    90 			count++;
       
    91 			}
       
    92 		}
       
    93 	return count;
       
    94     }
       
    95 
       
    96 EXPORT_C TUint AMMNodeBase::CountAllActivities(TUint8 aActivitySigId) const
       
    97     {
       
    98 	TInt i = iActivities.Count();
       
    99 	TUint count = 0;
       
   100 	while (i>0)
       
   101 		{
       
   102 		CNodeActivityBase* a = iActivities[--i];
       
   103 		if (aActivitySigId == a->ActivitySigId())
       
   104 			{
       
   105 			count++;
       
   106 			}
       
   107 		}
       
   108 	return count;
       
   109     }
       
   110 
       
   111 EXPORT_C TUint AMMNodeBase::CountAllActivities() const
       
   112 	{
       
   113 	return iActivities.Count();
       
   114 	}
       
   115 
       
   116 EXPORT_C const RPointerArray<CNodeActivityBase>& AMMNodeBase::Activities() const
       
   117 	{
       
   118 	return iActivities;
       
   119 	}
       
   120 
       
   121 EXPORT_C void AMMNodeBase::ConstructL(TInt aSize)
       
   122     {
       
   123     //Preallocate space for preallocated activities
       
   124     if (aSize==KUseDefaultPreallocatedSize)
       
   125     	{
       
   126     	//Nodes will usually use the default parameter (-1) and rely on KDefaultPreallocatedActivityBufferSize.
       
   127     	//We do not use KDefaultPreallocatedActivityBufferSize as the default argument to avoid publishing of
       
   128     	//this constant or KDefaultMaxPreallocatedActivityCount/KMaxPreallocatedActivitySize (either can be
       
   129     	//freely changed at any time).
       
   130     	aSize = KDefaultPreallocatedActivityBufferSize;
       
   131     	}
       
   132 
       
   133     if (aSize>0)
       
   134     	{
       
   135     	PreallocateSpaceL(aSize);
       
   136     	}
       
   137 	}
       
   138 
       
   139 EXPORT_C AMMNodeBase::~AMMNodeBase()
       
   140 	{
       
   141 	//We may still have some idle activities in the iActivities array.
       
   142 	//This may be considered normal since there is no strict requirement
       
   143 	//for a node to destroy all of them before going into destruction phase.
       
   144 	//What is crutial however, is that there are no running activities left.
       
   145 
       
   146 
       
   147 	for (TInt i = iActivities.Count() - 1; i >= 0; i--)
       
   148 		{
       
   149 		CNodeActivityBase* activity = iActivities[i];
       
   150 		if (activity->IsIdle())
       
   151 			{
       
   152 			iActivities.Remove(i);
       
   153 			activity->Destroy();
       
   154 			}
       
   155 		else
       
   156 			{
       
   157 			MESH_LOG((KMeshMachineSubTag, _L8("ERROR: ~AMMNodeBase(%08x) - Running activity found! (%08x) %s (%d)"),
       
   158 			    this, activity, activity->ActivityName(), activity->ActivityId()));
       
   159 			}
       
   160 		}
       
   161 
       
   162 #ifdef _DEBUG
       
   163 	for (TInt i = iActivities.Count() -1; i >= 0; i--)
       
   164 		{
       
   165 		CNodeActivityBase* activity = iActivities[i];
       
   166 		if (!activity->IsIdle())
       
   167 			{
       
   168 			User::Invariant(); //Running activities still present! Please fix your node's cleanup!
       
   169 			}
       
   170 		}
       
   171 #endif
       
   172 
       
   173     for (TInt i = iActivities.Count() -1; i >= 0; i--)
       
   174 		{
       
   175 		CNodeActivityBase* activity = iActivities[i];
       
   176 		iActivities.Remove(i);
       
   177 		activity->Destroy();
       
   178 		}
       
   179     iActivities.Close();
       
   180 
       
   181     User::Free(iPreallocatedSpace);
       
   182     iPreallocatedSpace = NULL;
       
   183 
       
   184 	}
       
   185 
       
   186 EXPORT_C void AMMNodeBase::RemoveClient(const TRuntimeCtxId& aClientId)
       
   187 	{
       
   188 	TNodeNullContext ctx(*this);
       
   189     RemoveClient(aClientId, ctx);
       
   190 	}
       
   191 
       
   192 EXPORT_C void AMMNodeBase::RemoveClient(const TRuntimeCtxId& aClientId, TNodeContextBase& aContext)
       
   193 	{
       
   194 	TInt foundAt = 0;
       
   195 	RNodeInterface* client = DoFindClient(aClientId, foundAt);
       
   196 	__ASSERT_DEBUG(client, User::Panic(KMMNodePanic, EPanicInvalidClientId));
       
   197 
       
   198 	//here we need to cancel all activities originating aClientId (except the current one)
       
   199 	__ASSERT_DEBUG(!client->RecipientId().IsNull(), User::Panic(KSpecAssert_ElemMeshMachNodC, 1));
       
   200 	AbortActivitiesOriginatedBy(aContext, client->RecipientId());
       
   201 
       
   202 	ANodeBase::RemoveClient(foundAt);
       
   203    	if (aContext.iSender == aClientId)
       
   204    	    {
       
   205    	    aContext.iPeer = NULL;
       
   206    	    }
       
   207 	}
       
   208 
       
   209 EXPORT_C CNodeActivityBase* AMMNodeBase::FindActivityById(TUint aActivityId) const
       
   210 	{
       
   211 	CNodeActivityBase* a = NULL;
       
   212 	for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--)
       
   213 		{
       
   214 		CNodeActivityBase* comp = iActivities[i];
       
   215 		if (!comp->IsIdle()	&& comp->ActivityId() == aActivityId)
       
   216 			{
       
   217 			a = comp;
       
   218 			}
       
   219 		}
       
   220 	return a;
       
   221 	}
       
   222 
       
   223 EXPORT_C CNodeActivityBase* AMMNodeBase::FindAddressedActivity(const TNodeContextBase& aContext) const
       
   224 	{
       
   225 	const TNodeCtxId* recipient = address_cast<const TNodeCtxId>(&aContext.iRecipient);
       
   226 	if (recipient==NULL)
       
   227 		{
       
   228 		return NULL;
       
   229 		}
       
   230 
       
   231 	CNodeActivityBase* a = NULL;
       
   232 	for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--)
       
   233 		{
       
   234 		CNodeActivityBase* act = iActivities[i];
       
   235 		const TNodeId& postedTo = act->iPostedToId;
       
   236 		if (!act->IsIdle()
       
   237 			&& (postedTo.IsNull() || aContext.iSender == postedTo)
       
   238 				&& (recipient->NodeCtx() == act->ActivityId()))
       
   239 			{
       
   240 			a = act;
       
   241 			}
       
   242 		}
       
   243 	return a;
       
   244 	}
       
   245 
       
   246 EXPORT_C void AMMNodeBase::Received(const TNodeSignal::TMessageId aNoPeerMsgIds[], TNodeContextBase& aContext)
       
   247     {
       
   248 	aContext.iReturn = KErrNone; //Clear the return value.
       
   249     CNodeActivityBase* sendersActivity = NULL;
       
   250     if (!Accept(aContext, sendersActivity) && aContext.iReturn == KErrNone )
       
   251         {//start new ones? but only if we know who sent a message or if it's a noPeer message
       
   252         //or if it's us sending message to ourselves
       
   253 
       
   254 	    //is it a message that must have a peer
       
   255 	    TBool noPeer = EFalse;
       
   256 	    for (const TNodeSignal::TMessageId* p = &aNoPeerMsgIds[0] ; !p->IsNull() ; ++p)
       
   257 	    	{
       
   258 	    	noPeer = (*p == aContext.iMessage.MessageId());
       
   259 	    	if (noPeer)
       
   260 	    		{
       
   261 	    		break;
       
   262 	    		}
       
   263 	    	}
       
   264         if (noPeer || aContext.IsPeer() || aContext.IsSelf())
       
   265             {
       
   266 			//At this stage we are about to add the peer to the activiy originators.
       
   267 			//For all "peer requests" we must ensure the peer is in the client's list.
       
   268 			//If this assertion fires, your environment is critically corrupted.
       
   269 			//You must repair it by reconsidering your protocols.
       
   270 			__ASSERT_ALWAYS(noPeer || aContext.iPeer!=NULL, User::Panic(KMMNodePanic, EPanicOriginatorIsNotAPeer));
       
   271            	TRAP(aContext.iReturn, StartNewActivitiesL(aContext, sendersActivity));
       
   272             }
       
   273         else
       
   274             {
       
   275             //unknown sender => ignore the message
       
   276 			NM_LOG_ADDRESS_EXT(KMeshMachineSubTag, aContext.iSender, _L8("AMMNodeBase:\tReceived() - Unknown sender. Message must have a peer => ignoring message"));
       
   277             }
       
   278         }
       
   279     else
       
   280         {
       
   281         __ASSERT_DEBUG(aContext.iMessage.MessageId().IsNull() || aContext.iReturn != KErrNone, User::Panic(KSpecAssert_ElemMeshMachNodC, 2)); //message must be processed
       
   282         }
       
   283 	}
       
   284 
       
   285 EXPORT_C void AMMNodeBase::HandlePassThroughMessage(TNodeContextBase& aContext)
       
   286     {
       
   287 	if (aContext.iMessage.IsMessage<TEBase::TCancel>())
       
   288 	    {
       
   289 	    ASSERT(aContext.iNodeActivity == NULL); //by definition, since nobody accepted this;
       
   290 	    TInt originatorIndex = KErrNotFound;
       
   291 		//Please note:
       
   292 		//The same originator must not attempt to start more than one activities on the same node
       
   293 		//(so there is only ever one activity on the node with the originator == that this TCancel is addressed to)!
       
   294 		//In general one originator (identified by a unique channel id) must never originate more
       
   295 		//than one activities at all.
       
   296 	    for (TInt i = 0; i < iActivities.Count(); i++)
       
   297 	    	{
       
   298 	    	if ((originatorIndex = iActivities[i]->FindOriginator(aContext.iSender)) != KErrNotFound)
       
   299 	    		{
       
   300 	    		aContext.iNodeActivity = iActivities[i];
       
   301 	    		break;
       
   302 	    		}
       
   303 	    	}
       
   304 	    
       
   305 	    if (aContext.iNodeActivity)
       
   306     	    {
       
   307     	    ASSERT(originatorIndex != KErrNotFound);
       
   308      	    if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator
       
   309 				{
       
   310 				aContext.iNodeActivity->Cancel(aContext);
       
   311 				}
       
   312 			else
       
   313 				{
       
   314 				// just tell this originator that we've stopped with respect to it.. otherwise keep running
       
   315 				TEBase::TError err(TEBase::TCancel::Id(), KErrCancel);
       
   316 				aContext.PostToSender(err);
       
   317 				aContext.iNodeActivity->RemoveOriginator(originatorIndex);
       
   318 				}
       
   319     		}
       
   320 	    }    
       
   321 	else if (aContext.iReturn==KErrNone && !aContext.iMessage.MessageId().IsNull())
       
   322 	    { //this is the pass-through message, forward to .....
       
   323         //Find the activity being addressed, if any
       
   324 		aContext.iNodeActivity = FindAddressedActivity(aContext);
       
   325 		if (aContext.iNodeActivity)
       
   326 			{ //Peer message, forward to originators
       
   327 			//aContext.iSender = Id();
       
   328 			NM_LOG_MESSAGE_EXT(KMeshMachineSubTag, aContext.iMessage, _L8("AMMNodeBase::HandlePassThroughMessage - message not served by the node but matching activity found=>SEND TO ACTIVITY'S ORIGINATORS"));
       
   329 			aContext.iNodeActivity->PostToOriginators(aContext.iMessage);
       
   330 			if (aContext.iMessage.IsMessage<TEBase::TError>())
       
   331 			    {
       
   332 			    //An activity received an error=>remove it from active array
       
   333 			    //This scenario will usually happen when there is no error activity on the node,
       
   334 			    //or when the error activity decides not to handle this particular error.
       
   335 			    aContext.iNodeActivity->SetIdle();
       
   336 			    }
       
   337 			aContext.iMessage.ClearMessageId();
       
   338 			}
       
   339 		else
       
   340 			{ //A stray message
       
   341 			//Please note that we should not implement forwarding for non-response messages here.
       
   342 			//Any non-response message that needs forwarding should use TMessageDispatcher or other
       
   343 			//supported mechanisms.
       
   344 			NM_LOG_MESSAGE_EXT(KMeshMachineSubTag, aContext.iMessage, _L8("ERROR: AMMNodeBase::HandlePassThroughMessage - A stray message received!"));
       
   345 			}
       
   346         }
       
   347     }
       
   348 
       
   349 
       
   350 EXPORT_C void AMMNodeBase::HandleMessageReturnValue(TNodeContextBase& aContext)
       
   351     {
       
   352 	if (aContext.iReturn != KErrNone)
       
   353 		{
       
   354 		//keep the original activity in case no aCurrentActivity
       
   355 		if(aContext.iNodeActivity && aContext.iNodeActivity->iOriginators.Count() > 0)
       
   356 			{
       
   357 			aContext.iNodeActivity->SetError(aContext.iReturn);
       
   358 			// Mark the activity for destruction
       
   359 			// When the activity is destroyed the Originators will be errored
       
   360 			aContext.iNodeActivity->SetIdle();
       
   361 			}
       
   362 
       
   363 		// Check to see if the node was unable to handle an error (e.g., an error recovery activity failed to start
       
   364 		// because there was insufficient memory).  If so, we manually error the activity and set it to idle causing
       
   365 		// its originators to be errored.  This is the most we can do if an error activity cannot be run.
       
   366 		else if(aContext.iMessage.IsMessage<TEBase::TError>())
       
   367 			{
       
   368 			CNodeActivityBase* activity = FindAddressedActivity(aContext);
       
   369 			if(activity)
       
   370 				{
       
   371 				activity->SetError(static_cast<TEBase::TError&>(aContext.iMessage).iValue);
       
   372 				// Mark the activity for destruction
       
   373 				// When the activity is destroyed the Originators will be errored
       
   374 				activity->SetIdle();
       
   375 				}
       
   376 			}
       
   377 
       
   378 		else
       
   379 			{ //No activity == single triple activity or an error from the first transition, so use the sender's message id.
       
   380 			TEBase::TError err(aContext.iMessage.MessageId(), aContext.iReturn);
       
   381 			aContext.PostToSender(err);
       
   382 			}
       
   383 		aContext.iReturn = KErrNone;
       
   384 		aContext.iMessage.ClearMessageId();
       
   385 		}
       
   386     }
       
   387 
       
   388 
       
   389 //N.B. This function may delete the object pointed to by aCurrentActivity.
       
   390 //So don't use it after this function is called.
       
   391 //Also, it may delete the node itself, so don't use it after this function is called.
       
   392 EXPORT_C void AMMNodeBase::PostReceived(TNodeContextBase& aContext)
       
   393 	{
       
   394     HandleMessageReturnValue(aContext);
       
   395 	HandlePassThroughMessage(aContext);
       
   396     SignalActivities();
       
   397     }
       
   398 
       
   399 void AMMNodeBase::SignalActivities()
       
   400 	{
       
   401 	TBool awoke = ETrue;
       
   402 	TInt c = iActivities.Count();
       
   403 	TNodeNullContext context(*this);
       
   404 	//Clean up..
       
   405 	while (awoke && c > 0)
       
   406 		{
       
   407 		awoke = EFalse;
       
   408 		for (TInt i = c - 1 ; i>=0 ; --i)
       
   409 			{
       
   410 			//Signal to waiting activities if:
       
   411 			//1) an event was received (& the state has potentialy changed as a result)
       
   412 			//- remember that an activity does not have to get idle as a result of processing an event which changes the state!!!!
       
   413 			//2) another waiting activity awoke == reacted to the signal (& the state has potentialy changed as a result)
       
   414 			//If any signalled activity reacted, the state could change and all other activities need to be signalled again.
       
   415 			context.iNodeActivity = iActivities[i];
       
   416 			awoke |= context.iNodeActivity->Signal(context);
       
   417 			if(context.iNodeActivity->IsIdle())
       
   418 				{
       
   419 				iActivities.Remove(i);
       
   420 				context.iNodeActivity->Destroy();
       
   421 				context.iNodeActivity = NULL;
       
   422 	            // NOTE: if "aContext.iNodeActivity" is the destroy activity, then deleting
       
   423 	            // it will destroy the node (i.e. "this") as well, so don't put anything after this line !
       
   424 	            if (c == 1)
       
   425 	                {
       
   426 	                // c == 1 means that we've just removed the last activity (also means i will be zero)
       
   427 	                // i == 0 means that this round of signalling parked activities has been completed
       
   428 	                // This is effectively safeguarding the access to iActivities which may or may not be
       
   429 	                // there (based on the note above). The destroy activity will always be placed at the
       
   430 	                // head of the list, and will therefore be the last to get processed.
       
   431 	                return;
       
   432 	                }
       
   433 				}
       
   434 			}
       
   435 		c = iActivities.Count();
       
   436 		}
       
   437 	}
       
   438 
       
   439 EXPORT_C void AMMNodeBase::AbortActivitiesOriginatedBy(TNodeContextBase& aContext, const TNodeId& aCommsId, TBool aIsNodeBeingDestroyed)
       
   440     {
       
   441     CNodeActivityBase* caller = aContext.iNodeActivity;
       
   442     TBool abortAll = aCommsId.IsNull();
       
   443 
       
   444     for (TInt i = iActivities.Count() - 1; i>=0; i--)
       
   445         {
       
   446         aContext.iNodeActivity = iActivities[i];
       
   447         if (caller != aContext.iNodeActivity)
       
   448             {
       
   449         	if (abortAll)
       
   450         	    {
       
   451         	    //Abort the whole activity (Cancel it & error all originators)
       
   452         	    aContext.iNodeActivity->Abort(aContext,aIsNodeBeingDestroyed);
       
   453         	    }
       
   454         	else
       
   455       	        {
       
   456       	        //Abort for one originator only (Cancel the activity if last originator & error just this one originator)
       
   457       	        TInt idx = aContext.iNodeActivity->FindOriginator(aCommsId);
       
   458       	        if (KErrNotFound!=idx)
       
   459       	        	{
       
   460 					if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator
       
   461 						{
       
   462 						aContext.iNodeActivity->SetError(KErrAbort);
       
   463            	        	aContext.iNodeActivity->Cancel(aContext);
       
   464 						}
       
   465 					
       
   466     					
       
   467                     //In the "quiet mode", when the hosting node is being destroyed, we can not afford sending
       
   468                     //an error to the node as it would hit void.
       
   469                     TNodePeerId& originator = aContext.iNodeActivity->iOriginators[idx];
       
   470                     TBool canSend = !((aIsNodeBeingDestroyed && originator == aContext.NodeId())
       
   471                         || aContext.iMessage.IsMessage<TEChild::TLeft>());
       
   472                     if (canSend)
       
   473                         {
       
   474                         aContext.iNodeActivity->PostToOriginator(originator, TEBase::TError(aContext.iMessage.MessageId(), KErrAbort).CRef());
       
   475                         }
       
   476     					
       
   477 
       
   478 	 	        	aContext.iNodeActivity->RemoveOriginator(idx);
       
   479       	        	}
       
   480       	        }
       
   481             }
       
   482         }
       
   483     aContext.iReturn = KErrNone;
       
   484     aContext.iNodeActivity = caller;
       
   485     }
       
   486 
       
   487 //This fn finds the (first) activity that has an originator matching that passed in
       
   488 EXPORT_C CNodeActivityBase* AMMNodeBase::FindActivityOriginatedBy(const TRuntimeCtxId& aPeerId)
       
   489     {
       
   490     for (TInt i = 0; i < iActivities.Count(); i++)
       
   491 		{
       
   492 		CNodeActivityBase* a = iActivities[i];
       
   493 		if (!a->IsIdle()
       
   494 			&& a->FindOriginator(aPeerId) != KErrNotFound)
       
   495 		    {
       
   496 			return a;
       
   497 		    }
       
   498 		}
       
   499 	return NULL;
       
   500     }
       
   501 
       
   502 TBool AMMNodeBase::Accept(TNodeContextBase& aContext, CNodeActivityBase*& aFoundActivity)
       
   503     {
       
   504 //    NM_LOG_MESSAGE_EXT(KMeshMachineSubTag, aContext.iMessage, _L8("AMMNodeBase:\tAccept"));
       
   505 
       
   506     //process the existing ones
       
   507     for (TInt i = 0; i < iActivities.Count(); i++)
       
   508 		{
       
   509 		CNodeActivityBase* a = aContext.iNodeActivity = iActivities[i];
       
   510 		if(a->Next(aContext))
       
   511 		    {
       
   512 	    	if (KErrNone == aContext.iReturn)
       
   513 				{
       
   514         		aContext.iMessage.ClearMessageId(); // message processed and value no longer needed
       
   515 	        	}
       
   516 
       
   517 			// If state went idle, aFoundActivity will be deleted later by PostReceived,
       
   518 			//  this gives us a chance to report error to originators if necessary.
       
   519 			aFoundActivity = a;
       
   520 			return ETrue;
       
   521 		    }
       
   522 
       
   523 		if (a->FindOriginator(aContext.iSender) != KErrNotFound)
       
   524 		    {
       
   525 		    aFoundActivity = a;
       
   526 		    }
       
   527 	    }
       
   528 	return EFalse;
       
   529     }
       
   530 
       
   531 void AMMNodeBase::StartNewActivitiesL(TNodeContextBase& aContext, CNodeActivityBase* aSendersActivity)
       
   532     {
       
   533     //new activity can only be started if the senders channel hasn't started any yet
       
   534     //but we need to check so that we can return an error
       
   535     TNodeActivityIter activityIter(iActivityMap);
       
   536 
       
   537 	const TNodeActivity* activity;
       
   538     while (NULL!=(activity = activityIter++) && aContext.iReturn == KErrNone)
       
   539         {
       
   540 		const TStateTriple* first;
       
   541 		aContext.iNodeActivity = NULL;
       
   542 		TInt i = iActivities.Count();
       
   543 		while (i>0 && !aContext.iNodeActivity)
       
   544 			{
       
   545 			if (activity->iId == iActivities[--i]->ActivityId())
       
   546 				{
       
   547 				aContext.iNodeActivity = iActivities[i];
       
   548 				}
       
   549 			}
       
   550 
       
   551         if ( (first = CNodeActivityBase::Accept( aContext,
       
   552                 *activity, NetStateMachine::KExecuteAlways)) != NULL )
       
   553             { //we do need to have a state here to go to otherwise we assume it is an activity
       
   554             //with one triple only
       
   555             if ((first+1)->iTCtor != NULL)
       
   556                 {
       
   557                 //is it any of the existing ones?
       
   558     	        if (aContext.iNodeActivity)
       
   559     	            {
       
   560                     __ASSERT_DEBUG(aSendersActivity == NULL || aSendersActivity == aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachNodC, 3));
       
   561                     if (aSendersActivity == NULL)
       
   562                         {
       
   563                         XNodePeerId originator(aContext.iSender, aContext.iPeer);
       
   564         	            aContext.iNodeActivity->StartL(aContext, originator, *first);
       
   565                         }
       
   566     	            }
       
   567     	        else
       
   568     	            {
       
   569 
       
   570 #ifdef SYMBIAN_TRACE_ENABLE
       
   571                     if (aSendersActivity)
       
   572                         {
       
   573 						//The sender is already running an activity on this node.
       
   574 						//There is no definitive reason why to disallow starting of a next one,
       
   575 						//it is however a sign that something _may_ be going horribly wrong.
       
   576 
       
   577 						//Usually, this is the case when the same originator sends several requests without
       
   578 						//caring of the order in which they are going to be completed and the possibility of
       
   579 						//cancelling them (there exist no way of targetting TCancel to more than one activity).
       
   580 
       
   581 						//Also, an error activity may be starting and producing this warning (but please note that
       
   582 						//error activity has no originators).
       
   583 
       
   584 						//Please also see note in CNodeActivityBase::Next()!
       
   585                         MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("WARNING: AMMNodeBase:\tStartNewActivitiesL - sender is starting an extra activity - TCancel will not work!"));
       
   586 						TInt i = iActivities.Count();
       
   587                         MESH_LOG((KMeshMachineSubTag, _L8("\tThe sender has already started %d activities:"), i));
       
   588 						while (i>0)
       
   589 							{
       
   590 							if (iActivities[--i]->FindOriginator(aContext.iSender) >= 0)
       
   591 								{
       
   592 		                        MESH_LOG((KMeshMachineSubTag, _L8("\t(%08x) %s (%d)"), aSendersActivity, aSendersActivity->ActivityName(), aSendersActivity->ActivityId()));
       
   593 								}
       
   594 							}
       
   595                         }
       
   596 #endif
       
   597     	            //create a new one then
       
   598     	            TRAPD(err, StartActivityL(aContext, *activity, *first));
       
   599     	            if(err!=KErrNone)
       
   600     	            	{
       
   601 	                    MESH_LOG((KMeshMachineSubTag,
       
   602 	                        _L8("ERROR: AMMNodeBase %08x:\tStartNewActivitiesL - Activity failed to start due to error %d!"),
       
   603 	                        this, err));
       
   604 
       
   605 	                    User::Leave(err);
       
   606     	            	}
       
   607     	            }
       
   608                 }
       
   609         	aContext.iMessage.ClearMessageId(); //message processed
       
   610     	    break;//only one activity can start since we have one activity per
       
   611     	    //channelId. (ChannelId == CommsId + activityId)
       
   612             }
       
   613         }
       
   614     }
       
   615 
       
   616 void AMMNodeBase::StartActivityL(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, const NetStateMachine::TStateTriple& aFirst)
       
   617     {
       
   618     CNodeActivityBase* a = aActivitySig.iCtor(aActivitySig,*this);
       
   619     if (iActivities.Find(a)==KErrNotFound)
       
   620     	{
       
   621     	//The activity did not add itself to the list in any special way, append it here
       
   622 	    CleanupStack::PushL(a);
       
   623    		a->AppendActivityL();
       
   624 	    CleanupStack::Pop(a);
       
   625 		}
       
   626 	//assign only after the activity is successfully appended
       
   627 	aContext.iNodeActivity = a;
       
   628 
       
   629     //if StartL leaves the "a" will be removed from the array and deleted in ::PostReceived
       
   630     //since it will be idle
       
   631     XNodePeerId originator(aContext.iSender, aContext.iPeer);
       
   632     a->StartL(aContext, originator, aFirst);
       
   633     }
       
   634 
       
   635 void AMMNodeBase::PreallocateSpaceL(TUint aSize)
       
   636 	{
       
   637 	__ASSERT_DEBUG(aSize>0, User::Panic(KSpecAssert_ElemMeshMachNodC, 4));
       
   638 	// Reserve extra space for the maximum number of preallocated activities supported by this node
       
   639 	// to ensure they can be added to the activities list while the system is out of memory.  We also
       
   640 	// add enough space for extra data strucures to store the free list - the caller cannot reserve this
       
   641 	// space without knowledge of the preallocation implementation so we do this ourselves.
       
   642 	TUint maxPreallocatedActivities = aSize / KMaxPreallocatedActivitySize;
       
   643 	iActivities.ReserveL(iActivities.Count() + maxPreallocatedActivities);
       
   644 	__ASSERT_DEBUG(iPreallocatedSpace==NULL, User::Panic(KSpecAssert_ElemMeshMachNodC, 5));
       
   645     iPreallocatedSpace = User::AllocZL(aSize + sizeof(TUint) + maxPreallocatedActivities * sizeof(TAny*));
       
   646     *reinterpret_cast<TUint*>(iPreallocatedSpace) = maxPreallocatedActivities;
       
   647 	}
       
   648 
       
   649 TUint AMMNodeBase::MaxPreallocatedActivityCount() const
       
   650 	{
       
   651 	// Maximum number of activities that can be preallocated is stored at the beginning of the buffer.
       
   652 	if(iPreallocatedSpace)
       
   653 		{
       
   654 		return *reinterpret_cast<TUint*>(iPreallocatedSpace);
       
   655 		}
       
   656 	return 0;
       
   657 	}
       
   658 
       
   659 TAny* AMMNodeBase::GetPreallocatedCell(TUint aIndex) const
       
   660 	{
       
   661 	// Calculate the offset of the start of the preallocated space after the free list.
       
   662 	TUint8* bufferStart = reinterpret_cast<TUint8*>(iPreallocatedSpace) + sizeof(TUint*) + MaxPreallocatedActivityCount() * sizeof(TAny*);
       
   663 
       
   664 	return bufferStart + aIndex * KMaxPreallocatedActivitySize;
       
   665 	}
       
   666 
       
   667 TAny* AMMNodeBase::BorrowPreallocatedSpace(TUint aSize)
       
   668 	{
       
   669 	MESH_LOG((KMeshMachineSubTag, _L8("AMMNodeBase %08x:\tBorrowPreallocatedSpace (%d)"),this,aSize));
       
   670 
       
   671 	__ASSERT_ALWAYS(iPreallocatedSpace, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken));
       
   672 	__ASSERT_ALWAYS(aSize <= KMaxPreallocatedActivitySize, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken));
       
   673 
       
   674 	#ifdef SYMBIAN_TRACE_ENABLE
       
   675 		if(!iPreallocatedSpace)
       
   676 			{
       
   677 			MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tBorrowPreallocatedSpace - Preallocated space has not been allocated!"), this));
       
   678 			}
       
   679 		if(aSize>KMaxPreallocatedActivitySize)
       
   680 			{
       
   681 			MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tBorrowPreallocatedSpace - Size exceeds maximum limit for a single allocation (%d was requested but only %d is available)!"), this, aSize, KMaxPreallocatedActivitySize));
       
   682 			}
       
   683 	#endif
       
   684 
       
   685 	TAny* ptr = NULL;
       
   686 	TUint maxPreallocatedActivities = MaxPreallocatedActivityCount();
       
   687 	TAny** freeList = reinterpret_cast<TAny**>(reinterpret_cast<TUint8*>(iPreallocatedSpace) + sizeof(TUint));
       
   688 	TUint index = 0;
       
   689 
       
   690 	// Search the free list to see if any space is available.
       
   691 	for(; index < maxPreallocatedActivities; index ++)
       
   692 		{
       
   693 		if(!freeList[index])
       
   694 			{
       
   695 			// This cell is now allocated to the calling activity.
       
   696 			ptr = freeList[index] = GetPreallocatedCell(index);
       
   697 
       
   698 			// Zero the cell so that any object allocated will have the expected initial zero fill.
       
   699 			memset(ptr, 0, KMaxPreallocatedActivitySize);
       
   700 
       
   701 			break;
       
   702 			}
       
   703 		}
       
   704 
       
   705 	// Check to make sure a free cell was found.
       
   706 	bool freeCellFound = index < maxPreallocatedActivities;
       
   707 	if(!freeCellFound)
       
   708 		{
       
   709 		MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tBorrowPreallocatedSpace - All %d preallocation cells have been allocated!"), this, maxPreallocatedActivities));
       
   710 		__ASSERT_ALWAYS(freeCellFound, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken));
       
   711 		}
       
   712 
       
   713 	return ptr;
       
   714 	}
       
   715 
       
   716 void AMMNodeBase::ReturnPreallocatedSpace(TAny* aSpace)
       
   717 	{
       
   718 	MESH_LOG((KMeshMachineSubTag, _L8("AMMNodeBase %08x:\tReturnPreallocatedSpace"), this));
       
   719 
       
   720 	TUint maxPreallocatedActivities = MaxPreallocatedActivityCount();
       
   721 	TAny** freeList = reinterpret_cast<TAny**>(reinterpret_cast<TUint8*>(iPreallocatedSpace) + sizeof(TUint));
       
   722 	TUint index = 0;
       
   723 
       
   724 	// Search the free list to return the cell.
       
   725 	for(; index < maxPreallocatedActivities; index ++)
       
   726 		{
       
   727 		if(freeList[index] == aSpace)
       
   728 			{
       
   729 			// Mark this cell as free.
       
   730 			freeList[index] = NULL;
       
   731 
       
   732 			break;
       
   733 			}
       
   734 		}
       
   735 
       
   736 	bool allocatedCellFound = index < maxPreallocatedActivities;
       
   737 	if(!allocatedCellFound)
       
   738 		{
       
   739 		MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tReturnPreallocatedSpace - the returned pointer 0x%08X is invalid!"), this, aSpace));
       
   740 		__ASSERT_DEBUG(allocatedCellFound, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceReturnedOther));
       
   741 		}
       
   742 	}
       
   743 
       
   744 
       
   745 //-=========================================================
       
   746 //
       
   747 //AMMNodeIdBase
       
   748 //
       
   749 //-=========================================================
       
   750 EXPORT_C const TNodeId& AMMNodeIdBase::NodeId() const
       
   751     {
       
   752     return Messages::ANodeId::Id();
       
   753     }
       
   754 
       
   755 //-=========================================================
       
   756 //
       
   757 //XNodePeerId
       
   758 //
       
   759 //-=========================================================
       
   760 EXPORT_C XNodePeerId::XNodePeerId(const TRuntimeCtxId& aPeerId, RNodeInterface* aPeer, CBase* aInfo)
       
   761 :	TNodePeerId(aPeerId, aPeer),
       
   762 	iInfo(aInfo)
       
   763 	{
       
   764 	}
       
   765 
       
   766 EXPORT_C void XNodePeerId::Destroy()
       
   767 	{
       
   768 	delete iInfo;
       
   769 	iInfo = NULL;
       
   770 	}
       
   771 
       
   772