datacommsserver/esockserver/MobilityCoreProviders/src/mobilitymcpractivities.cpp.orig
changeset 2 dee179edb159
parent 1 21d2ab05f085
child 3 b6139031a239
equal deleted inserted replaced
1:21d2ab05f085 2:dee179edb159
     1 // Copyright (c) 2007-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 #include <elements/nm_messages_errorrecovery.h>
       
    17 #include <comms-infras/ss_coreprstates.h>
       
    18 #include "mobilitymcpractivities.h"
       
    19 #include <comms-infras/mobilitymcprstates.h>
       
    20 #include <comms-infras/ss_nodemessages_selector.h>
       
    21 #include <comms-infras/ss_nodemessages_mobility.h>
       
    22 #include <comms-infras/ss_nodemessages_availability.h>
       
    23 #include <comms-infras/ss_logext.h>
       
    24 
       
    25 
       
    26 #ifdef _DEBUG
       
    27 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
       
    28 // (if it could happen through user error then you should give it an explicit, documented, category + code)
       
    29 _LIT(KSpecAssert_ESockMbCrMCPRAct, "ESockMbCrMCPRAct");
       
    30 #endif
       
    31 
       
    32 #ifdef __CFLOG_ACTIVE
       
    33 	#define KCoreMCprStatesTag KESockMetaConnectionTag
       
    34 	_LIT8(KCoreMCprStatesSubTag, "coremcprstate");
       
    35 #endif
       
    36 
       
    37 using namespace ESock;
       
    38 using namespace CorePanics;
       
    39 using namespace MCprStates;
       
    40 using namespace NetStateMachine;
       
    41 using namespace MCprActivities;
       
    42 using namespace MobilityMCprActivities;
       
    43 using namespace Messages;
       
    44 using namespace MeshMachine;
       
    45 
       
    46 //
       
    47 //Panics
       
    48 #ifdef _DEBUG
       
    49 _LIT (KCoreMobileMCprPanic,"CoreMobileMCprPanic");
       
    50 #endif
       
    51 
       
    52 namespace MobilityMCprPrioritisedSelectActivity
       
    53 {
       
    54 DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivitySelect, MCprPrioritisedSelect, TCFSelector::TSimpleSelect, CSelectNextLayerActivity::NewL)
       
    55 	//Reply from TAwaitingSelectNextLayer if no choices, otherwise accept
       
    56 	FIRST_NODEACTIVITY_ENTRY(MCprStates::TAwaitingSelectNextLayer, MeshMachine::TNoTag)
       
    57 	THROUGH_NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TProcessPrioritisedSelectionPolicy, MCprStates::TSelectedProvider)
       
    58 	//Start the selection main loop
       
    59 	NODEACTIVITY_ENTRY(MCprStates::KSelectedProvider, CSelectNextLayerActivity::TFindOrCreateTierManager, MCprStates::TAwaitingTierManagerCreated, MeshMachine::TNoTag)
       
    60 	NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TJoinTierManager, CoreStates::TAwaitingJoinComplete, MeshMachine::TNoTag)
       
    61 	//Select next provider and enter the selection internal loop if provider received. Break if SelectComplete(NULL).
       
    62 	NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TSelectNextLayer, MCprStates::TAwaitingSelectComplete, CSelectNextLayerActivity::TNoTagOrSelectedProviderIsNull)
       
    63     NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TAddProviderInfo, MCprStates::TAwaitingSelectComplete, CSelectNextLayerActivity::TNoTagBackwardsOrJoinServiceProvider)
       
    64     //Break the selection internal loop if SelectComplete(NULL), otherwise stay in this tripple
       
    65     NODEACTIVITY_ENTRY(MCprStates::KJoinServiceProvider, CSelectNextLayerActivity::TJoinServiceProvider, CoreStates::TAwaitingJoinComplete, MeshMachine::TNoTag)
       
    66     THROUGH_NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TSendSelectComplete, CSelectNextLayerActivity::TSelectedProviderIsNullOrJoinServiceProviderBackward)
       
    67 	//Break the selection main loop if no more choices, otherwise go back again
       
    68 	THROUGH_NODEACTIVITY_ENTRY(MCprStates::KSelectedProviderIsNull, CSelectNextLayerActivity::TLeaveTierManager, CSelectNextLayerActivity::TNoTagOrSelectedProviderBackward)
       
    69 	//Finish the activity
       
    70 	LAST_NODEACTIVITY_ENTRY(KNoTag, MCprStates::TSendFinalSelectComplete)
       
    71 NODEACTIVITY_END()
       
    72 }
       
    73 
       
    74 namespace MobilityMCprMobilityActivity
       
    75 {
       
    76 //This activity monitors availability status on this node
       
    77 //NOTE: This activity assumes there is only one data client (Cpr) of this MCpr!
       
    78 //NOTE: This activity can only be executed in the context of CMobilityMetaConnectionProvider (or derived)
       
    79 //NOTE: TError may come from the availability activity only. It is handled by the ECFActivityError.
       
    80 DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityMCprMobility, MCprMobility, TCFMobilityProvider::TStartMobility, MobilityMCprActivities::CMobilityActivity::NewL)
       
    81 	//The activity only makes sense after the startup sequence completed on this layer
       
    82 	FIRST_NODEACTIVITY_ENTRY(MobilityMCprStates::TAwaitingStartMobility, MeshMachine::TNoTag/*BlockedByNoServiceProviderStarted*/)
       
    83 	//Report to the client that we have successfully started
       
    84 	THROUGH_NODEACTIVITY_ENTRY(KNoTag, MobilityMCprStates::TReplyMobilityStarted, MeshMachine::TNoTag)
       
    85 	//Register with self for availability notifications. Self will report _any_ availabilty change (even available->available) back to
       
    86 	//this activity. This activity can trigger mobility (see CMobilityActivity::TNoTagOrErrorTagOrStartMobilityHandshakeBackwardsOnMobilityTriggerBlockedByErrorRecovery)
       
    87 	//if it sees that the availability notification has influcenced what the currently preffered bearer should be.
       
    88 	THROUGH_NODEACTIVITY_ENTRY(KNoTag, CMobilityActivity::TSendAvailabilityRequest, MeshMachine::TTag<MobilityMCprStates::KStartMobilityHandshake>)
       
    89 
       
    90 	//<BEGIN> MAIN LOOP ****************
       
    91 	//The main mobility handshake loop. The loop is executed when performing migration from one service provider to another.
       
    92 	//The entry condition for the loop is that:
       
    93 	//- upgrade: a better then current access point is now available (a better access point reported available)
       
    94 	//- downgrade:
       
    95 	//  (a) the current access point is being rejected by the client (e.g.: the current access point doesn't seem to route traffic where required)
       
    96 	//  (b) the current access point ceases to be available (reports availability below reasonable threshold).
       
    97 	//      NOTE: if the current bearer ceases to be available completely (goes down), then this will be assisted by an error recovery request;
       
    98 	//      NOTE: This tuple doesn't actually do (b), i.e.: assumes the threshold of '1' (in 0..100 availability score range)
       
    99 	//Before awaitng for availability change or rejection by the client (TAwaitingCurrentCarrierRejectedOrAvailabilityChange), the activity
       
   100 	//first checks (TNoTagOrAwaitMobilityBlockedByErrorRecovery) if the availability has changed since it last checked
       
   101 	//(availability could have been reported amidst the previous handshake loop)
       
   102 	THROUGH_NODEACTIVITY_ENTRY(MobilityMCprStates::KStartMobilityHandshake, CMobilityActivity::TClearHandshakingFlag, CMobilityActivity::TNoTagOrAwaitMobilityBlockedByErrorRecovery)
       
   103 	NODEACTIVITY_ENTRY(MobilityMCprStates::KAwaitMobility, MeshMachine::TDoNothing, CMobilityActivity::TAwaitingCurrentCarrierRejectedOrAvailabilityChange, CMobilityActivity::TNoTagOrAwaitMobilityBackwardsOnMobilityTriggerBlockedByErrorRecovery)
       
   104 
       
   105 		//Mobility has been triggered ((a) or (b)). Start mobility handshake (set handshaking flag and inform the client about the preferred bearer)
       
   106 		NODEACTIVITY_ENTRY(KNoTag, CMobilityActivity::TInformMigrationAvailableAndSetHandshakingFlag, MobilityMCprStates::TAwaitingMigrationRequestedOrRejected, CMobilityActivity::TNoTagOrReConnectOrStartMobilityHandshakeBackwards)
       
   107 		//The client accepts the new access point.
       
   108 		//For the moment it is sufficient to use the re-connect activity, in the future we may want to
       
   109 		//customise the behavior, for example start the new layer before rebinding it, etc.
       
   110 		//Should rebinding fail, the mobility activity will be set to an error mode. The error mode will be cleared if
       
   111 		//there are other bearers this activity can offer. If there aren't the data client will be errored.
       
   112 		NODEACTIVITY_ENTRY(MobilityMCprStates::KReConnect, CMobilityActivity::TRequestReConnect, MCprStates::TAwaitingReConnectCompleteOrError, CMobilityActivity::TNoTagOrStartMobilityHandshakeBackwards)
       
   113 		//Rebinding has been successful. As far as MCPR is concerned, the mobility is finished, but the MCPR must await
       
   114 		//for the handshake (accept|reject) before it can offer another bearer.
       
   115 		NODEACTIVITY_ENTRY(KNoTag, CMobilityActivity::TInformMigrationCompleted, MobilityMCprStates::TAwaitingMigrationAcceptedOrRejected, MeshMachine::TTag<MobilityMCprStates::KStartMobilityHandshake|EBackward>)
       
   116 NODEACTIVITY_END()
       
   117 }
       
   118 
       
   119 namespace MCprConnectionStartRecoveryActivity
       
   120 {
       
   121 //MCprConnectionStartRecovery activity belongs to a group of Error Recovery Activities.
       
   122 //Error Recovery Activities need to handle their own errors (generated as well as returned).
       
   123 
       
   124 DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityConnectionStartRecovery, MCprConnectionStartRecovery, TEErrorRecovery::TErrorRecoveryRequest, CConnectionRecoveryActivity::NewL)
       
   125 	FIRST_NODEACTIVITY_ENTRY(MCprStates::TAwaitingConnectionStartRecoveryRequest, MobilityMCprStates::TNoTagOrErrorTagIfMobilityRunning)
       
   126 	LAST_NODEACTIVITY_ENTRY(KErrorTag, CConnectionRecoveryActivity::TSendIgnoreRecoveryResponse)
       
   127 
       
   128 	THROUGH_NODEACTIVITY_ENTRY(KNoTag, CConnectionRecoveryActivity::TStoreErrorContext, MeshMachine::TNoTag)
       
   129 	//Decide if it it possible/sensible to reconnect and retry
       
   130 	//This transition will leave if not possible to recover (==TSendPropagateRecoveryResponse from Transition::Error())
       
   131 	NODEACTIVITY_ENTRY(KNoTag, CConnectionRecoveryActivity::TProcessConnectionStartRecoveryRequest, MCprStates::TAwaitingReConnectCompleteOrError, MeshMachine::TNoTagOrErrorTag) //Own error handling
       
   132 	//Respond with retry
       
   133 	LAST_NODEACTIVITY_ENTRY(KNoTag, CConnectionRecoveryActivity::TSendRetryRecoveryResponse)
       
   134 	//Respond with propagate - the reconnect failed (we could think of re-trying reconnect again though..)
       
   135 	LAST_NODEACTIVITY_ENTRY(KErrorTag, CConnectionRecoveryActivity::TSendPropagateRecoveryResponse)
       
   136 NODEACTIVITY_END()
       
   137 }
       
   138 
       
   139 namespace MCprConnectionGoneDownRecoveryActivity
       
   140 {
       
   141 //MCprConnectionGoneDownRecovery activity belongs to a group of Error Recovery Activities.
       
   142 //Error Recovery Activities need to handle their own errors (generated as well as returned).
       
   143 
       
   144 //NOTE: This activity is only a reference one. All it does it waits for the mobility handshake to finish before
       
   145 //continuing with the stack cleanup originated by TGoneDown.
       
   146 DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityConnectionGoneDownRecovery, MCprConnectionGoneDownRecovery, TEErrorRecovery::TErrorRecoveryRequest, CConnectionRecoveryActivity::NewL)
       
   147 	FIRST_NODEACTIVITY_ENTRY(MCprStates::TAwaitingConnectionGoneDownRecoveryRequest, MeshMachine::TNoTag)
       
   148 	THROUGH_NODEACTIVITY_ENTRY(KNoTag, CConnectionRecoveryActivity::TStoreErrorContext, CoreStates::TNoTagOrNoPeer)
       
   149 	LAST_NODEACTIVITY_ENTRY(CoreStates::KNoPeer, MCprStates::TSendPropagateRecoveryResponse) //Take error codes directly from the request
       
   150 	THROUGH_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing, MobilityMCprStates::TNoTagBlockedByMobilityHandshaking)
       
   151 	//Decide if it it possible/sensible to retry
       
   152 	//This transition will leave if not possible to recover (==TSendPropagateRecoveryResponse from Transition::Error())
       
   153 	LAST_NODEACTIVITY_ENTRY(KNoTag, CConnectionRecoveryActivity::TProcessConnectionGoneDownRecoveryRequest) //Take error codes from the request directly
       
   154 NODEACTIVITY_END()
       
   155 }
       
   156 
       
   157 namespace MobilityMCprActivities
       
   158 {
       
   159 DEFINE_EXPORT_ACTIVITY_MAP(mobilityMCprActivities)
       
   160 	ACTIVITY_MAP_ENTRY(MobilityMCprPrioritisedSelectActivity, MCprPrioritisedSelect)
       
   161 	ACTIVITY_MAP_ENTRY(MobilityMCprMobilityActivity, MCprMobility)
       
   162 	ACTIVITY_MAP_ENTRY(MCprConnectionStartRecoveryActivity,MCprConnectionStartRecovery)
       
   163 	ACTIVITY_MAP_ENTRY(MCprConnectionGoneDownRecoveryActivity,MCprConnectionGoneDownRecovery)
       
   164 ACTIVITY_MAP_END_BASE(MCprActivities, coreMCprActivities)
       
   165 }
       
   166 
       
   167 //
       
   168 // CMobilityActivity
       
   169 MeshMachine::CNodeActivityBase* MobilityMCprActivities::CMobilityActivity::NewL(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
       
   170 	{
       
   171 	return new (ELeave) CMobilityActivity(aActivitySig, aNode);
       
   172 	}
       
   173 
       
   174 CMobilityActivity::CMobilityActivity(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
       
   175 :	MeshMachine::CNodeRetryActivity(aActivitySig, aNode),
       
   176 	//NOTE: This reference implementation will currently only react to availability oscilating around
       
   177 	//the middle point on the availability scale
       
   178 	iAvailabilityScoreTreshold((TAvailabilityStatus::EMinAvailabilityScore + TAvailabilityStatus::EMaxAvailabilityScore) / 2)
       
   179 	{
       
   180 	}
       
   181 
       
   182 CMobilityActivity::~CMobilityActivity()
       
   183 	{
       
   184 	//cancel availablilty subscription.
       
   185     RClientInterface::OpenPostMessageClose(TNodeCtxId(ActivityId(), iNode.Id()), iNode.Id(), TEBase::TCancel().CRef());
       
   186 	ClearHandshakingFlag();
       
   187 	}
       
   188 
       
   189 TBool CMobilityActivity::EvaluatePreference(CMobilityActivity::TContext& aContext)
       
   190 	{
       
   191 	//Find the most preferred Service Provider
       
   192 	TClientIter<TDefaultClientMatchPolicy> iter = iNode.GetClientIter<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EServProvider));
       
   193 	__ASSERT_DEBUG(iter[0], User::Panic(KCoreMobileMCprPanic, KPanicNoServiceProvider)); //A Service Provider must exist!
       
   194 
       
   195 	//If we are evaluating the preferences as a result of carrier rejection, we will
       
   196 	//not propose the most recently rejected one.
       
   197 	//NOTE: This implementation does not provide a blacklisting mechanism.
       
   198 	//It does not store any blacklisting information.
       
   199 	//lastRejected is only the recently rejected carrier that may not be proposed again for the client
       
   200 	//to be able to renegotiate the old bearer and continue using the connection.
       
   201 	//NOTE: This reference implementation will work only when at least one of the two most preferred carriers
       
   202 	//can be used (accepted) by the mobility client at any given time.
       
   203 	RMetaServiceProviderInterface* candidate = NULL;
       
   204 	RMetaServiceProviderInterface* lastRejected = NULL;
       
   205 	if ( Error() != KErrNone )
       
   206 	    {
       
   207 	    //The activity is running in an error mode attempting to recover from it.
       
   208 	    //There's a couple of reasons why the activity may be in an error mode:
       
   209 	    //- rejection
       
   210 	    //  - current bearer rejected;
       
   211 	    //  - proposed bearer rejected;
       
   212 	    //  - failure to migrate to the proposed bearer;
       
   213         lastRejected = iAvailable ? iAvailable :
       
   214                                     static_cast<RMetaServiceProviderInterface*>(aContext.Node().ServiceProvider());
       
   215 	    }
       
   216 
       
   217     iCandidate = iAvailable;
       
   218 	iAvailable = NULL; //Do not remember rejected candidate any longer
       
   219 	while ((candidate = static_cast<RMetaServiceProviderInterface*>(iter++)) != NULL)
       
   220 		{
       
   221 		const TAvailabilityStatus& status = candidate->AvailabilityStatus();
       
   222 		if (!status.IsKnown())
       
   223 			{
       
   224 			//We are still waiting for the availability check results for this AP
       
   225 			//Ignore the whole evaluation now as we may soon receive a better candidate
       
   226 			//to propose to the mobility client.
       
   227 			return EFalse;
       
   228 			}
       
   229 
       
   230 		if (status.Score() > iAvailabilityScoreTreshold
       
   231 			&& candidate!=lastRejected)
       
   232 			{
       
   233 			if (candidate==aContext.Node().ServiceProvider()
       
   234 			    && Error() == KErrNone )
       
   235 				{
       
   236 				//The preferred one is the current one, is still available and was not just rejected.
       
   237 				//No need to do anything more.
       
   238 				return EFalse;
       
   239 				}
       
   240 
       
   241 			//A new match found
       
   242 			iAvailable = candidate;
       
   243 			return ETrue;
       
   244 			}
       
   245 		}
       
   246 
       
   247 	//There is no choice for migration
       
   248 	return EFalse; //No match found
       
   249 	}
       
   250 
       
   251 void CMobilityActivity::SetHandshakingFlag()
       
   252 	{
       
   253 	static_cast<CMobilityMetaConnectionProvider&>(iNode).iIsHandshakingNow = ETrue;
       
   254 	}
       
   255 
       
   256 void CMobilityActivity::ClearHandshakingFlag()
       
   257 	{
       
   258 	static_cast<CMobilityMetaConnectionProvider&>(iNode).iIsHandshakingNow = EFalse;
       
   259 	}
       
   260 
       
   261 DEFINE_SMELEMENT(CMobilityActivity::TNoTagOrReConnectOrStartMobilityHandshakeBackwards, NetStateMachine::MStateFork, CMobilityActivity::TContext)
       
   262 TInt CMobilityActivity::TNoTagOrReConnectOrStartMobilityHandshakeBackwards::TransitionTag()
       
   263 	{
       
   264 	if (iContext.Activity()->Error() == KErrNone &&
       
   265 	    (message_cast<TCFMobilityProvider::TMigrationRequested>(&iContext.iMessage) ||
       
   266 	     message_cast<TCFMcpr::TReConnectComplete>(&iContext.iMessage)))
       
   267 		{
       
   268 	        CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity);
       
   269 			if( activity.iCurrent!=activity.iAvailable )
       
   270 			    return MobilityMCprStates::KReConnect | NetStateMachine::EForward;
       
   271 			else
       
   272 		        return MeshMachine::KNoTag | NetStateMachine::EForward;
       
   273 		}
       
   274 	return MobilityMCprStates::KStartMobilityHandshake | NetStateMachine::EBackward;
       
   275 	}
       
   276 
       
   277 DEFINE_SMELEMENT(CMobilityActivity::TNoTagOrStartMobilityHandshakeBackwards, NetStateMachine::MStateFork, CMobilityActivity::TContext)
       
   278 TInt CMobilityActivity::TNoTagOrStartMobilityHandshakeBackwards::TransitionTag()
       
   279 	{
       
   280 	if (iContext.Activity()->Error() == KErrNone &&
       
   281 	    (message_cast<TCFMobilityProvider::TMigrationRequested>(&iContext.iMessage) ||
       
   282 	     message_cast<TCFMcpr::TReConnectComplete>(&iContext.iMessage)))
       
   283 		{
       
   284 			return MeshMachine::KNoTag | NetStateMachine::EForward;
       
   285 		}
       
   286 	return MobilityMCprStates::KStartMobilityHandshake | NetStateMachine::EBackward;
       
   287 	}
       
   288 
       
   289 DEFINE_SMELEMENT(CMobilityActivity::TNoTagOrAwaitMobilityBackwardsOnMobilityTrigger, NetStateMachine::MStateFork, CMobilityActivity::TContext)
       
   290 TInt CMobilityActivity::TNoTagOrAwaitMobilityBackwardsOnMobilityTrigger::TransitionTag()
       
   291 	{
       
   292 	//This is where the judgement is made on whether to trigger mobility (offer the client another bearer)
       
   293 	//or ignore and come back waiting.
       
   294 	__ASSERT_DEBUG(iContext.iMessage.IsMessage<TCFMobilityProvider::TMigrationRejected>() ||
       
   295 			iContext.iMessage.IsMessage<TCFAvailabilityControlClient::TAvailabilityNotification>(),
       
   296 			User::Panic(KCoreMobileMCprPanic, KPanicIncorrectMessage));
       
   297 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   298 	CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity);
       
   299 
       
   300 	if (activity.EvaluatePreference(iContext))
       
   301 		{
       
   302         activity.SetError(KErrNone);
       
   303 		return KNoTag;
       
   304 		}
       
   305     else if (activity.Error() != KErrNone )
       
   306         {
       
   307         activity.PostToOriginators(TEBase::TError(activity.Error()).CRef());
       
   308         activity.SetError(KErrNone);
       
   309         }
       
   310 	return MobilityMCprStates::KAwaitMobility | NetStateMachine::EBackward;
       
   311 	}
       
   312 
       
   313 DEFINE_SMELEMENT(CMobilityActivity::TNoTagOrAwaitMobility, NetStateMachine::MStateFork, CMobilityActivity::TContext)
       
   314 TInt CMobilityActivity::TNoTagOrAwaitMobility::TransitionTag()
       
   315 	{
       
   316 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   317 	CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity);
       
   318 
       
   319 	if (activity.EvaluatePreference(iContext))
       
   320 		{
       
   321 		activity.SetError(KErrNone);
       
   322 		return KNoTag;
       
   323 		}
       
   324 	else if (activity.Error() != KErrNone )
       
   325 	    {
       
   326 	    activity.PostToOriginators(TEBase::TError(activity.Error()).CRef());
       
   327 	    activity.SetError(KErrNone);
       
   328 	    }
       
   329 	return MobilityMCprStates::KAwaitMobility;
       
   330 	}
       
   331 
       
   332 DEFINE_SMELEMENT(CMobilityActivity::TSendAvailabilityRequest, NetStateMachine::MStateTransition, CMobilityActivity::TContext)
       
   333 void CMobilityActivity::TSendAvailabilityRequest::DoL()
       
   334 	{
       
   335 	//Issue availability notification registration to start the availability activity on this node.
       
   336 	//NOTE: since we've requested availability from self, we are interested in any change (even available->available)
       
   337 	//since we could be switching from AP1 available to AP2 available. Either way we must recalculate.
       
   338 	//We're hence interested in TAvailabilitySubscriptionOptions::EAnyNestedChange.
       
   339 	TAvailabilitySubscriptionOptions availabilityOptions(TAvailabilitySubscriptionOptions::EAnyNestedChange);
       
   340 	TCFAvailabilityProvider::TAvailabilityNotificationRegistration msg(availabilityOptions);
       
   341 	RClientInterface::OpenPostMessageClose(TNodeCtxId(iContext.ActivityId(), iContext.NodeId()), iContext.NodeId(), msg);
       
   342 	//Do not set iPostedTo. We are not waiting for the responses.
       
   343 	}
       
   344 
       
   345 DEFINE_SMELEMENT(CMobilityActivity::TInformMigrationAvailableAndSetHandshakingFlag, NetStateMachine::MStateTransition, CMobilityActivity::TContext)
       
   346 void CMobilityActivity::TInformMigrationAvailableAndSetHandshakingFlag::DoL()
       
   347 	{
       
   348 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   349 	CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity);
       
   350 
       
   351 	//Inform the CPR that a potential migration is available. We only support a single data client
       
   352 	//in this implementation.
       
   353 	__ASSERT_DEBUG(activity.iAvailable, User::Panic(KCoreMobileMCprPanic, KPanicNoServiceProvider));
       
   354 
       
   355 	//Compute all this here to keep EvaluatePreference() as fast as possible
       
   356 	activity.iCurrent = static_cast<RMetaServiceProviderInterface*>(iContext.Node().ServiceProvider());
       
   357 	__ASSERT_DEBUG(activity.iCurrent, User::Panic(KCoreMobileMCprPanic, KPanicNoServiceProvider));
       
   358 
       
   359 	//Perform a simple check if this is an upgrade or not
       
   360 	TClientIter<TDefaultClientMatchPolicy> iter = iContext.Node().GetClientIter<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EServProvider));
       
   361 	RNodeInterface* sp = iter++;
       
   362 	while (sp && sp!=activity.iCurrent && sp!=activity.iAvailable)
       
   363 		{
       
   364 		sp = iter++;
       
   365 		}
       
   366 
       
   367 	TBool isUpgrade = (sp != activity.iCurrent); //If current was found first -> this is not an upgrade
       
   368 	if( activity.iCurrent == activity.iAvailable && activity.iCandidate )
       
   369 	    {
       
   370 		// The available client is the same as the current and a candidate exists, this indicates that
       
   371 		// an error has occured when trying to start the candidate bearer and the control as reverted to
       
   372 		// the current bearer. In this situation the notification needs to look as if the bearer has
       
   373 		// migrated from the failed candidate to the current bearer.
       
   374 		TCFMobilityControlClient::TMigrationNotification msg(activity.iCandidate->ProviderInfo().APId(),
       
   375 											   activity.iAvailable->ProviderInfo().APId(),
       
   376 											   isUpgrade, EFalse);
       
   377 		activity.PostToOriginators(msg);
       
   378 	    }
       
   379 	else
       
   380 	    {
       
   381 		// Standard case where migration is going from current to available.
       
   382 		TCFMobilityControlClient::TMigrationNotification msg(activity.iCurrent->ProviderInfo().APId(),
       
   383 											   activity.iAvailable->ProviderInfo().APId(),
       
   384 											   isUpgrade, EFalse);
       
   385 		activity.PostToOriginators(msg);
       
   386 	    }
       
   387 
       
   388 	activity.ClearPostedTo();
       
   389 	activity.SetHandshakingFlag();
       
   390 	}
       
   391 
       
   392 
       
   393 DEFINE_SMELEMENT(CMobilityActivity::TAwaitingCurrentCarrierRejectedOrAvailabilityChange, NetStateMachine::MState, CMobilityActivity::TContext)
       
   394 TBool CMobilityActivity::TAwaitingCurrentCarrierRejectedOrAvailabilityChange::Accept()
       
   395 	{
       
   396 	if (iContext.iMessage.IsMessage<TCFMobilityProvider::TMigrationRejected>())
       
   397 	    {
       
   398 	    iContext.Activity()->SetError(KErrNotFound);
       
   399 	    return ETrue;
       
   400 	    }
       
   401 	return  iContext.iMessage.IsMessage<TCFAvailabilityControlClient::TAvailabilityNotification>();
       
   402 	}
       
   403 
       
   404 
       
   405 DEFINE_SMELEMENT(CMobilityActivity::TRequestReConnect, NetStateMachine::MStateTransition, CMobilityActivity::TContext)
       
   406 void CMobilityActivity::TRequestReConnect::DoL()
       
   407 	{
       
   408 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   409 	CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity);
       
   410 
       
   411 	__ASSERT_DEBUG(activity.iAvailable, User::Panic(KCoreMobileMCprPanic, KPanicNoServiceProvider));
       
   412 	__ASSERT_DEBUG(activity.iCurrent, User::Panic(KCoreMobileMCprPanic, KPanicNoServiceProvider));
       
   413 	__ASSERT_DEBUG(activity.iCurrent!=activity.iAvailable, User::Panic(KSpecAssert_ESockMbCrMCPRAct, 1));
       
   414 
       
   415 	// For the moment it is sufficient to use the re-connect activity, in the future we may want to
       
   416 	// customise the behavior, for example start the new layer before rebinding it, etc.
       
   417 	TCFMcpr::TReConnect msg(activity.iCurrent->RecipientId(), activity.iAvailable->RecipientId());
       
   418 	activity.PostRequestTo(iContext.NodeId(), msg);
       
   419 	}
       
   420 
       
   421 DEFINE_SMELEMENT(CMobilityActivity::TInformMigrationCompleted, NetStateMachine::MStateTransition, CMobilityActivity::TContext)
       
   422 void CMobilityActivity::TInformMigrationCompleted::DoL()
       
   423 	{
       
   424 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   425 	iContext.iNodeActivity->PostToOriginators(TCFMobilityProvider::TMigrationComplete().CRef());
       
   426 	iContext.iNodeActivity->ClearPostedTo();
       
   427 	}
       
   428 
       
   429 DEFINE_SMELEMENT(CMobilityActivity::TClearHandshakingFlag, NetStateMachine::MStateTransition, CMobilityActivity::TContext)
       
   430 void CMobilityActivity::TClearHandshakingFlag::DoL()
       
   431 	{
       
   432 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   433 	CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity);
       
   434 	activity.ClearHandshakingFlag();
       
   435 	}
       
   436 
       
   437 
       
   438 //
       
   439 //CConnectionRecoveryActivity
       
   440 MeshMachine::CNodeActivityBase* CConnectionRecoveryActivity::NewL(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
       
   441 	{
       
   442 	return new (ELeave) CConnectionRecoveryActivity(aActivitySig, aNode);
       
   443 	}
       
   444 
       
   445 CConnectionRecoveryActivity::CConnectionRecoveryActivity(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
       
   446 :	MeshMachine::CNodeRetryActivity(aActivitySig, aNode)
       
   447 	{
       
   448 	}
       
   449 
       
   450 void CConnectionRecoveryActivity::ReplyToOriginators(TEErrorRecovery::TErrorRecoveryResponse& aCFMessageSig)
       
   451 	{
       
   452 	NM_LOG_START_BLOCK(KESockMeshMachine, _L8("CConnectionRecoveryActivity::ReplyToOriginators"));
       
   453 	NM_LOG((KESockMeshMachine, _L8("[this=0x%08x] "), this));
       
   454 	NM_LOG_MESSAGE(KESockMeshMachine, aCFMessageSig);
       
   455 	NM_LOG_END_BLOCK(KESockMeshMachine, _L8("CConnectionRecoveryActivity::ReplyToOriginators"));
       
   456 	for (TInt n = iOriginators.Count() - 1;n>=0; n--)
       
   457 		{
       
   458 		Messages::TNodePeerId& peerId = iOriginators[n];
       
   459 		TCFSafeMessage::TResponseCarrierWest<TEErrorRecovery::TErrorRecoveryResponse> resp(aCFMessageSig, peerId.RecipientId());
       
   460 		peerId.PostMessage(iNode.Id(), resp);
       
   461 		}
       
   462 	}
       
   463 
       
   464 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TAwaitingReConnectComplete, NetStateMachine::MState, CConnectionRecoveryActivity::TContext)
       
   465 TBool CConnectionRecoveryActivity::TAwaitingReConnectComplete::Accept()
       
   466 	{
       
   467    	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   468    	TEBase::TError* msg = message_cast<TEBase::TError>(&iContext.iMessage);
       
   469    	if(msg)
       
   470     	{
       
   471 		CConnectionRecoveryActivity& ac = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity);
       
   472 		TErrResponse propagateResp(TErrResponse::EPropagate,ac.iOriginalErrContext.iStateChange.iError,ac.iOriginalErrContext.iMessageId);
       
   473 		TEErrorRecovery::TErrorRecoveryResponse errResp(propagateResp);
       
   474 		ac.ReplyToOriginators(errResp);
       
   475     	ac.SetIdle();
       
   476    		iContext.iMessage.ClearMessageId();
       
   477    		return EFalse;
       
   478    		}
       
   479 	return (iContext.iMessage.IsMessage<TCFMcpr::TReConnectComplete>())? ETrue : EFalse;
       
   480 	}
       
   481 
       
   482 void CConnectionRecoveryActivity::TTransitionBase::Error(TInt /*aError*/)
       
   483 	{
       
   484 	//Reply to the Error Activity and terminate
       
   485 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   486 	CConnectionRecoveryActivity& ac = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity);
       
   487 	TEErrorRecovery::TErrorRecoveryResponse errResp(TErrResponse(TErrResponse::EPropagate,ac.iOriginalErrContext.iStateChange.iError,ac.iOriginalErrContext.iMessageId));
       
   488 	ac.ReplyToOriginators(errResp);
       
   489 	iContext.iNodeActivity->SetIdle();
       
   490 	}
       
   491 
       
   492 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TStoreErrorContext, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext)
       
   493 void CConnectionRecoveryActivity::TStoreErrorContext::DoL()
       
   494 	{
       
   495 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   496 	CConnectionRecoveryActivity& activity = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity);
       
   497 	activity.iOriginalErrContext = message_cast<TEErrorRecovery::TErrorRecoveryRequest>(iContext.iMessage).iErrContext;
       
   498 	}
       
   499 
       
   500 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TProcessConnectionStartRecoveryRequest, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext)
       
   501 void CConnectionRecoveryActivity::TProcessConnectionStartRecoveryRequest::DoL()
       
   502 	{
       
   503 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   504 	RNodeInterface* newSP = NULL;
       
   505 	RNodeInterface* curSP = iContext.Node().ServiceProvider(); //Our current started Service Provider.
       
   506 
       
   507 	//Choose Service Providers to work on
       
   508 	TClientIter<TDefaultClientMatchPolicy> iter = iContext.Node().GetClientIter<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EServProvider));
       
   509 	RNodeInterface* itf = NULL;
       
   510 	for (itf = iter++; itf!=NULL && newSP==NULL; itf = iter++)
       
   511 		{
       
   512 		if (itf==curSP)
       
   513 			{
       
   514 			newSP = iter++; //And the new one to try next
       
   515 			}
       
   516 		}
       
   517 
       
   518 	//Sanity check.
       
   519 	//The new provider must not be started, there can be only one started at a time.
       
   520 	__ASSERT_DEBUG(newSP==NULL || (newSP->Flags() & TCFClientType::EStarted)==0, User::Panic(KSpecAssert_ESockMbCrMCPRAct, 3));
       
   521 
       
   522 	//If there is no other Service Provider to try, return KErrNotFound
       
   523 	if (newSP==NULL || curSP == NULL)
       
   524 		{
       
   525 #ifdef __CFLOG_ACTIVE
       
   526 		__CFLOG_VAR((KCoreMCprStatesTag, KCoreMCprStatesSubTag, _L8("WARNING: CConnectionRecoveryActivity::TProcessConnectionStartRecoveryRequest::DoL() - no more choices, abandoning recovery.")));
       
   527 #endif
       
   528 		User::Leave(KErrNotFound);
       
   529 		}
       
   530 
       
   531 	//Diagnostinc - there must be a data client or we cannot be here
       
   532 	__ASSERT_DEBUG(iContext.Node().GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EData)), User::Panic(KCoreMobileMCprPanic, KPanicNoDataClient));
       
   533 	iContext.iNodeActivity->PostRequestTo(iContext.NodeId(),
       
   534 			TCFMcpr::TReConnect(curSP->RecipientId(), newSP->RecipientId()).CRef());
       
   535 	}
       
   536 
       
   537 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TProcessConnectionGoneDownRecoveryRequest, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext)
       
   538 void CConnectionRecoveryActivity::TProcessConnectionGoneDownRecoveryRequest::DoL()
       
   539 	{
       
   540 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   541 	CConnectionRecoveryActivity& activity = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity);
       
   542 
       
   543 	RNodeInterface* started = iContext.Node().ServiceProvider();
       
   544 	TUint apId = (TUint)activity.iOriginalErrContext.iInfo;
       
   545 	RNodeInterface* gonedownsp = iContext.Node().FindServiceProvider(apId);
       
   546 	if (started && started != gonedownsp)
       
   547 		{
       
   548 		CConnectionRecoveryActivity::TSendRetryRecoveryResponse tr(iContext);
       
   549 		tr.DoL();
       
   550 		}
       
   551 	else
       
   552 		{
       
   553 		CConnectionRecoveryActivity::TSendPropagateRecoveryResponse tr(iContext);
       
   554 		tr.DoL();
       
   555 		}
       
   556 	}
       
   557 
       
   558 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TSendRetryRecoveryResponse, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext)
       
   559 void CConnectionRecoveryActivity::TSendRetryRecoveryResponse::DoL()
       
   560 	{
       
   561 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   562 	CConnectionRecoveryActivity& activity = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity);
       
   563 	TEErrorRecovery::TErrorRecoveryResponse err(TErrResponse(TErrResponse::ERetry,KErrNone,activity.iOriginalErrContext.iMessageId));
       
   564 	activity.ReplyToOriginators(err);
       
   565 	}
       
   566 
       
   567 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TSendPropagateRecoveryResponse, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext)
       
   568 void CConnectionRecoveryActivity::TSendPropagateRecoveryResponse::DoL()
       
   569 	{
       
   570 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   571 	CConnectionRecoveryActivity& activity = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity);
       
   572 	TEErrorRecovery::TErrorRecoveryResponse err(TErrResponse(TErrResponse::EPropagate,
       
   573 		activity.iOriginalErrContext.iStateChange.iError,activity.iOriginalErrContext.iMessageId));
       
   574 	activity.ReplyToOriginators(err);
       
   575 	}
       
   576 
       
   577 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TSendIgnoreRecoveryResponse, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext)
       
   578 void CConnectionRecoveryActivity::TSendIgnoreRecoveryResponse::DoL()
       
   579 	{
       
   580 	__ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity));
       
   581 	CConnectionRecoveryActivity& activity = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity);
       
   582 	TEErrorRecovery::TErrorRecoveryResponse err(TErrResponse(TErrResponse::EIgnore,KErrNone,activity.iOriginalErrContext.iMessageId));
       
   583 	activity.ReplyToOriginators(err);
       
   584 	}
       
   585 
       
   586