--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/esockserver/MobilityCoreProviders/src/mobilitycpractivities.cpp Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,285 @@
+// Copyright (c) 2007-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:
+// mobilityactivities.cpp
+// Mobility Connection Provider activity definitions.
+//
+//
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <comms-infras/mobilitycpr.h>
+#include "mobilitycpractivities.h"
+#include <comms-infras/mobilitycprstates.h>
+#include <comms-infras/ss_coreprstates.h>
+
+#include <comms-infras/ss_nodemessages.h>
+#include <comms-infras/corecpractivities.h>
+#include <elements/nm_messages_errorrecovery.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_ESockMbCrCPRAct, "ESockMbCrCPRAct");
+#endif
+
+
+using namespace ESock;
+using namespace Messages;
+using namespace MeshMachine;
+using namespace NetStateMachine;
+using namespace MobilityCprActivities;
+using namespace MobilityCprStates;
+using namespace CorePanics;
+
+//
+//Panics
+#ifdef _DEBUG
+_LIT (KCoreMobileCprPanic,"CoreMobileCprPanic");
+#endif
+
+namespace CprMobilityActivity
+{
+/**
+ Activity responsible for interacting with the ESock client mobility extension
+ API and with the MCPR for the acceptance or rejection of requests to migrate
+ bearer.
+*/
+DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityCprMobility, MobilityCprMobility, TCFMobilityProvider::TStartMobility, CMobilityActivity::NewL)
+ FIRST_NODEACTIVITY_ENTRY(MobilityCprStates::TAwaitingStartMobility, MeshMachine::TNoTag)
+
+ // Attempt to start mobility activity on the meta plane
+ NODEACTIVITY_ENTRY(KNoTag, MobilityCprStates::TSendStartMobility, MobilityCprStates::TAwaitingMobilityStartedOrError, MeshMachine::TNoTagOrErrorTag)
+
+ // Success - complete the IPC client
+ THROUGH_NODEACTIVITY_ENTRY(KNoTag, CMobilityActivity::TCompleteMobilityClient, TTag<CMobilityActivity::KWaitForMobility>)
+
+ //<BEGIN> MAIN LOOP ****************
+ //Awaiting mobility triggers, which can either be:
+ //(1) TMigrationNotification (PreferredCarrierAvailable) coming from the control provider (presumably as a response to changing availability)
+ //(2) TMigrationRejected (NewCarrierRejected) coming from the control client (who's presumably not content with the currently offered carrier).
+ //(3) TError coming from the control provider in response to the previous rejection. The client rejected the current bearer, but there are no more bearers to offer.
+ NODEACTIVITY_ENTRY(CMobilityActivity::KWaitForMobility, MeshMachine::TDoNothing, MobilityCprStates::TAwaitingNewCarrierOrErrorOrRelayAndConsumeCurrentCarrierRejected, CMobilityActivity::TStartHandshakeOrErrorTagBlockedByClientNotReady)
+
+ // Notify the ESock client that a preferred carrier is available and await the client to respond
+ // The response may be:
+ // (1) TCFMobilityProvider::TMigrationRequested - proceed with the migration - the tuple will jump (with KNoTag) to await for the control provider to supply the new bearer.
+ // (2) TCFMobilityProvider::TMigrationRejected - abort the migration - the tuple will jump (with KWaitForMobility | EBackaward) back to awaiting for the preferred bearer.
+ // Note that TAwaitAndRelayMigrationRequestedOrMigrationRejected does the job of forwarding both messages to the control provider.
+ NODEACTIVITY_ENTRY(CMobilityActivity::KStartHandshake, CMobilityActivity::TNotifyClientPreferredCarrierAvailable, MobilityCprStates::TAwaitAndRelayMigrationRequestedOrMigrationRejected, CMobilityActivity::TNoTagOrWaitForMobilityBackwards)
+
+ //We've just told the control provider (see above: TAwaitAndRelayMigrationRequested...) that the offered carrier has been accepted - the client is requesting migration.
+ //The control provider may respond threefold:
+ //(1) TMigrationComplete - Proceed with the migration - the tuple will jump (with KNoTag) to starting of the bearer;
+ //(2) TMigrationNotification - offer another bearer (if the current one became out of date) - the tuple will jump back to the processing of the new bearer
+ //(3) TError - abort mobility if the current bearer is out of date and there are no more bearers to offer - the tuple will jump to the KErrorTag tuple who will decide what kind of error it is.
+ NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing, MobilityCprStates::TAwaitingMigrationCompleteOrNewCarrierOrError, MobilityCprStates::TNoTagOrStartHandshakeBackwardsOrError)
+ THROUGH_NODEACTIVITY_ENTRY(KErrorTag, CMobilityActivity::TCompleteMobilityClient, MeshMachine::TTag<CMobilityActivity::KWaitForMobility|EBackward>)
+
+ // Start the new connection
+ NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TStartServiceProvider, MobilityCprStates::TAwaitingStartedOrError, CMobilityActivity::TNoTagOrErrorTagBlockedByClientNotReady)
+ NODEACTIVITY_ENTRY(KErrorTag, TSendErrorRecoveryReq, MeshMachine::TAwaitingErrorRecoveryResponseOrError, CMobilityActivity::TNoTagBackwardsOrRecoverableErrorOrErrorBlockedByClientNotReady)
+
+ //If the bearer fails to start, the can be another bearer available, so we need to notify the control provider in case it can offer one.
+ //This node does that by rejecting the current bearer.
+ THROUGH_NODEACTIVITY_ENTRY(CoreStates::KRecoverableErrorTag, MobilityCprStates::TSendMigrationRejected, TTag<CMobilityActivity::KWaitForMobility|EBackward>)
+ THROUGH_NODEACTIVITY_ENTRY(KErrorTag, CMobilityActivity::TCompleteMobilityClient, MeshMachine::TTag<CMobilityActivity::KWaitForMobility|EBackward>)
+
+ NODEACTIVITY_ENTRY(KNoTag, CMobilityActivity::TNotifyClientNewCarrierActive, MobilityCprStates::TAwaitAndRelayMigrationAcceptedOrMigrationRejected, MeshMachine::TTag<CMobilityActivity::KWaitForMobility|EBackward>)
+ //<END> MAIN LOOP **************
+
+NODEACTIVITY_END()
+} // namespace CprMobilityActivity
+
+namespace MobilityCprActivities
+{
+DEFINE_EXPORT_ACTIVITY_MAP(mobilityCprActivities)
+ ACTIVITY_MAP_ENTRY(CprMobilityActivity, MobilityCprMobility)
+ACTIVITY_MAP_END_BASE(CprActivities, coreCprActivities)
+}
+
+//
+// CMobilityActivity
+CMobilityActivity::CMobilityActivity(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
+: MeshMachine::CNodeRetryActivity(aActivitySig, aNode)
+ {
+ __ASSERT_DEBUG(static_cast<CMobilityConnectionProvider&>(iNode).iMobilityActivity == NULL, User::Panic(KCoreMobileCprPanic, KPanicActivity));
+ }
+
+CMobilityActivity::~CMobilityActivity()
+ {
+ //This pointer becomes invalid now, clear if still set.
+ static_cast<CMobilityConnectionProvider&>(iNode).iMobilityActivity = NULL;
+ CCommsApiExtResponder::Complete(iResponder, Error() ? Error() : KErrAbort); //Safe if NULL
+ SetError(KErrNone);
+ }
+
+MeshMachine::CNodeActivityBase* CMobilityActivity::NewL(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode)
+ {
+ CMobilityActivity* self = new(ELeave) CMobilityActivity(aActivitySig, aNode);
+ return self;
+ }
+
+void CMobilityActivity::SetResponder(ESock::CCommsApiExtResponder& aResponder)
+ {
+ __ASSERT_DEBUG(iResponder==NULL, User::Panic(KSpecAssert_ESockMbCrCPRAct, 7));
+ __ASSERT_DEBUG(&aResponder, User::Panic(KSpecAssert_ESockMbCrCPRAct, 8));
+ iResponder = &aResponder;
+
+ //CMobilityActivity::TMobilityClientNotReadyMutex may have CMobilityActivity await for
+ //iResponder to pop up and if it is waiting, we need to signal it.
+ TNodeNullContext context(iNode, this);
+ Signal(context);
+ }
+
+TBool CMobilityActivity::TMobilityClientNotReadyMutex::IsBlocked(MeshMachine::TNodeContextBase& aContext)
+ {
+ __ASSERT_DEBUG(aContext.iNodeActivity, User::Panic(KCoreMobileCprPanic, KPanicNoActivity));
+ CMobilityActivity& activity = static_cast<CMobilityActivity&>(*aContext.iNodeActivity);
+ return activity.iResponder? EFalse : ETrue;
+ }
+
+//Cpr::CMobilityActivity has no originators
+void CMobilityActivity::StartL(TNodeContextBase& aContext, const Messages::XNodePeerId& aOriginator, const TStateTriple& aFirst)
+ {
+ //This activity does not support multiple clients. Any subsequent client should be completed with KErrNotSupported
+ //from CMobilityConnectionProvider::OpenExtensionInterface().
+ __ASSERT_DEBUG(iOriginators.Count()==0, User::Panic(KSpecAssert_ESockMbCrCPRAct, 1));
+
+ MeshMachine::CNodeRetryActivity::StartL(aContext, aOriginator, aFirst);
+
+ TCFMobilityProvider::TStartMobility& msg = message_cast<TCFMobilityProvider::TStartMobility>(aContext.iMessage);
+ iResponder = static_cast<CCommsApiExtResponder*>(msg.iPtr);
+ iClientId = msg.iValue;
+ __ASSERT_DEBUG(msg.iValue != 0, User::Panic(KSpecAssert_ESockMbCrCPRAct, 2)); //Client id must be valid here.
+
+ //Set a pointer to the mobility activity in the node on which it's running
+ __ASSERT_DEBUG(static_cast<CMobilityConnectionProvider&>(iNode).iMobilityActivity == NULL, User::Panic(KSpecAssert_ESockMbCrCPRAct, 3));
+ static_cast<CMobilityConnectionProvider&>(iNode).iMobilityActivity = this;
+ }
+
+void CMobilityActivity::Cancel(TNodeContextBase& aContext)
+ {
+ RNodeInterface* cp = iNode.GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::ECtrlProvider));
+ __ASSERT_DEBUG(cp, User::Panic(KSpecAssert_ESockMbCrCPRAct, 4)); //We are a Cpr, must exist.
+
+ //PostedTo() could be our service provider or possibly other peer
+ if (PostedToId() != cp->RecipientId())
+ {
+ cp->PostMessage(TNodeCtxId(ActivityId(), iNode.Id()),
+ TEBase::TCancel().CRef());
+ }
+
+ MeshMachine::CNodeRetryActivity::Cancel(aContext); //Send TCancel to iPostedTo
+ }
+
+
+DEFINE_SMELEMENT(CMobilityActivity::TNoTagBackwardsOrRecoverableErrorOrError, NetStateMachine::MStateFork, CMobilityActivity::TContext)
+TInt CMobilityActivity::TNoTagBackwardsOrRecoverableErrorOrError::TransitionTag()
+ {
+ if (iContext.iMessage.IsMessage<TEErrorRecovery::TErrorRecoveryResponse>())
+ {
+ TErrResponse& resp = message_cast<TEErrorRecovery::TErrorRecoveryResponse>(iContext.iMessage).iErrResponse;
+ if (resp.iAction == TErrResponse::ERetry)
+ {
+ return KNoTag | NetStateMachine::EBackward;
+ }
+ else if (resp.iAction == TErrResponse::EPropagate || resp.iError == KErrCancel)
+ {
+ return KErrorTag;
+ }
+ else if (resp.iAction == TErrResponse::EIgnore) // and or iError is KErrCancel
+ {
+ //TODO RZ: This looks inappropriate. EIgnore and EPropagate flags are not
+ //really complimentary. They're simply invalid in soem scenarios.
+ //Here we use ignore to an activity that attempted error recovery,
+ //it technically cannot ignore the error. It will propagate it back
+ //to the MCPR (and not to the client) by rejecting the current bearer.
+ //It feels thought clearing the error doesn't belong here. It probably
+ //belongs to the error activity.
+ iContext.Activity()->SetError(KErrNone);
+ return CoreStates::KRecoverableErrorTag;
+ }
+ }
+ return KNoTag;
+ }
+
+
+DEFINE_SMELEMENT(CMobilityActivity::TNoTagOrWaitForMobilityBackwards, NetStateMachine::MStateFork, CMobilityActivity::TContext)
+TInt CMobilityActivity::TNoTagOrWaitForMobilityBackwards::TransitionTag()
+ {
+ if(iContext.iMessage.IsMessage<TCFMobilityProvider::TMigrationRequested>())
+ {
+ return KNoTag;
+ }
+ else
+ {
+ __ASSERT_DEBUG(iContext.iMessage.IsMessage<TCFMobilityProvider::TMigrationRejected>(), User::Panic(KSpecAssert_ESockMbCrCPRAct, 6));
+ return CMobilityActivity::KWaitForMobility|EBackward;
+ }
+ }
+
+
+//Transitions
+
+DEFINE_SMELEMENT(CMobilityActivity::TCompleteMobilityClient, NetStateMachine::MStateTransition, CMobilityActivity::TContext)
+void CMobilityActivity::TCompleteMobilityClient::DoL()
+ {
+ __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileCprPanic, KPanicNoActivity));
+ CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity);
+ CCommsApiExtResponder::Complete(activity.iResponder, activity.Error());
+
+ //There is only one way to kill the mobility activity and it is by the client closing the API extension.
+ //This will be manifested with KErrCancel.
+ if (activity.Error() == KErrCancel)
+ {
+ activity.SetIdle();
+ }
+ activity.SetError(KErrNone); //The error has been handled
+ activity.ClearPostedTo();
+ }
+
+DEFINE_SMELEMENT(CMobilityActivity::TNotifyClientPreferredCarrierAvailable, NetStateMachine::MStateTransition, CMobilityActivity::TContext)
+void CMobilityActivity::TNotifyClientPreferredCarrierAvailable::DoL()
+ {
+ __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileCprPanic, KPanicNoActivity));
+ CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity);
+ TCFMobilityControlClient::TMigrationNotification& msg = message_cast<TCFMobilityControlClient::TMigrationNotification>(iContext.iMessage);
+
+ activity.iCurrentAp = msg.iValue1;
+ activity.iPreferredAp = msg.iValue2;
+ activity.iIsUpgrade = msg.iValue3;
+
+ CCommsMobilitySrvResp* responder = static_cast<CCommsMobilitySrvResp*>(activity.iResponder);
+ activity.iResponder = NULL;
+ CCommsMobilitySrvResp::PreferredCarrierAvailable(responder, TAccessPointInfo(activity.iCurrentAp), TAccessPointInfo(activity.iPreferredAp), activity.iIsUpgrade, EFalse);
+ activity.ClearPostedTo();
+ }
+
+DEFINE_SMELEMENT(CMobilityActivity::TNotifyClientNewCarrierActive, NetStateMachine::MStateTransition, CMobilityActivity::TContext)
+void CMobilityActivity::TNotifyClientNewCarrierActive::DoL()
+ {
+ __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileCprPanic, KPanicNoActivity));
+ CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity);
+ CCommsMobilitySrvResp* responder = static_cast<CCommsMobilitySrvResp*>(activity.iResponder);
+ activity.iResponder = NULL;
+ CCommsMobilitySrvResp::NewCarrierActive(responder, TAccessPointInfo(activity.iPreferredAp), EFalse);
+ activity.ClearPostedTo();
+ }
+
+