--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/email/pop3andsmtpmtm/servermtmutils/src/cimmobilitymanager.cpp Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,541 @@
+// 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:
+//
+
+#include "cimmobilitymanager.h"
+#include "cimmobilitypolicyprovider.h"
+#include "mobilitytestmtmapi.h"
+#include "cimmobilitylogger.h"
+#include <imutdll.h>
+
+/**
+The factory constructor. Part of two phased construction.
+@param aAccountId - the ID of the email account
+@param aMtm - Bearer Mobility API for the server MTM
+*/
+EXPORT_C CImMobilityManager* CImMobilityManager::NewL(TUid aMtmUid, TMsvId aAccountId, MImMobileServer& aMtm)
+// static method
+ {
+ CImMobilityManager* self = new(ELeave) CImMobilityManager(aMtmUid, aAccountId, aMtm);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CImMobilityManager::CImMobilityManager(TUid aMtmUid, TMsvId aAccountId, MImMobileServer& aMtm)
+ : iMtmUid(aMtmUid), iAccountId(aAccountId), iMtm(aMtm), iIsCancelled(EFalse)
+ {
+ MOBILITY_TEST_CREATE(aAccountId, *this);
+ }
+
+void CImMobilityManager::ConstructL()
+ {
+ // Ensure an instance of the mobility Policy Provider exists.
+ CImMobilityPolicyProvider::CreateL();
+ }
+
+CImMobilityManager::~CImMobilityManager()
+ {
+ iIsCancelled = ETrue;
+ delete iCommsMobilityApi;
+ iCommsMobilityApi = NULL;
+
+ if (iState == EMobilityWaitForUpgradePolicy ||
+ iState == EMobilityWaitForDowngradePolicy ||
+ iState == EMobilityWaitForUpgradePolicyAndOldSocketClose)
+ {
+ CImMobilityPolicyProvider::GetRef().Cancel(iAccountId);
+ }
+ CImMobilityPolicyProvider::Delete();
+ MOBILITY_TEST_DELETE(*this);
+ }
+
+/**
+Registers with the Bearer Mobility Framework for preferred carrier notifications
+@param aConnection - the connected session.
+*/
+EXPORT_C void CImMobilityManager::SetConnection(RCommsSubSession& aConnection)
+ {
+ if (iState == EMobilityUninitialised)
+ {
+ TRAPD(err, iCommsMobilityApi = CActiveCommsMobilityApiExt::NewL(aConnection, *this));
+
+ if (err == KErrNone)
+ {
+ iState = EMobilityIdle;
+ __LOG_FORMAT((KDefaultLog, "<%d> SetConnection() OK", iAccountId));
+ }
+ else
+ {
+ __LOG_FORMAT((KDefaultLog, "<%d> SetConnection() Error %d", iAccountId, err));
+ }
+ }
+ else
+ {
+ // unexpected in this state
+ __LOG_FORMAT((KDefaultLog, "<%d> SetConnection() unexpected state : %d", iAccountId, iState));
+ __ASSERT_DEBUG(EFalse, gPanic(EPanicInvalidMobilityState));
+ }
+ }
+
+/**
+Notification of preferred carrier availability.
+This is called as a result of a new, preferred carrier becoming available (upgrade)
+or the existing carrier being lost, with an alternative available (downgrade).
+
+The notification is handed up to the Mobility Policy Provider for decision.
+
+@param aOldAp - info about the old carrier
+@param aNewAp - info about the new carrier
+@param aIsUpgrade - indicates if this is an upgrade
+@param aIsSeamless - indicates if a migration will be seamless
+*/
+void CImMobilityManager::PreferredCarrierAvailable(TAccessPointInfo aOldAp, TAccessPointInfo aNewAp, TBool aIsUpgrade, TBool aIsSeamless)
+ {
+ __LOG_FORMAT((KDefaultLog, "<%d> PreferredCarrierAvailable(state:%d old:%d new:%d isUp:%d isSless:%d)", iAccountId, iState, aOldAp.AccessPoint(), aNewAp.AccessPoint(), aIsUpgrade, aIsSeamless));
+ // Handle the upgrade notice
+ switch (iState)
+ {
+ case EMobilityIdle:
+ case EMobilityWaitForMigrate:
+ case EMobilityConnectingToNewCarrier:
+ {
+ // no special "extra" action to do in these states - just inform the
+ // MTM (in the case of a downgrade) and notify the policy provider.
+ // This is done below.
+ break;
+ }
+ case EMobilityWaitForUpgradePolicy:
+ case EMobilityWaitForDowngradePolicy:
+ case EMobilityWaitForUpgradePolicyAndOldSocketClose:
+ {
+ // If in these states, this function call indicates that the
+ // last received carrier availability notification is no longer
+ // applicable. This could happen for a number of reasons:
+ // - the preferred carrier becomes unavailable
+ // - the notice changes from an upgrade to a downgrade
+ // - any others?
+ // Anyway, what needs to happen is for the policy provider to have
+ // its last notification cancelled, and the new one issued.
+ CImMobilityPolicyProvider::GetRef().Cancel(iAccountId);
+ break;
+ }
+ case EMobilityWaitForOldSocketClose:
+ case EMobilityWaitForOldSocketCloseCarrierRejected:
+ {
+ // If in this state, the previous notice was for an upgrade, and
+ // the old connection is still being tidied up. If the new notice
+ // is for a downgrade, then the old connection must be torn down
+ // immediately.
+ if (!aIsUpgrade)
+ {
+ iMtm.CarrierLost();
+ // If the new connection is the same as the new connection for
+ // the previous notice then the carrier change has already been
+ // accepted - otherwise fall through to re-notify the policy provider
+ if (aNewAp.AccessPoint()==iNewAp.AccessPoint())
+ {
+ iState = EMobilityWaitForMigrate;
+
+//#ifdef __MOBILITY_TEST_FRAMEWORK
+// TBool handled = CImMobilityTestFramework::Response(*this, KMobilityTestResponseMigrateToPreferredCarrier);
+// if (!handled)
+//#endif //__MOBILITY_TEST_FRAMEWORK
+ iCommsMobilityApi->MigrateToPreferredCarrier();
+ // job done, return
+ return;
+ }
+ // break;
+ }
+ else
+ {
+ // If the new notice is for an upgrade, it can only
+ // mean that an even better carrier has become available
+ // while waiting for the old old carrier to be tidied up!
+ iState = EMobilityWaitForUpgradePolicyAndOldSocketClose;
+ CImMobilityPolicyProvider::GetRef().PreferredCarrierAvailable(*this, iAccountId, iMtmUid, iMtm.MobilityProgress(), aOldAp, aNewAp, aIsUpgrade, aIsSeamless);
+ return;
+ }
+ break;
+ }
+ case EMobilityUninitialised:
+ default:
+ {
+ // unexpected in this state
+ __ASSERT_DEBUG(EFalse, gPanic(EPanicInvalidMobilityState));
+ }
+ }
+
+ // pass the notification up to the policy provider.
+ if (aIsUpgrade)
+ {
+ if (iState != EMobilityWaitForUpgradePolicyAndOldSocketClose)
+ {
+ iState = EMobilityWaitForUpgradePolicy;
+ }
+ CImMobilityPolicyProvider::GetRef().PreferredCarrierAvailable(*this, iAccountId, iMtmUid, iMtm.MobilityProgress(), aOldAp, aNewAp, aIsUpgrade, aIsSeamless);
+ }
+ else
+ {
+ iMtm.CarrierLost();
+ iState = EMobilityWaitForDowngradePolicy;
+ CImMobilityPolicyProvider::GetRef().PreferredCarrierAvailable(*this, iAccountId, iMtmUid, iMtm.MobilityProgress(), aOldAp, aNewAp, aIsUpgrade, aIsSeamless);
+ }
+ }
+
+/**
+Notification that the new carrier is active and available for connecting sockets.
+
+@param aNewAp - info about the new carrier
+@param aIsSeamless - indicates if a migration will be seamless
+*/
+void CImMobilityManager::NewCarrierActive(TAccessPointInfo aNewAp, TBool aIsSeamless)
+ {
+ __LOG_FORMAT((KDefaultLog, "<%d> NewCarrierActive(state:%d new:%d isSless:%d)", iAccountId, iState, aNewAp.AccessPoint(), aIsSeamless));
+ switch (iState)
+ {
+ case EMobilityWaitForMigrate:
+ {
+ iState = EMobilityConnectingToNewCarrier;
+ iMtm.NewCarrierActive(aNewAp, aIsSeamless);
+ break;
+ }
+ case EMobilityUninitialised:
+ case EMobilityIdle:
+ case EMobilityWaitForUpgradePolicy:
+ case EMobilityWaitForDowngradePolicy:
+ case EMobilityWaitForOldSocketClose:
+ case EMobilityConnectingToNewCarrier:
+ case EMobilityWaitForUpgradePolicyAndOldSocketClose:
+ case EMobilityWaitForOldSocketCloseCarrierRejected:
+ default:
+ {
+ // unexpected in this state
+ __ASSERT_DEBUG(EFalse, gPanic(EPanicInvalidMobilityState));
+ }
+ }
+ }
+
+/**
+Notification that an error has occured.
+This indicates that the RConnection in use is no longer valid, therefore
+the Server MTM will be immediately notified. Once this is done, this function
+MUST NOT perform any actions that use class data, as the Server MTM may delete
+its instance of CImMobilityManager.
+
+@param aError - error code
+*/
+void CImMobilityManager::Error(TInt aError)
+ {
+ // If we're closing down, we don't need to handle further notifications from Comms,
+ // and we can safely return from here.
+ if(iIsCancelled)
+ {
+ return;
+ }
+
+ __LOG_FORMAT((KDefaultLog, "<%d> Error (state:%d error:%d)", iAccountId, iState, aError));
+ switch (iState)
+ {
+ case EMobilityWaitForUpgradePolicy:
+ case EMobilityWaitForDowngradePolicy:
+ case EMobilityWaitForUpgradePolicyAndOldSocketClose:
+ {
+ // cancel the policy request.
+ CImMobilityPolicyProvider::GetRef().Cancel(iAccountId);
+ // fall through
+ }
+ case EMobilityIdle:
+ {
+ iState = EMobilityUninitialised;
+ iMtm.MobilityError(aError);
+ break;
+ }
+ case EMobilityWaitForOldSocketClose:
+ case EMobilityWaitForMigrate:
+ case EMobilityConnectingToNewCarrier:
+ case EMobilityWaitForOldSocketCloseCarrierRejected:
+ {
+ iState = EMobilityUninitialised;
+ // Tell the policy provider about it. (must happen before informing MTM)
+ CImMobilityPolicyProvider::GetRef().MigrationComplete(iAccountId, KImMigrateMobilityError, iNewAp);
+ // Inform the MTM. Do this last - this may delete the mobility manager
+ iMtm.MobilityError(aError);
+ break;
+ }
+
+ case EMobilityUninitialised:
+ default:
+ {
+ // unexpected in this state
+ __ASSERT_DEBUG(EFalse, gPanic(EPanicInvalidMobilityState));
+ }
+ }
+ }
+
+/**
+Instruction from the Messaging Plugin Provider that the new carrier is to be accepted.
+
+@param aAction - action that the server MTM should take when closing existing sockets.
+*/
+EXPORT_C void CImMobilityManager::AcceptNewCarrier(TImMobilityAction aAction)
+ {
+ __LOG_FORMAT((KDefaultLog, "<%d> Accept New Carrier (state:%d action:%d)", iAccountId, iState, aAction));
+ switch (iState)
+ {
+ case EMobilityWaitForDowngradePolicy:
+ {
+ // old connections already closed - just inform the mobility framework
+ iState = EMobilityWaitForMigrate;
+//#ifdef __MOBILITY_TEST_FRAMEWORK
+// TBool handled = CImMobilityTestFramework::Response(*this, KMobilityTestResponseMigrateToPreferredCarrier);
+// if (!handled)
+//#endif //__MOBILITY_TEST_FRAMEWORK
+ iCommsMobilityApi->MigrateToPreferredCarrier();
+ break;
+ }
+ case EMobilityWaitForUpgradePolicy:
+ {
+ if (aAction == KAcceptImmediately)
+ {
+ iMtm.CarrierLost();
+ iState = EMobilityWaitForMigrate;
+//#ifdef __MOBILITY_TEST_FRAMEWORK
+// TBool handled = CImMobilityTestFramework::Response(*this, KMobilityTestResponseMigrateToPreferredCarrier);
+// if (!handled)
+//#endif //__MOBILITY_TEST_FRAMEWORK
+ iCommsMobilityApi->MigrateToPreferredCarrier();
+ }
+ else
+ {
+ iState = EMobilityWaitForOldSocketClose;
+ iMtm.PrepareForNewCarrier(aAction, iIsSeamless);
+ }
+ break;
+ }
+ case EMobilityWaitForUpgradePolicyAndOldSocketClose:
+ {
+
+ if (aAction == KAcceptImmediately)
+ {
+ iMtm.CarrierLost();
+ iState = EMobilityWaitForMigrate;
+//#ifdef __MOBILITY_TEST_FRAMEWORK
+// TBool handled = CImMobilityTestFramework::Response(*this, KMobilityTestResponseMigrateToPreferredCarrier);
+// if (!handled)
+//#endif //__MOBILITY_TEST_FRAMEWORK
+ iCommsMobilityApi->MigrateToPreferredCarrier();
+ }
+ else
+ {
+ // already waiting to finish using old carrier
+ // do not update migration action, stick to first choice.
+ iState = EMobilityWaitForOldSocketClose;
+ }
+ break;
+ }
+
+ case EMobilityUninitialised:
+ case EMobilityIdle:
+ case EMobilityWaitForOldSocketClose:
+ case EMobilityWaitForOldSocketCloseCarrierRejected:
+ case EMobilityWaitForMigrate:
+ case EMobilityConnectingToNewCarrier:
+ default:
+ {
+ // unexpected in this state
+ __ASSERT_DEBUG(EFalse, gPanic(EPanicInvalidMobilityState));
+ }
+ }
+ }
+
+/**
+Instruction from the Messaging Plugin Provider that the new carrier is to be ignored.
+
+@param aAction - action that the server MTM should take when closing existing sockets.
+*/
+EXPORT_C void CImMobilityManager::IgnoreNewCarrier()
+ {
+ __LOG_FORMAT((KDefaultLog, "<%d> Error (state:%d)", iAccountId, iState));
+ switch (iState)
+ {
+ case EMobilityWaitForUpgradePolicyAndOldSocketClose:
+ {
+ // defensive handling of "double upgrade" situation, in which an
+ // upgrade is accepted, then a second upgrade notification is
+ // received before the first handshake completes, and this second
+ // upgrage is rejected.
+ iState = EMobilityWaitForOldSocketCloseCarrierRejected;
+//#ifdef __MOBILITY_TEST_FRAMEWORK
+// TBool handled = CImMobilityTestFramework::Response(*this, KMobilityTestResponseIgnorePreferredCarrier);
+// if (!handled)
+//#endif //__MOBILITY_TEST_FRAMEWORK
+ iCommsMobilityApi->IgnorePreferredCarrier();
+ break;
+ }
+ case EMobilityWaitForUpgradePolicy:
+ case EMobilityWaitForDowngradePolicy:
+ {
+ iState = EMobilityIdle;
+//#ifdef __MOBILITY_TEST_FRAMEWORK
+// TBool handled = CImMobilityTestFramework::Response(*this, KMobilityTestResponseIgnorePreferredCarrier);
+// if (!handled)
+//#endif //__MOBILITY_TEST_FRAMEWORK
+ iCommsMobilityApi->IgnorePreferredCarrier();
+ break;
+ }
+ case EMobilityUninitialised:
+ case EMobilityIdle:
+ case EMobilityWaitForOldSocketClose:
+ case EMobilityWaitForOldSocketCloseCarrierRejected:
+ case EMobilityWaitForMigrate:
+ case EMobilityConnectingToNewCarrier:
+ default:
+ {
+ // unexpected in this state
+ __ASSERT_DEBUG(EFalse, gPanic(EPanicInvalidMobilityState));
+ }
+ }
+ }
+
+/**
+Notification from the server MTM that existing sockets have been closed and that
+it is ready for migration to the new carrier to occur.
+*/
+EXPORT_C void CImMobilityManager::MigrateToNewCarrier()
+ {
+ __LOG_FORMAT((KDefaultLog, "<%d> MigrateToNewCarrier(state:%d)", iAccountId, iState));
+ // otherwise... switch on state.
+ switch (iState)
+ {
+ case EMobilityWaitForOldSocketClose:
+ {
+ iState = EMobilityWaitForMigrate;
+//#ifdef __MOBILITY_TEST_FRAMEWORK
+// TBool handled = CImMobilityTestFramework::Response(*this, KMobilityTestResponseMigrateToPreferredCarrier);
+// if (!handled)
+//endif //__MOBILITY_TEST_FRAMEWORK
+ iCommsMobilityApi->MigrateToPreferredCarrier();
+ break;
+ }
+ case EMobilityWaitForUpgradePolicyAndOldSocketClose:
+ {
+ // ahha! we have since received a notice that an even better
+ // carrier has come along. Wait for what we should do.
+ iState = EMobilityWaitForUpgradePolicy;
+ break;
+ }
+ case EMobilityWaitForOldSocketCloseCarrierRejected:
+ {
+ // instruct the MTM to reconnect - using the original AP
+ // This is effectively the same as making an initial connection
+ // so slip to default connected state.
+ iState = EMobilityIdle;
+ iMtm.NewCarrierActive(iOldAp, iIsSeamless);
+ break;
+ }
+ case EMobilityUninitialised:
+ case EMobilityIdle:
+ case EMobilityWaitForUpgradePolicy:
+ case EMobilityWaitForDowngradePolicy:
+ case EMobilityWaitForMigrate:
+ case EMobilityConnectingToNewCarrier:
+ default:
+ {
+ // unexpected in this state
+ __ASSERT_DEBUG(EFalse, gPanic(EPanicInvalidMobilityState));
+ }
+ }
+ }
+
+/**
+Notification from the server MTM that it has successfully re-established connection
+with the remote server using the new carrier.
+*/
+EXPORT_C void CImMobilityManager::NewCarrierAccepted()
+ {
+ __LOG_FORMAT((KDefaultLog, "<%d> NewCarrierAccepted(state:%d)", iAccountId, iState));
+ switch (iState)
+ {
+ case EMobilityIdle:
+ {
+ // Do nothing. This might occur if previous state
+ // was EMobilityWaitForOldSocketCloseCarrierRejected
+ // the mobility framework is not expecting a response.
+ break;
+ }
+ case EMobilityConnectingToNewCarrier:
+ {
+ iState = EMobilityIdle;
+//#ifdef __MOBILITY_TEST_FRAMEWORK
+// TBool handled = CImMobilityTestFramework::Response(*this, KMobilityTestResponseNewCarrierAccepted);
+// if (!handled)
+//#endif //__MOBILITY_TEST_FRAMEWORK
+ iCommsMobilityApi->NewCarrierAccepted();
+ // Tell the policy provider about it.
+ CImMobilityPolicyProvider::GetRef().MigrationComplete(iAccountId, KImMigrateOK, iNewAp);
+ break;
+ }
+ case EMobilityUninitialised:
+ case EMobilityWaitForUpgradePolicy:
+ case EMobilityWaitForDowngradePolicy:
+ case EMobilityWaitForUpgradePolicyAndOldSocketClose:
+ case EMobilityWaitForOldSocketCloseCarrierRejected:
+ case EMobilityWaitForOldSocketClose:
+ case EMobilityWaitForMigrate:
+ default:
+ {
+ // unexpected in this state
+ __ASSERT_DEBUG(EFalse, gPanic(EPanicInvalidMobilityState));
+ }
+ }
+ }
+
+/**
+Notification from the server MTM that it has been unable to re-established connection
+with the remote server using the new carrier.
+*/
+EXPORT_C void CImMobilityManager::NewCarrierRejected()
+ {
+ __LOG_FORMAT((KDefaultLog, "<%d> NewCarrierRejected(state:%d)", iAccountId, iState));
+ switch (iState)
+ {
+ case EMobilityIdle: // this results from the initial carrier being rejected.
+ case EMobilityConnectingToNewCarrier:
+ {
+ iState = EMobilityIdle;
+//#ifdef __MOBILITY_TEST_FRAMEWORK
+// TBool handled = CImMobilityTestFramework::Response(*this, KMobilityTestResponseNewCarrierRejected);
+// if (!handled)
+//#endif //__MOBILITY_TEST_FRAMEWORK
+ iCommsMobilityApi->NewCarrierRejected();
+ // tell the policy provider about it.
+ CImMobilityPolicyProvider::GetRef().MigrationComplete(iAccountId, KImMigrateCouldNotReconnect, iNewAp);
+ break;
+ }
+ case EMobilityUninitialised:
+ case EMobilityWaitForUpgradePolicy:
+ case EMobilityWaitForDowngradePolicy:
+ case EMobilityWaitForUpgradePolicyAndOldSocketClose:
+ case EMobilityWaitForOldSocketCloseCarrierRejected:
+ case EMobilityWaitForOldSocketClose:
+ case EMobilityWaitForMigrate:
+ default:
+ {
+ // unexpected in this state
+ __ASSERT_DEBUG(EFalse, gPanic(EPanicInvalidMobilityState));
+ }
+ }
+ }