commsfwsupport/commselements/meshmachine/src/mm_node.cpp
changeset 0 dfb7c4ff071f
child 1 21d2ab05f085
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commsfwsupport/commselements/meshmachine/src/mm_node.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,772 @@
+// Copyright (c) 2006-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:
+//
+
+/**
+ @file
+*/
+
+#include "mm_node.h"
+#include "mm_nodepeer.h"
+#include "mm_activities.h"
+#include <elements/mm_context_internal.h>
+#include <elements/mm_log.h>
+
+#include <elements/nm_messages_base.h>
+#include <elements/nm_messages_child.h>
+
+
+#ifdef _DEBUG
+// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
+// (if it could happen through user error then you should give it an explicit, documented, category + code)
+_LIT(KSpecAssert_ElemMeshMachNodC, "ElemMeshMachNodC");
+#endif
+
+using namespace Messages;
+using namespace MeshMachine;
+using namespace NetStateMachine;
+
+//By default we reserve the space generously, to fit even a synchronised activity preallocating space for up to 4 originators.
+//Any node, hosting specific activities that may need the preallocation mechanism can choose a more optimal amounts.
+//For efficiency reasons it is strongly recommended that any node (or family of nodes) is revisited and an optimal
+//amount of space is specified (could be specified in the base class for those nodes or in every type of node separatelly).
+static const TUint KDefaultMaxPreallocatedActivityCount = 1;
+static const TUint KMaxPreallocatedActivitySize = sizeof(CNodeRetryParallelActivity) + sizeof(APreallocatedOriginators<4>);
+static const TUint KDefaultPreallocatedActivityBufferSize = KDefaultMaxPreallocatedActivityCount * KMaxPreallocatedActivitySize;
+
+//-=========================================================
+//
+//Panics
+//
+//-=========================================================
+_LIT (KMMNodePanic,"MMNodePanic");
+enum
+	{
+	EPanicPreallocatedSpaceAlreadyTaken = 1,
+	EPanicPreallocatedSpaceReturnedOther = 2,
+	EPanicInvalidClientId = 3,
+	EPanicOriginatorIsNotAPeer = 4,
+	EPanicNotSynchronisedActivity = 5,
+	};
+
+//-=========================================================
+//
+//AMMNodeBase
+//
+//-=========================================================
+EXPORT_C AMMNodeBase::AMMNodeBase(const TNodeActivityMap& aActivityMap, const TNodeId& aNodeId)
+:	ANodeBase(aNodeId),
+	TIfStaticFetcherNearestInHierarchy(this),
+	iActivityMap(aActivityMap),
+	iPreallocatedSpace(NULL)
+	{
+	};
+
+EXPORT_C void AMMNodeBase::ReturnInterfacePtrL(AMMNodeBase*& aInterface)
+    {
+    aInterface = this;
+    }
+
+EXPORT_C TUint AMMNodeBase::CountActivities(TUint8 aActivitySigId) const
+    {
+	TInt i = iActivities.Count();
+	TUint count = 0;
+	while (i>0)
+		{
+		CNodeActivityBase* a = iActivities[--i];
+		if (aActivitySigId == a->ActivitySigId() && !a->IsIdle())
+			{
+			count++;
+			}
+		}
+	return count;
+    }
+
+EXPORT_C TUint AMMNodeBase::CountAllActivities(TUint8 aActivitySigId) const
+    {
+	TInt i = iActivities.Count();
+	TUint count = 0;
+	while (i>0)
+		{
+		CNodeActivityBase* a = iActivities[--i];
+		if (aActivitySigId == a->ActivitySigId())
+			{
+			count++;
+			}
+		}
+	return count;
+    }
+
+EXPORT_C TUint AMMNodeBase::CountAllActivities() const
+	{
+	return iActivities.Count();
+	}
+
+EXPORT_C const RPointerArray<CNodeActivityBase>& AMMNodeBase::Activities() const
+	{
+	return iActivities;
+	}
+
+EXPORT_C void AMMNodeBase::ConstructL(TInt aSize)
+    {
+    //Preallocate space for preallocated activities
+    if (aSize==KUseDefaultPreallocatedSize)
+    	{
+    	//Nodes will usually use the default parameter (-1) and rely on KDefaultPreallocatedActivityBufferSize.
+    	//We do not use KDefaultPreallocatedActivityBufferSize as the default argument to avoid publishing of
+    	//this constant or KDefaultMaxPreallocatedActivityCount/KMaxPreallocatedActivitySize (either can be
+    	//freely changed at any time).
+    	aSize = KDefaultPreallocatedActivityBufferSize;
+    	}
+
+    if (aSize>0)
+    	{
+    	PreallocateSpaceL(aSize);
+    	}
+	}
+
+EXPORT_C AMMNodeBase::~AMMNodeBase()
+	{
+	//We may still have some idle activities in the iActivities array.
+	//This may be considered normal since there is no strict requirement
+	//for a node to destroy all of them before going into destruction phase.
+	//What is crutial however, is that there are no running activities left.
+
+
+	for (TInt i = iActivities.Count() - 1; i >= 0; i--)
+		{
+		CNodeActivityBase* activity = iActivities[i];
+		if (activity->IsIdle())
+			{
+			iActivities.Remove(i);
+			activity->Destroy();
+			}
+		else
+			{
+			MESH_LOG((KMeshMachineSubTag, _L8("ERROR: ~AMMNodeBase(%08x) - Running activity found! (%08x) %s (%d)"),
+			    this, activity, activity->ActivityName(), activity->ActivityId()));
+			}
+		}
+
+#ifdef _DEBUG
+	for (TInt i = iActivities.Count() -1; i >= 0; i--)
+		{
+		CNodeActivityBase* activity = iActivities[i];
+		if (!activity->IsIdle())
+			{
+			User::Invariant(); //Running activities still present! Please fix your node's cleanup!
+			}
+		}
+#endif
+
+    for (TInt i = iActivities.Count() -1; i >= 0; i--)
+		{
+		CNodeActivityBase* activity = iActivities[i];
+		iActivities.Remove(i);
+		activity->Destroy();
+		}
+    iActivities.Close();
+
+    User::Free(iPreallocatedSpace);
+    iPreallocatedSpace = NULL;
+
+	}
+
+EXPORT_C void AMMNodeBase::RemoveClient(const TRuntimeCtxId& aClientId)
+	{
+	TNodeNullContext ctx(*this);
+    RemoveClient(aClientId, ctx);
+	}
+
+EXPORT_C void AMMNodeBase::RemoveClient(const TRuntimeCtxId& aClientId, TNodeContextBase& aContext)
+	{
+	TInt foundAt = 0;
+	RNodeInterface* client = DoFindClient(aClientId, foundAt);
+	__ASSERT_DEBUG(client, User::Panic(KMMNodePanic, EPanicInvalidClientId));
+
+	//here we need to cancel all activities originating aClientId (except the current one)
+	__ASSERT_DEBUG(!client->RecipientId().IsNull(), User::Panic(KSpecAssert_ElemMeshMachNodC, 1));
+	AbortActivitiesOriginatedBy(aContext, client->RecipientId());
+
+	ANodeBase::RemoveClient(foundAt);
+   	if (aContext.iSender == aClientId)
+   	    {
+   	    aContext.iPeer = NULL;
+   	    }
+	}
+
+EXPORT_C CNodeActivityBase* AMMNodeBase::FindActivityById(TUint aActivityId) const
+	{
+	CNodeActivityBase* a = NULL;
+	for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--)
+		{
+		CNodeActivityBase* comp = iActivities[i];
+		if (!comp->IsIdle()	&& comp->ActivityId() == aActivityId)
+			{
+			a = comp;
+			}
+		}
+	return a;
+	}
+
+EXPORT_C CNodeActivityBase* AMMNodeBase::FindAddressedActivity(const TNodeContextBase& aContext) const
+	{
+	const TNodeCtxId* recipient = address_cast<const TNodeCtxId>(&aContext.iRecipient);
+	if (recipient==NULL)
+		{
+		return NULL;
+		}
+
+	CNodeActivityBase* a = NULL;
+	for (TInt i = iActivities.Count() - 1; i>=0 && a==NULL; i--)
+		{
+		CNodeActivityBase* act = iActivities[i];
+		const TNodeId& postedTo = act->iPostedToId;
+		if (!act->IsIdle()
+			&& (postedTo.IsNull() || aContext.iSender == postedTo)
+				&& (recipient->NodeCtx() == act->ActivityId()))
+			{
+			a = act;
+			}
+		}
+	return a;
+	}
+
+EXPORT_C void AMMNodeBase::Received(const TNodeSignal::TMessageId aNoPeerMsgIds[], TNodeContextBase& aContext)
+    {
+	aContext.iReturn = KErrNone; //Clear the return value.
+    CNodeActivityBase* sendersActivity = NULL;
+    if (!Accept(aContext, sendersActivity) && aContext.iReturn == KErrNone )
+        {//start new ones? but only if we know who sent a message or if it's a noPeer message
+        //or if it's us sending message to ourselves
+
+	    //is it a message that must have a peer
+	    TBool noPeer = EFalse;
+	    for (const TNodeSignal::TMessageId* p = &aNoPeerMsgIds[0] ; !p->IsNull() ; ++p)
+	    	{
+	    	noPeer = (*p == aContext.iMessage.MessageId());
+	    	if (noPeer)
+	    		{
+	    		break;
+	    		}
+	    	}
+        if (noPeer || aContext.IsPeer() || aContext.IsSelf())
+            {
+			//At this stage we are about to add the peer to the activiy originators.
+			//For all "peer requests" we must ensure the peer is in the client's list.
+			//If this assertion fires, your environment is critically corrupted.
+			//You must repair it by reconsidering your protocols.
+			__ASSERT_ALWAYS(noPeer || aContext.iPeer!=NULL, User::Panic(KMMNodePanic, EPanicOriginatorIsNotAPeer));
+           	TRAP(aContext.iReturn, StartNewActivitiesL(aContext, sendersActivity));
+            }
+        else
+            {
+            //unknown sender => ignore the message
+			NM_LOG_ADDRESS_EXT(KMeshMachineSubTag, aContext.iSender, _L8("AMMNodeBase:\tReceived() - Unknown sender. Message must have a peer => ignoring message"));
+            }
+        }
+    else
+        {
+        __ASSERT_DEBUG(aContext.iMessage.MessageId().IsNull() || aContext.iReturn != KErrNone, User::Panic(KSpecAssert_ElemMeshMachNodC, 2)); //message must be processed
+        }
+	}
+
+EXPORT_C void AMMNodeBase::HandlePassThroughMessage(TNodeContextBase& aContext)
+    {
+	if (aContext.iMessage.IsMessage<TEBase::TCancel>())
+	    {
+	    ASSERT(aContext.iNodeActivity == NULL); //by definition, since nobody accepted this;
+	    TInt originatorIndex = KErrNotFound;
+		//Please note:
+		//The same originator must not attempt to start more than one activities on the same node
+		//(so there is only ever one activity on the node with the originator == that this TCancel is addressed to)!
+		//In general one originator (identified by a unique channel id) must never originate more
+		//than one activities at all.
+	    for (TInt i = 0; i < iActivities.Count(); i++)
+	    	{
+	    	if ((originatorIndex = iActivities[i]->FindOriginator(aContext.iSender)) != KErrNotFound)
+	    		{
+	    		aContext.iNodeActivity = iActivities[i];
+	    		break;
+	    		}
+	    	}
+	    
+	    if (aContext.iNodeActivity)
+    	    {
+    	    ASSERT(originatorIndex != KErrNotFound);
+     	    if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator
+				{
+				aContext.iNodeActivity->Cancel(aContext);
+				}
+			else
+				{
+				// just tell this originator that we've stopped with respect to it.. otherwise keep running
+				TEBase::TError err(TEBase::TCancel::Id(), KErrCancel);
+				aContext.PostToSender(err);
+				aContext.iNodeActivity->RemoveOriginator(originatorIndex);
+				}
+    		}
+	    }    
+	else if (aContext.iReturn==KErrNone && !aContext.iMessage.MessageId().IsNull())
+	    { //this is the pass-through message, forward to .....
+        //Find the activity being addressed, if any
+		aContext.iNodeActivity = FindAddressedActivity(aContext);
+		if (aContext.iNodeActivity)
+			{ //Peer message, forward to originators
+			//aContext.iSender = Id();
+			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"));
+			aContext.iNodeActivity->PostToOriginators(aContext.iMessage);
+			if (aContext.iMessage.IsMessage<TEBase::TError>())
+			    {
+			    //An activity received an error=>remove it from active array
+			    //This scenario will usually happen when there is no error activity on the node,
+			    //or when the error activity decides not to handle this particular error.
+			    aContext.iNodeActivity->SetIdle();
+			    }
+			aContext.iMessage.ClearMessageId();
+			}
+		else
+			{ //A stray message
+			//Please note that we should not implement forwarding for non-response messages here.
+			//Any non-response message that needs forwarding should use TMessageDispatcher or other
+			//supported mechanisms.
+			NM_LOG_MESSAGE_EXT(KMeshMachineSubTag, aContext.iMessage, _L8("ERROR: AMMNodeBase::HandlePassThroughMessage - A stray message received!"));
+			}
+        }
+    }
+
+
+EXPORT_C void AMMNodeBase::HandleMessageReturnValue(TNodeContextBase& aContext)
+    {
+	if (aContext.iReturn != KErrNone)
+		{
+		//keep the original activity in case no aCurrentActivity
+		if(aContext.iNodeActivity && aContext.iNodeActivity->iOriginators.Count() > 0)
+			{
+			aContext.iNodeActivity->SetError(aContext.iReturn);
+			// Mark the activity for destruction
+			// When the activity is destroyed the Originators will be errored
+			aContext.iNodeActivity->SetIdle();
+			}
+
+		// Check to see if the node was unable to handle an error (e.g., an error recovery activity failed to start
+		// because there was insufficient memory).  If so, we manually error the activity and set it to idle causing
+		// its originators to be errored.  This is the most we can do if an error activity cannot be run.
+		else if(aContext.iMessage.IsMessage<TEBase::TError>())
+			{
+			CNodeActivityBase* activity = FindAddressedActivity(aContext);
+			if(activity)
+				{
+				activity->SetError(static_cast<TEBase::TError&>(aContext.iMessage).iValue);
+				// Mark the activity for destruction
+				// When the activity is destroyed the Originators will be errored
+				activity->SetIdle();
+				}
+			}
+
+		else
+			{ //No activity == single triple activity or an error from the first transition, so use the sender's message id.
+			TEBase::TError err(aContext.iMessage.MessageId(), aContext.iReturn);
+			aContext.PostToSender(err);
+			}
+		aContext.iReturn = KErrNone;
+		aContext.iMessage.ClearMessageId();
+		}
+    }
+
+
+//N.B. This function may delete the object pointed to by aCurrentActivity.
+//So don't use it after this function is called.
+//Also, it may delete the node itself, so don't use it after this function is called.
+EXPORT_C void AMMNodeBase::PostReceived(TNodeContextBase& aContext)
+	{
+    HandleMessageReturnValue(aContext);
+	HandlePassThroughMessage(aContext);
+    SignalActivities();
+    }
+
+void AMMNodeBase::SignalActivities()
+	{
+	TBool awoke = ETrue;
+	TInt c = iActivities.Count();
+	TNodeNullContext context(*this);
+	//Clean up..
+	while (awoke && c > 0)
+		{
+		awoke = EFalse;
+		for (TInt i = c - 1 ; i>=0 ; --i)
+			{
+			//Signal to waiting activities if:
+			//1) an event was received (& the state has potentialy changed as a result)
+			//- remember that an activity does not have to get idle as a result of processing an event which changes the state!!!!
+			//2) another waiting activity awoke == reacted to the signal (& the state has potentialy changed as a result)
+			//If any signalled activity reacted, the state could change and all other activities need to be signalled again.
+			context.iNodeActivity = iActivities[i];
+			awoke |= context.iNodeActivity->Signal(context);
+			if(context.iNodeActivity->IsIdle())
+				{
+				iActivities.Remove(i);
+				context.iNodeActivity->Destroy();
+				context.iNodeActivity = NULL;
+	            // NOTE: if "aContext.iNodeActivity" is the destroy activity, then deleting
+	            // it will destroy the node (i.e. "this") as well, so don't put anything after this line !
+	            if (c == 1)
+	                {
+	                // c == 1 means that we've just removed the last activity (also means i will be zero)
+	                // i == 0 means that this round of signalling parked activities has been completed
+	                // This is effectively safeguarding the access to iActivities which may or may not be
+	                // there (based on the note above). The destroy activity will always be placed at the
+	                // head of the list, and will therefore be the last to get processed.
+	                return;
+	                }
+				}
+			}
+		c = iActivities.Count();
+		}
+	}
+
+EXPORT_C void AMMNodeBase::AbortActivitiesOriginatedBy(TNodeContextBase& aContext, const TNodeId& aCommsId, TBool aIsNodeBeingDestroyed)
+    {
+    CNodeActivityBase* caller = aContext.iNodeActivity;
+    TBool abortAll = aCommsId.IsNull();
+
+    for (TInt i = iActivities.Count() - 1; i>=0; i--)
+        {
+        aContext.iNodeActivity = iActivities[i];
+        if (caller != aContext.iNodeActivity)
+            {
+        	if (abortAll)
+        	    {
+        	    //Abort the whole activity (Cancel it & error all originators)
+        	    aContext.iNodeActivity->Abort(aContext,aIsNodeBeingDestroyed);
+        	    }
+        	else
+      	        {
+      	        //Abort for one originator only (Cancel the activity if last originator & error just this one originator)
+      	        TInt idx = aContext.iNodeActivity->FindOriginator(aCommsId);
+      	        if (KErrNotFound!=idx)
+      	        	{
+					if(aContext.iNodeActivity->iOriginators.Count() == 1) // only if this is the final originator
+						{
+						aContext.iNodeActivity->SetError(KErrAbort);
+           	        	aContext.iNodeActivity->Cancel(aContext);
+						}
+					
+    					
+                    //In the "quiet mode", when the hosting node is being destroyed, we can not afford sending
+                    //an error to the node as it would hit void.
+                    TNodePeerId& originator = aContext.iNodeActivity->iOriginators[idx];
+                    TBool canSend = !((aIsNodeBeingDestroyed && originator == aContext.NodeId())
+                        || aContext.iMessage.IsMessage<TEChild::TLeft>());
+                    if (canSend)
+                        {
+                        aContext.iNodeActivity->PostToOriginator(originator, TEBase::TError(aContext.iMessage.MessageId(), KErrAbort).CRef());
+                        }
+    					
+
+	 	        	aContext.iNodeActivity->RemoveOriginator(idx);
+      	        	}
+      	        }
+            }
+        }
+    aContext.iReturn = KErrNone;
+    aContext.iNodeActivity = caller;
+    }
+
+//This fn finds the (first) activity that has an originator matching that passed in
+EXPORT_C CNodeActivityBase* AMMNodeBase::FindActivityOriginatedBy(const TRuntimeCtxId& aPeerId)
+    {
+    for (TInt i = 0; i < iActivities.Count(); i++)
+		{
+		CNodeActivityBase* a = iActivities[i];
+		if (!a->IsIdle()
+			&& a->FindOriginator(aPeerId) != KErrNotFound)
+		    {
+			return a;
+		    }
+		}
+	return NULL;
+    }
+
+TBool AMMNodeBase::Accept(TNodeContextBase& aContext, CNodeActivityBase*& aFoundActivity)
+    {
+//    NM_LOG_MESSAGE_EXT(KMeshMachineSubTag, aContext.iMessage, _L8("AMMNodeBase:\tAccept"));
+
+    //process the existing ones
+    for (TInt i = 0; i < iActivities.Count(); i++)
+		{
+		CNodeActivityBase* a = aContext.iNodeActivity = iActivities[i];
+		if(a->Next(aContext))
+		    {
+	    	if (KErrNone == aContext.iReturn)
+				{
+        		aContext.iMessage.ClearMessageId(); // message processed and value no longer needed
+	        	}
+
+			// If state went idle, aFoundActivity will be deleted later by PostReceived,
+			//  this gives us a chance to report error to originators if necessary.
+			aFoundActivity = a;
+			return ETrue;
+		    }
+
+		if (a->FindOriginator(aContext.iSender) != KErrNotFound)
+		    {
+		    aFoundActivity = a;
+		    }
+	    }
+	return EFalse;
+    }
+
+void AMMNodeBase::StartNewActivitiesL(TNodeContextBase& aContext, CNodeActivityBase* aSendersActivity)
+    {
+    //new activity can only be started if the senders channel hasn't started any yet
+    //but we need to check so that we can return an error
+    TNodeActivityIter activityIter(iActivityMap);
+
+	const TNodeActivity* activity;
+    while (NULL!=(activity = activityIter++) && aContext.iReturn == KErrNone)
+        {
+		const TStateTriple* first;
+		aContext.iNodeActivity = NULL;
+		TInt i = iActivities.Count();
+		while (i>0 && !aContext.iNodeActivity)
+			{
+			if (activity->iId == iActivities[--i]->ActivityId())
+				{
+				aContext.iNodeActivity = iActivities[i];
+				}
+			}
+
+        if ( (first = CNodeActivityBase::Accept( aContext,
+                *activity, NetStateMachine::KExecuteAlways)) != NULL )
+            { //we do need to have a state here to go to otherwise we assume it is an activity
+            //with one triple only
+            if ((first+1)->iTCtor != NULL)
+                {
+                //is it any of the existing ones?
+    	        if (aContext.iNodeActivity)
+    	            {
+                    __ASSERT_DEBUG(aSendersActivity == NULL || aSendersActivity == aContext.iNodeActivity, User::Panic(KSpecAssert_ElemMeshMachNodC, 3));
+                    if (aSendersActivity == NULL)
+                        {
+                        XNodePeerId originator(aContext.iSender, aContext.iPeer);
+        	            aContext.iNodeActivity->StartL(aContext, originator, *first);
+                        }
+    	            }
+    	        else
+    	            {
+
+#ifdef SYMBIAN_TRACE_ENABLE
+                    if (aSendersActivity)
+                        {
+						//The sender is already running an activity on this node.
+						//There is no definitive reason why to disallow starting of a next one,
+						//it is however a sign that something _may_ be going horribly wrong.
+
+						//Usually, this is the case when the same originator sends several requests without
+						//caring of the order in which they are going to be completed and the possibility of
+						//cancelling them (there exist no way of targetting TCancel to more than one activity).
+
+						//Also, an error activity may be starting and producing this warning (but please note that
+						//error activity has no originators).
+
+						//Please also see note in CNodeActivityBase::Next()!
+                        MESH_LOG_CONTEXT_EXT(KMeshMachineSubTag, aContext, _L8("WARNING: AMMNodeBase:\tStartNewActivitiesL - sender is starting an extra activity - TCancel will not work!"));
+						TInt i = iActivities.Count();
+                        MESH_LOG((KMeshMachineSubTag, _L8("\tThe sender has already started %d activities:"), i));
+						while (i>0)
+							{
+							if (iActivities[--i]->FindOriginator(aContext.iSender) >= 0)
+								{
+		                        MESH_LOG((KMeshMachineSubTag, _L8("\t(%08x) %s (%d)"), aSendersActivity, aSendersActivity->ActivityName(), aSendersActivity->ActivityId()));
+								}
+							}
+                        }
+#endif
+    	            //create a new one then
+    	            TRAPD(err, StartActivityL(aContext, *activity, *first));
+    	            if(err!=KErrNone)
+    	            	{
+	                    MESH_LOG((KMeshMachineSubTag,
+	                        _L8("ERROR: AMMNodeBase %08x:\tStartNewActivitiesL - Activity failed to start due to error %d!"),
+	                        this, err));
+
+	                    User::Leave(err);
+    	            	}
+    	            }
+                }
+        	aContext.iMessage.ClearMessageId(); //message processed
+    	    break;//only one activity can start since we have one activity per
+    	    //channelId. (ChannelId == CommsId + activityId)
+            }
+        }
+    }
+
+void AMMNodeBase::StartActivityL(TNodeContextBase& aContext, const TNodeActivity& aActivitySig, const NetStateMachine::TStateTriple& aFirst)
+    {
+    CNodeActivityBase* a = aActivitySig.iCtor(aActivitySig,*this);
+    if (iActivities.Find(a)==KErrNotFound)
+    	{
+    	//The activity did not add itself to the list in any special way, append it here
+	    CleanupStack::PushL(a);
+   		a->AppendActivityL();
+	    CleanupStack::Pop(a);
+		}
+	//assign only after the activity is successfully appended
+	aContext.iNodeActivity = a;
+
+    //if StartL leaves the "a" will be removed from the array and deleted in ::PostReceived
+    //since it will be idle
+    XNodePeerId originator(aContext.iSender, aContext.iPeer);
+    a->StartL(aContext, originator, aFirst);
+    }
+
+void AMMNodeBase::PreallocateSpaceL(TUint aSize)
+	{
+	__ASSERT_DEBUG(aSize>0, User::Panic(KSpecAssert_ElemMeshMachNodC, 4));
+	// Reserve extra space for the maximum number of preallocated activities supported by this node
+	// to ensure they can be added to the activities list while the system is out of memory.  We also
+	// add enough space for extra data strucures to store the free list - the caller cannot reserve this
+	// space without knowledge of the preallocation implementation so we do this ourselves.
+	TUint maxPreallocatedActivities = aSize / KMaxPreallocatedActivitySize;
+	iActivities.ReserveL(iActivities.Count() + maxPreallocatedActivities);
+	__ASSERT_DEBUG(iPreallocatedSpace==NULL, User::Panic(KSpecAssert_ElemMeshMachNodC, 5));
+    iPreallocatedSpace = User::AllocZL(aSize + sizeof(TUint) + maxPreallocatedActivities * sizeof(TAny*));
+    *reinterpret_cast<TUint*>(iPreallocatedSpace) = maxPreallocatedActivities;
+	}
+
+TUint AMMNodeBase::MaxPreallocatedActivityCount() const
+	{
+	// Maximum number of activities that can be preallocated is stored at the beginning of the buffer.
+	if(iPreallocatedSpace)
+		{
+		return *reinterpret_cast<TUint*>(iPreallocatedSpace);
+		}
+	return 0;
+	}
+
+TAny* AMMNodeBase::GetPreallocatedCell(TUint aIndex) const
+	{
+	// Calculate the offset of the start of the preallocated space after the free list.
+	TUint8* bufferStart = reinterpret_cast<TUint8*>(iPreallocatedSpace) + sizeof(TUint*) + MaxPreallocatedActivityCount() * sizeof(TAny*);
+
+	return bufferStart + aIndex * KMaxPreallocatedActivitySize;
+	}
+
+TAny* AMMNodeBase::BorrowPreallocatedSpace(TUint aSize)
+	{
+	MESH_LOG((KMeshMachineSubTag, _L8("AMMNodeBase %08x:\tBorrowPreallocatedSpace (%d)"),this,aSize));
+
+	__ASSERT_ALWAYS(iPreallocatedSpace, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken));
+	__ASSERT_ALWAYS(aSize <= KMaxPreallocatedActivitySize, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken));
+
+	#ifdef SYMBIAN_TRACE_ENABLE
+		if(!iPreallocatedSpace)
+			{
+			MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tBorrowPreallocatedSpace - Preallocated space has not been allocated!"), this));
+			}
+		if(aSize>KMaxPreallocatedActivitySize)
+			{
+			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));
+			}
+	#endif
+
+	TAny* ptr = NULL;
+	TUint maxPreallocatedActivities = MaxPreallocatedActivityCount();
+	TAny** freeList = reinterpret_cast<TAny**>(reinterpret_cast<TUint8*>(iPreallocatedSpace) + sizeof(TUint));
+	TUint index = 0;
+
+	// Search the free list to see if any space is available.
+	for(; index < maxPreallocatedActivities; index ++)
+		{
+		if(!freeList[index])
+			{
+			// This cell is now allocated to the calling activity.
+			ptr = freeList[index] = GetPreallocatedCell(index);
+
+			// Zero the cell so that any object allocated will have the expected initial zero fill.
+			memset(ptr, 0, KMaxPreallocatedActivitySize);
+
+			break;
+			}
+		}
+
+	// Check to make sure a free cell was found.
+	bool freeCellFound = index < maxPreallocatedActivities;
+	if(!freeCellFound)
+		{
+		MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tBorrowPreallocatedSpace - All %d preallocation cells have been allocated!"), this, maxPreallocatedActivities));
+		__ASSERT_ALWAYS(freeCellFound, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceAlreadyTaken));
+		}
+
+	return ptr;
+	}
+
+void AMMNodeBase::ReturnPreallocatedSpace(TAny* aSpace)
+	{
+	MESH_LOG((KMeshMachineSubTag, _L8("AMMNodeBase %08x:\tReturnPreallocatedSpace"), this));
+
+	TUint maxPreallocatedActivities = MaxPreallocatedActivityCount();
+	TAny** freeList = reinterpret_cast<TAny**>(reinterpret_cast<TUint8*>(iPreallocatedSpace) + sizeof(TUint));
+	TUint index = 0;
+
+	// Search the free list to return the cell.
+	for(; index < maxPreallocatedActivities; index ++)
+		{
+		if(freeList[index] == aSpace)
+			{
+			// Mark this cell as free.
+			freeList[index] = NULL;
+
+			break;
+			}
+		}
+
+	bool allocatedCellFound = index < maxPreallocatedActivities;
+	if(!allocatedCellFound)
+		{
+		MESH_LOG((KMeshMachineSubTag, _L8("ERROR AMMNodeBase %08x:\tReturnPreallocatedSpace - the returned pointer 0x%08X is invalid!"), this, aSpace));
+		__ASSERT_DEBUG(allocatedCellFound, User::Panic(KMMNodePanic, EPanicPreallocatedSpaceReturnedOther));
+		}
+	}
+
+
+//-=========================================================
+//
+//AMMNodeIdBase
+//
+//-=========================================================
+EXPORT_C const TNodeId& AMMNodeIdBase::NodeId() const
+    {
+    return Messages::ANodeId::Id();
+    }
+
+//-=========================================================
+//
+//XNodePeerId
+//
+//-=========================================================
+EXPORT_C XNodePeerId::XNodePeerId(const TRuntimeCtxId& aPeerId, RNodeInterface* aPeer, CBase* aInfo)
+:	TNodePeerId(aPeerId, aPeer),
+	iInfo(aInfo)
+	{
+	}
+
+EXPORT_C void XNodePeerId::Destroy()
+	{
+	delete iInfo;
+	iInfo = NULL;
+	}
+
+