diff -r 826cea16efd9 -r 13a33d82ad98 videoconnutility/connutility/src/vcxconnutilimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videoconnutility/connutility/src/vcxconnutilimpl.cpp Wed Sep 01 12:20:37 2010 +0100 @@ -0,0 +1,1155 @@ +/* +* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "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: Class to handle connection creation.* +*/ + + + + +// INCLUDE FILES +#include +#include +#include // CMDBSession +#include // CCDWAPIPBearerRecord +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "vcxconnectionutility.hrh" +#include "vcxconnutilimpl.h" +#include "vcxconnutilengine.h" +#include "vcxconnutilpubsub.h" +#include "vcxconnutilwaitsch.h" + +// CONSTANTS +_LIT( KConnUtilRoleSema, "__ConnUtillMasterSlaveRoleSwitchSema__ "); +_LIT( KConnUtilConnectionSema, "__ConnUtillConnectionCreateSema__ "); + +const TInt KIptvCenRepAPModeAlwaysAsk = 0; +const TInt KConUtilSemaStartupValue = 1; +const TInt KNbrOfNotFoundConnTries = 30; + + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::NewL() +// ----------------------------------------------------------------------------- +// +CVcxConnUtilImpl* CVcxConnUtilImpl::NewL( CVcxConnectionUtility* aUiInterface ) + { + CVcxConnUtilImpl* self = CVcxConnUtilImpl::NewLC( aUiInterface ); + CleanupStack::Pop( self ); // self; + return self; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::NewLC() +// ----------------------------------------------------------------------------- +// +CVcxConnUtilImpl* CVcxConnUtilImpl::NewLC( CVcxConnectionUtility* aUiInterface ) + { + CVcxConnUtilImpl* self = new (ELeave) CVcxConnUtilImpl( aUiInterface ); + CleanupStack::PushL( self ); + self->ConstructL( ); + return self; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::ConstructL() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::ConstructL( ) + { + MPX_DEBUG1("vcxconnutil ## CVcxConnUtilImpl::ConstructL() in"); + + iWaitHandler = CVcxConnUtilWaitSch::NewL(); + + iObservers.Reset(); + + TInt err( KErrNone ); + err = iSemaSwitchRole.CreateGlobal( KConnUtilRoleSema, KConUtilSemaStartupValue ); + if( err == KErrAlreadyExists ) + { + // semafore exists already, open it + err = iSemaSwitchRole.OpenGlobal( KConnUtilRoleSema ); + } + User::LeaveIfError( err ); + + err = iSemaCreateConn.CreateGlobal( KConnUtilConnectionSema, KConUtilSemaStartupValue ); + if( err == KErrAlreadyExists ) + { + // semafore exists already, open it + err = iSemaCreateConn.OpenGlobal( KConnUtilConnectionSema ); + } + User::LeaveIfError( err ); + + iEngine = CVcxConnUtilEngine::NewL( this ); + + iPubsub = CVcxConnUtilPubSub::NewL( this ); + + // check and set pubsub -values + TInt activeIap( 0 ); + User::LeaveIfError( iPubsub->GetValue( EVCxPSIapId, activeIap ) ); + if( activeIap != 0 ) + { + // check if there really is connection, if not reinit values + if( !iEngine->IsIapConnected( activeIap ) ) + { + // no connection, data integrity has been corrupted at some point + activeIap = 0; + } + } + if( activeIap == 0 ) + { + MPX_DEBUG1("CVcxConnUtilImpl::ConstructL() no connection yet, initing values"); + User::LeaveIfError( iPubsub->SetValue( EVCxPSMasterExists, 0 ) ); + + User::LeaveIfError( iPubsub->SetValue( EVCxPSIapId, 0 ) ); + + User::LeaveIfError( iPubsub->SetValue( EVCxPSSnapId, 0 ) ); + + User::LeaveIfError( iPubsub->SetValue( + EVCxPSConnectionStatus, EVCxNotConnected ) ); + + User::LeaveIfError( iPubsub->SetValue( EVCxPSNbrConnInstances, 0 ) ); + } + + MPX_DEBUG1("vcxconnutil ## CVcxConnUtilImpl::ConstructL() out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::CVcxNsConnectionUtility() +// ----------------------------------------------------------------------------- +// +CVcxConnUtilImpl::CVcxConnUtilImpl( CVcxConnectionUtility* aUiInterface ) : +iUIInterface( aUiInterface ) + { + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::~CVcxConnectionUtility() +// ----------------------------------------------------------------------------- +// +CVcxConnUtilImpl::~CVcxConnUtilImpl() + { + MPX_DEBUG1("vcxconnutil ## CVcxConnUtilImpl::~CVcxConnUtilImpl in"); + + iObservers.Close(); + + if( iEngine && iPubsub ) + { + TRAP_IGNORE( DisconnectL() ); + } + + delete iWaitHandler; + + iSemaSwitchRole.Close(); + iSemaCreateConn.Close(); + + delete iPubsub; + delete iEngine; + + MPX_DEBUG1("vcxconnutil ## CVcxConnUtilImpl::~CVcxConnUtilImpl out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::RegisterObserverL +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::RegisterObserverL( MConnUtilEngineObserver* aObserver ) + { + MPX_DEBUG1("vcxconnutil ## CVcxConnUtilImpl::RegisterObserverL in"); + iObservers.AppendL( aObserver ); + MPX_DEBUG1("vcxconnutil ## CVcxConnUtilImpl::RegisterObserverL out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::RemoveObserver +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::RemoveObserver( MConnUtilEngineObserver* aObserver ) + { + MPX_DEBUG1("Cvcxconnutil ## VcxConnUtilImpl::RemoveObserver in"); + TInt i; + for ( i = 0; i < iObservers.Count(); i++ ) + { + if ( aObserver == iObservers[i] ) + { + iObservers.Remove( i ); + iObservers.Compress(); + break; + } + } + MPX_DEBUG1("Cvcxconnutil ## VcxConnUtilImpl::RemoveObserver out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::EngineConnectionStatus +// ----------------------------------------------------------------------------- +// +TVCxConnectionStatus CVcxConnUtilImpl::EngineConnectionStatus() + { + return iEngine->ConnectionStatus(); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::GetIap +// ----------------------------------------------------------------------------- +// +TInt CVcxConnUtilImpl::GetIap( TUint32& aIapId, TBool aSilent ) + { + MPX_DEBUG1("vcxconnutil ## CVcxConnUtilImpl::GetIap in "); + aIapId = 0; + TInt err( KErrNone ); + // assume always new connection + iNewConnection = ETrue; + + switch ( iEngine->ConnectionStatus() ) + { + case EVCxNotConnected: + case EVCxDisconnecting: + iSemaCreateConn.Wait(); + err = KErrNotFound; + // KErrNotFound from connection creation indicates that we have + // some destination with unusable iap(s) in it for we cannot connect to + // in that case, destination id to db is setted as "always ask" and connection + // creation will be tried again for 30 times + for(TInt i = 0; i < KNbrOfNotFoundConnTries && err == KErrNotFound; ++i) + { + err = CreateConnection( aSilent ); + MPX_DEBUG2("vcxconnutil ## CVcxConnUtilImpl::GetIap - CreateConnection returned %d ", err ); + } + iSemaCreateConn.Signal(); + break; + case EVCxConnecting: + { + // this instance is connecting, meaning engine is waiting for + // networking to create connection, we need to wait for the engine + // to finish it's waiting + TRAP( err, WaitL( EVCxPSConnectionStatus ) ); + if( iEngine->ConnectionStatus() != EVCxConnected ) + { + // if main active object didn't managed to create connection, + // return error. This active object does not know the actual + // error so return KErrGeneral + err = KErrGeneral; + } + else + { + err = HandleFinalizeConnection(); + } + } + break; + case EVCxRoamingAccepted: // pass throught + case EVCxRoamingRequest: // pass throught + TRAP( err, WaitL( EVCxPSConnectionStatus ) ); + default: + iNewConnection = EFalse; + break; + } + + if( err == KErrNone ) + { + // get iap id if any. If this is the first connection for this + // instance, iap id will be fetched later on + aIapId = iEngine->IapId(); + } + + MPX_DEBUG2("vcxconnutil ## CVcxConnUtilImpl::GetIap out error: %d ", err ); + return err; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::WapIdFromIapIdL +// ----------------------------------------------------------------------------- +// +TUint32 CVcxConnUtilImpl::WapIdFromIapIdL( TUint32 aIapId ) + { + MPX_DEBUG1("vcxconnutil ## CVcxConnUtilImpl::WapIdFromIapIdL() in "); + MPX_DEBUG2("vcxconnutil ## CVcxConnUtilImpl::WapIdFromIapIdL() IAP id = %d", aIapId); + CMDBSession* db = CMDBSession::NewL( CMDBSession::LatestVersion() ); + CleanupStack::PushL( db ); + + // WapIpBearer table contains the mapping between wap and iap id's. + CCDWAPIPBearerRecord* wapBearerRecord = + static_cast( CCDRecordBase::RecordFactoryL( KCDTIdWAPIPBearerRecord ) ); + + CleanupStack::PushL( wapBearerRecord ); + + wapBearerRecord->iWAPIAP = aIapId; + + TBool found = wapBearerRecord->FindL( *db ); + + if ( !found ) + { + MPX_DEBUG1("vcxconnutil ## CVcxConnUtilImpl::WapIdFromIapIdL() Record was not found. Leaving with KErrNotFound."); + User::Leave(KErrNotFound); + } + + TUint32 wap = static_cast( wapBearerRecord->iWAPAccessPointId ); + + CleanupStack::PopAndDestroy( wapBearerRecord ); + CleanupStack::PopAndDestroy( db ); + + MPX_DEBUG2("vcxconnutil ## CVcxConnUtilImpl::WapIdFromIapIdL() Matching WAP id = %d", wap); + MPX_DEBUG1("vcxconnutil ## CVcxConnUtilImpl::WapIdFromIapIdL() out "); + return wap; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::PrepareConnSettings() +// ----------------------------------------------------------------------------- +// +TInt CVcxConnUtilImpl::PrepareConnSettings() + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::PrepareConnSettings in"); + TInt err( KErrNone ); + TInt vcDestinationID( 0 ); + + if ( !iEngine->QueryConn() ) + { + TRAP( err, vcDestinationID = + iEngine->GetCmmDestinationIdL( CMManager::ESnapPurposeUnknown ) ); + MPX_DEBUG2( "vcxconnutil ## CVcxConnUtilImpl::PrepareConnSettings - destination id %d", vcDestinationID); + } + + TBool detailsGotten( EFalse ); + TRAP( err, detailsGotten = iEngine->PrepareConnectionDetailsL( vcDestinationID ) ); + if( err == KErrNone && !detailsGotten ) + { + // not able to resolve connection details, proceed with always ask + iEngine->ResetConnectionInfo(); + } + + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::PrepareConnSettings out"); + return err; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::CreateConnection() +// ----------------------------------------------------------------------------- +// +TInt CVcxConnUtilImpl::CreateConnection( TBool aSilent ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::CreateConnectionL in"); + + TInt err( KErrNone ); + + TInt connStatusPS( EVCxNotConnected ); + + err = PrepareConnSettings(); + if( err != KErrNone ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::CreateConnectionL error getting connsettings out"); + return err; + } + + err = iPubsub->GetValue( EVCxPSConnectionStatus, connStatusPS ); + if( err != KErrNone ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::CreateConnectionL error getting PS conn status out"); + return err; + } + + // if there is already an active connection created by some other + // instance, use that one + TInt snapId( 0 ); + TBool masterConnect( EFalse ); + + if( connStatusPS == EVCxConnected || connStatusPS == EVCxRoamingRequest ) + { + err = iPubsub->GetValue( EVCxPSSnapId, snapId ); + if( err != KErrNone ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::CreateConnectionL error getting PS snap id, out"); + return err; + } + if( snapId == 0 ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::CreateConnectionL not usable snap is in PS"); + // current snap is undefined, set snap id KErrNotFound for + // DoCreateConnection to use active iap instead of snap id + snapId = KErrNotFound; + } + } + else + { + masterConnect = ETrue; + snapId = iEngine->DestinationId(); + } + + err = DoCreateConnection( aSilent, snapId, masterConnect ); + if( err == KErrNotFound && masterConnect ) + { + // KErrNotFound from connection creation indicates that we have + // some destination with unusable iap(s) in it. Enable connection query. + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::CreateConnectionL - set connection query"); + iEngine->SetQueryConn( ETrue ); + } + if( err == KErrNone ) + { + err = HandleFinalizeConnection(); + } + + MPX_DEBUG2( "vcxconnutil ## CVcxConnUtilImpl::CreateConnectionL out (%d)", err); + return err; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::DoCreateConnection() +// ----------------------------------------------------------------------------- +// +TInt CVcxConnUtilImpl::DoCreateConnection( TBool /*aSilent*/, TInt32 aSnapId, TBool aMasterConnect ) + { + MPX_DEBUG2( "vcxconnutil ## CVcxConnUtilImpl::DoCreateConnectionL in (snapId=%d)", aSnapId); + + TInt err( KErrNone ); + + if ( aSnapId == KIptvCenRepAPModeAlwaysAsk ) + { + //In always ask mode we show always ask dialog + TCommDbConnPref connPref; + connPref.SetDialogPreference( ECommDbDialogPrefPrompt ); + err = iEngine->StartToConnect( connPref ); + MPX_DEBUG2( "CVcxConnUtilImpl::DoCreateConnectionL connection start always ask err %d", err); + } + else if ( aSnapId > KIptvCenRepAPModeAlwaysAsk ) + { + TConnSnapPref prefs; + prefs.SetSnap( aSnapId ); + err = iEngine->StartToConnect( prefs, aMasterConnect ); + MPX_DEBUG2( "CVcxConnUtilImpl::DoCreateConnectionL connection start err %d", err); + } + else + { + TInt iapPS( 0 ); + err = iPubsub->GetValue( EVCxPSIapId, iapPS ); + if( err == KErrNone ) + { + if( iapPS ) + { + TCommDbConnPref connPref; + connPref.SetIapId( iapPS ); + connPref.SetDialogPreference( ECommDbDialogPrefDoNotPrompt ); + err = iEngine->StartToConnect( connPref, EFalse ); + MPX_DEBUG2( "CVcxConnUtilImpl::DoCreateConnectionL connection via iap start err %d", err); + } + else + { + err = KErrNotFound; + } + } + } + if( err == KErrNone && aMasterConnect ) + { + err = iEngine->CreateMobility(); + } + MPX_DEBUG2( "vcxconnutil ## CVcxConnUtilImpl::DoCreateConnectionL out (%d)", err); + return err; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::HandleFinalizeConnection() +// ----------------------------------------------------------------------------- +// +TInt CVcxConnUtilImpl::HandleFinalizeConnection() + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleFinalizeConnection in"); + if( !iNewConnection ) + { + // if connection is not new for this instance + // no finalizing required + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleFinalizeConnection no new connection, out"); + return KErrNone; + } + if( iEngine->ConnectionStatus() != EVCxConnected ) + { + // connection not ok, no point to proceed, return error + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleFinalizeConnection not connected, out"); + return KErrGeneral; + } + + iNewConnection = EFalse; + TRAPD( err, iEngine->FillActiveConnectionDetailsL() ); + + if( err == KErrNone ) + { + TRAP( err, iPubsub->IncCounterPubSubL( EVCxPSNbrConnInstances ) ); + if( err == KErrNone ) + { + // master role check and switch if necessary + if( !iMaster ) + { + err = CheckAndChangeSlaveToMaster(); + } + } + if( err == KErrNone && iMaster ) + { + TRAP( err, SaveConnectionToPubSubL() ); + } + if( err == KErrNone ) + { + // start getting events from pubsub + iPubsub->StartSubscibers(); + } + } + if( err != KErrNone ) + { + // some operation above failed, internal error + // try to disconnect and return error + TRAPD( errDisc, DisconnectL() ); + // return latest error if disconnecting fails + if( errDisc != KErrNone ) + { + err = errDisc; + } + } + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleFinalizeConnection out"); + return err; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::DisconnectConnection() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::DisconnectL() + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::Disconnect in"); + TVCxConnectionStatus connStatus = iEngine->ConnectionStatus(); + + // if this is a master, and it is roaming we need to wait + // for roaming to finish + if( iMaster ) + { + // because EVCxRoamingAccepted is never saved as + // connection status to PS, + // it is safe to wait PS value key change here + if( connStatus == EVCxRoamingRequest || + connStatus == EVCxRoamingAccepted ) + { + MPX_DEBUG1( "CVcxConnUtilImpl::Disconnect master waiting roaming to finish"); + WaitL( EVCxPSConnectionStatus ); + MPX_DEBUG1( "CVcxConnUtilImpl::Disconnect master waiting finished"); + connStatus = iEngine->ConnectionStatus(); + } + } + else + { + // if slave is about to disconnect + // and it's internal state is roaming + // we know that it has been responded to + // roaming request. Decrease value here + if( connStatus == EVCxRoamingRequest || + connStatus == EVCxRoamingAccepted || + connStatus == EVCxPendingClientRequest ) + { + if( connStatus == EVCxRoamingAccepted ) + { + MPX_DEBUG1( "CVcxConnUtilImpl::Disconnect slave removes it's acceptance"); + iPubsub->DecCounterPubSubL( EVCxPSNbRoamAccepted ); + } + MPX_DEBUG1( "CVcxConnUtilImpl::Disconnect slave removes it's response"); + iPubsub->DecCounterPubSubL( EVCxPSNbrRoamResp ); + } + } + + // disconnecting, no longer interested in pubsub events + iPubsub->CancelValueSubscribers(); + + if( connStatus == EVCxNotConnected ) + { + return; + } + + TInt nbrOfConnUsers( 0 ); + User::LeaveIfError( iPubsub->GetValue( EVCxPSNbrConnInstances, nbrOfConnUsers ) ); + + if( nbrOfConnUsers > 0 ) + { + iPubsub->DecCounterPubSubL( EVCxPSNbrConnInstances ); + } + iPubsub->GetValue( EVCxPSNbrConnInstances, nbrOfConnUsers ); + // we're leaving and there are no other instances using connection + if( nbrOfConnUsers == 0 ) + { + // no more connection users, reset PS -values + User::LeaveIfError( iPubsub->SetValue( EVCxPSIapId, 0 ) ); + + User::LeaveIfError( iPubsub->SetValue( EVCxPSSnapId, 0 ) ); + + User::LeaveIfError( iPubsub->SetValue( + EVCxPSConnectionStatus, EVCxNotConnected ) ); + + User::LeaveIfError( iPubsub->SetValue( + EVCxPSRoamingRequestStatus, EVCxRoamingNotInit ) ); + } + iEngine->Disconnect(); + + // cannot be master anymore if not using connection + if( iMaster ) + { + iMaster = EFalse; + User::LeaveIfError( iPubsub->SetValue( EVCxPSMasterExists, 0 ) ); + } + + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::Disconnect out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::SaveConnectionToPubSubL() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::SaveConnectionToPubSubL() + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::SaveConnectionToPubSubL in"); + // publish connection properties + // IAP id: + User::LeaveIfError( iPubsub->SetValue( EVCxPSIapId, iEngine->IapId() ) ); + + // Snap ID: + User::LeaveIfError( iPubsub->SetValue( EVCxPSSnapId, iEngine->DestinationId() ) ); + + // connection State + User::LeaveIfError( iPubsub->SetValue( + EVCxPSConnectionStatus, iEngine->ConnectionStatus() ) ); + + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::SaveConnectionToPubSubL out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::RequestIsRoamingAllowedL() +// ----------------------------------------------------------------------------- +// +TBool CVcxConnUtilImpl::RequestIsRoamingAllowedL() + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::RequestIsRoamingAllowedL in"); + TBool okToRoam( ETrue ); + + // if this instance is master, need to wait for slaves to request their status before proceeding + if( iMaster ) + { + // init pubsubs for roaming request status checking + User::LeaveIfError( iPubsub->SetValue( EVCxPSNbrRoamResp, 0 ) ); + User::LeaveIfError( iPubsub->SetValue( EVCxPSNbRoamAccepted, 0 ) ); + + // query own state + okToRoam = DoRequestClientRoamingL(); + // client might have disconnected + if( iEngine->ConnectionStatus() == EVCxNotConnected ) + { + MPX_DEBUG1( "CVcxConnUtilImpl::RequestIsRoamingAllowedL master disconnected, out"); + return EFalse; + } + + User::LeaveIfError( iPubsub->SetValue( EVCxPSConnectionStatus, EVCxRoamingRequest ) ); + TInt nbrOfConnUsers(0); + User::LeaveIfError( iPubsub->GetValue( EVCxPSNbrConnInstances, nbrOfConnUsers ) ); + if( okToRoam && nbrOfConnUsers > 1 ) + { + + // if we have slaves also using connection, + // we need to wait for them to request roaming statuses + // from their clients also. In this case, the status is being + // checked via pubsub EVCxPSRoamingRequestStatus to which master + // updates after enought resposes are received + MPX_DEBUG1( "CVcxConnUtilImpl::RequestIsRoamingAllowedL master waiting"); + TRAPD( err, WaitL( EVCxPSRoamingRequestStatus ) ); + if( err != KErrNone ) + { + MPX_DEBUG2( "CVcxConnUtilImpl::RequestIsRoamingAllowedL master wait leaved %d", err ); + } + MPX_DEBUG1( "CVcxConnUtilImpl::RequestIsRoamingAllowedL master released"); + + TInt roamingStatus( EVCxRoamingNotInit ); + User::LeaveIfError( iPubsub->GetValue( EVCxPSRoamingRequestStatus, roamingStatus ) ); + if( EVCxRoamingAllowed != roamingStatus ) + { + okToRoam = EFalse; + } + } + } + // reset roaming PS value + User::LeaveIfError( iPubsub->SetValue( EVCxPSRoamingRequestStatus, EVCxRoamingNotInit ) ); + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::RequestIsRoamingAllowedL out"); + return okToRoam; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::DoRequestClientRoamingL() +// ----------------------------------------------------------------------------- +// +TBool CVcxConnUtilImpl::DoRequestClientRoamingL() + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::DoRequestClientRoamingL in" ); + + TBool okToRoam( ETrue ); + TInt err( KErrNone ); + + TVCxConnectionStatus oldState = iEngine->ConnectionStatus(); + iEngine->SetConnectionStatus( EVCxPendingClientRequest ); + for ( TInt i = 0; i < iObservers.Count() && okToRoam; i++ ) + { + TRAP( err, okToRoam = iObservers[i]->RequestIsRoamingAllowedL() ); + if( err != KErrNone || !okToRoam ) + { + okToRoam = EFalse; + break; + } + } + if( iEngine->ConnectionStatus() != EVCxNotConnected ) + { + // operation path back to connection utility, reset state, in case + // client has not diconnected during callback + iEngine->SetConnectionStatus( oldState ); + + if( okToRoam && err == KErrNone ) + { + // roaming ok for this instance, increase nbr of accepted + iPubsub->IncCounterPubSubL( EVCxPSNbRoamAccepted ); + MPX_DEBUG1( "CVcxConnUtilImpl::DoRequestClientRoamingL accepted increased" ); + } + } + + // increase nbr of responses + iPubsub->IncCounterPubSubL( EVCxPSNbrRoamResp ); + + MPX_DEBUG2( "CVcxConnUtilImpl::DoRequestClientRoamingL allowed %d out", okToRoam ); + + return okToRoam; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::IapChanged() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::IapChangedL() + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::IapChanged in"); + if( !iMaster ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::IapChanged not master out"); + return; + } + TInt err( KErrNone ); + + // current information + TUint32 oldIap = iEngine->IapId(); + TVCxConnectionStatus engineStatus = iEngine->ConnectionStatus(); + + // resolve connection information from the network middleware + iEngine->ResetConnectionInfo(); + if( engineStatus != EVCxNotConnected && + engineStatus != EVCxError ) + { + iEngine->FillActiveConnectionDetailsL(); + } + + // if there is no active connection or gotten iap id is invalid + TUint32 iapID = iEngine->IapId(); + if( iapID == 0 || !( iEngine->IsIapConnected( iapID ) ) ) + { + if( engineStatus != EVCxError ) + { + engineStatus = EVCxNotConnected; + } + // signal status before disconnect -call to make sure + // slaves react in case master's disconnecting fails + MPX_DEBUG2( "IapChanged not connected notify %d ", engineStatus ); + iPubsub->SetValue( EVCxPSConnectionStatus, engineStatus ); + + MPX_DEBUG1( "CVcxConnUtilImpl::IapChanged no active iap, diconnect"); + TRAP( err, DisconnectL() ); + if( err != KErrNone ) + { + MPX_DEBUG2( "CVcxConnUtilImpl::IapChanged no active iap, diconnect leaves %d", err ); + } + } + else + { + MPX_DEBUG1( "CVcxConnUtilImpl::IapChanged iap connected"); + engineStatus = EVCxConnected; + iEngine->SetConnectionStatus( EVCxConnected ); + // refresh PS connection state + SaveConnectionToPubSubL(); + } + + // notify clients about iap change + if( engineStatus != EVCxError && ( oldIap != iapID || !iapID ) ) + { + MPX_DEBUG1( "CVcxConnUtilImpl::IapChanged notify observers"); + NotifyObserversIAPChanged(); + } + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::IapChanged out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::WaitL() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::WaitL( TUint32 aWaitId ) + { + iWaitHandler->WaitL( aWaitId ); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::EndWait() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::EndWait( TUint32 aWaitId ) + { + iWaitHandler->EndWait( aWaitId ); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::IsMaster() +// ----------------------------------------------------------------------------- +// +TBool CVcxConnUtilImpl::IsMaster() + { + return iMaster; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::ValueChangedL() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::ValueChangedL( const TUint32& aKey, const TInt& aValue ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::ValueChangedL (TInt) in"); + EndWait( aKey ); + // pubsub key value changed, check and update + // functionality as required. + switch( aKey ) + { + case EVCxPSMasterExists: + { + HandleMasterChangeL(); + break; + } + case EVCxPSConnectionStatus: + { + HandleSlaveConnectionStatusL( aValue ); + break; + } + case EVCxPSNbrRoamResp: + { + HandleRoamingReponsesL( aValue ); + } + break; + case EVCxPSRoamingRequestStatus: + // NOP + break; + default: + User::Leave( KErrNotFound ); + break; + } + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::ValueChangedL (TInt) out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::HandleMasterChangeL() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::HandleMasterChangeL() + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleMasterChangeL in"); + // if this instance is not connected, don't bother + // to change. Not connected instance cannot be master + if( iMaster ) + { + MPX_DEBUG1( "CVcxConnUtilImpl::HandleMasterChangeL master, out"); + return; + } + + if( iEngine->ConnectionStatus() != EVCxConnected ) + { + MPX_DEBUG1( "CVcxConnUtilImpl::HandleMasterChangeL not connected, out"); + return; + } + + User::LeaveIfError( CheckAndChangeSlaveToMaster() ); + + if( iMaster ) + { + // at this point we need to reinit ex-slave's connection to use + // destination (snap) instead of IAP for the ex-slave to be able + // to get mobility events. + // if original connection was via IAP due "always ask", do nothing + if( iEngine->DestinationId() ) + { + // this instance has become master, so it needs to init the mobility object + if( iEngine->CreateMobility() != KErrNone ) + { + MPX_DEBUG1( "CVcxConnUtilImpl::HandleMasterChangeL master reinit connection not ok"); + DisconnectL(); + } + else + { + MPX_DEBUG1( "CVcxConnUtilImpl::HandleMasterChangeL master reinit connection ok"); + iEngine->FillActiveConnectionDetailsL(); + SaveConnectionToPubSubL(); + } + } + } + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleMasterChangeL out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::CheckAndChangeSlaveToMaster() +// ----------------------------------------------------------------------------- +// +TInt CVcxConnUtilImpl::CheckAndChangeSlaveToMaster() + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::CheckAndChangeSlaveToMaster in"); + TInt err( KErrNone ); + TInt status( 0 ); + + /////// + // entering critical section + iSemaSwitchRole.Wait(); + err = iPubsub->GetValue( EVCxPSMasterExists, status ); + // if master already exists, do nothing + if( !status && err == KErrNone) + { + MPX_DEBUG1( "CVcxConnUtilImpl::CheckAndChangeSlaveToMaster changing master"); + iMaster = ETrue; + err = iPubsub->SetValue( EVCxPSMasterExists, iMaster ); + } + iSemaSwitchRole.Signal(); + // Leaving critical section + /////// + + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::CheckAndChangeSlaveToMaster out"); + return err; + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::HandleSlaveConnectionStatusL() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::HandleSlaveConnectionStatusL( const TInt& aNewStatus ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleSlaveConnectionStatus in"); + // if master, do nothing + if( iMaster ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleSlaveConnectionStatus master out"); + return; + } + // resolve given connection, this structure is needed + // to prevent errors in type check + TVCxConnectionStatus gottenStatus( EVCxNotConnected ); + switch( aNewStatus ) + { + case EVCxNotConnected: + gottenStatus = EVCxNotConnected; + break; + case EVCxConnecting: + gottenStatus = EVCxConnecting; + break; + case EVCxConnected: + gottenStatus = EVCxConnected; + break; + case EVCxDisconnecting: + gottenStatus = EVCxDisconnecting; + break; + case EVCxRoamingRequest: + gottenStatus = EVCxRoamingRequest; + break; + case EVCxRoamingAccepted: + gottenStatus = EVCxRoamingAccepted; + break; + case EVCxError: + gottenStatus = EVCxError; + break; + default: + User::Leave( KErrGeneral ); + break; + } + TVCxConnectionStatus currentStatus = iEngine->ConnectionStatus(); + + MPX_DEBUG2( "HandleSlaveConnectionStatus gotten %d", gottenStatus ); + MPX_DEBUG2( "HandleSlaveConnectionStatus current %d", currentStatus ); + + if( gottenStatus == EVCxRoamingRequest && currentStatus == EVCxConnected ) + { + // if master is requesting roaming, query all external clients + // whether we can roam or not + MPX_DEBUG1( "CVcxConnUtilImpl::HandleSlaveConnectionStatus slave check Roaming"); + if ( DoRequestClientRoamingL() ) + { + gottenStatus = EVCxRoamingAccepted; + } + // client might have disconnected during roaming. In that case do not change status + if( iEngine->ConnectionStatus() != EVCxNotConnected ) + { + // set connection status explicitly to tell slave we're roaming + iEngine->SetConnectionStatus( gottenStatus ); + } + } + + else if( ( currentStatus == EVCxRoamingRequest || + currentStatus == EVCxRoamingAccepted || + currentStatus == EVCxConnected ) && + gottenStatus == EVCxConnected ) + { + // if current status was roaming or + // master has notified new connection and state + // has changed to connected, meaning + // master has succesfully reinitialized preferred connection + // slave needs to try to reinit connection via new iap if + // new iap differs from current + + TInt valueFromPS( 0 ); + User::LeaveIfError( iPubsub->GetValue( EVCxPSIapId, valueFromPS ) ); + MPX_DEBUG2( "HandleSlaveConnectionStatus slave iap %d", iEngine->IapId() ); + MPX_DEBUG2( "HandleSlaveConnectionStatus slave PS iap %d", valueFromPS ); + if( valueFromPS != iEngine->IapId() ) + { + User::LeaveIfError( iPubsub->GetValue( EVCxPSSnapId, valueFromPS ) ); + iEngine->Disconnect(); + if( DoCreateConnection( ETrue, valueFromPS, EFalse ) == KErrNone ) + { + // refresh connection details + iEngine->FillActiveConnectionDetailsL(); + MPX_DEBUG1( "CVcxConnUtilImpl::HandleSlaveConnectionStatus slave restarted ok" ); + } + else + { + MPX_DEBUG1( "CVcxConnUtilImpl::HandleSlaveConnectionStatus slave restarting not ok" ); + DisconnectL(); + gottenStatus = EVCxNotConnected; + } + NotifyObserversIAPChanged(); + } + iEngine->SetConnectionStatus( gottenStatus ); + } + else + { + if( gottenStatus == EVCxNotConnected || + gottenStatus == EVCxError ) + { + // master has notified disconnecting or error for some reason + DisconnectL(); + // notify normal disconnect to observers + if( gottenStatus == EVCxNotConnected ) + { + NotifyObserversIAPChanged(); + } + } + } + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleSlaveConnectionStatus out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::ValueChangedL() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::HandleRoamingReponsesL( const TInt& aNbrOfResps ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleRoamingReponsesL in"); + if( !iMaster ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleRoamingReponsesL slave out"); + return; + } + if( iEngine->ConnectionStatus() != EVCxRoamingRequest ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleRoamingReponsesL not roaming"); + return; + } + // check if all have been responded and if all agreed on roaming + TInt nbrOfConUsers( 0 ); + TInt nbrOfAgeed( 0 ); + TInt nbrofResponses( aNbrOfResps ); + + User::LeaveIfError( iPubsub->GetValue( EVCxPSNbrConnInstances, nbrOfConUsers ) ); + User::LeaveIfError( iPubsub->GetValue( EVCxPSNbRoamAccepted, nbrOfAgeed ) ); + + if( nbrOfConUsers == nbrofResponses ) + { + if( nbrofResponses == nbrOfAgeed ) + { + // every instance has responded and all agrees roaming, + // change state for master's main thread to proceed + MPX_DEBUG1( "CVcxConnUtilImpl::HandleRoamingReponsesL EVCxRoamingAllowed"); + + User::LeaveIfError( iPubsub->SetValue( + EVCxPSRoamingRequestStatus, EVCxRoamingAllowed ) ); + } + else + { + MPX_DEBUG1( "CVcxConnUtilImpl::HandleRoamingReponsesL EVCxRoamingNotInit"); + User::LeaveIfError( iPubsub->SetValue( + EVCxPSRoamingRequestStatus, EVCxRoamingNotInit ) ); + } + } + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::HandleRoamingReponsesL out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::NotifyObserversIAPChanged() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::NotifyObserversIAPChanged() + { + for ( TInt i = 0; i < iObservers.Count(); i++ ) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::NotifyObserversIAPChanged notifying observer"); + TRAPD( err, iObservers[i]->IapChangedL() ); + if( err != KErrNone ) + { + MPX_DEBUG2( "vcxconnutil ## NotifyObserversIAPChanged::IapChanged observer leaved %d", err); + } + } + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::DisplayWaitNote() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::DisplayWaitNote(const TDesC& aConnectionName) + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::DisplayWaitNote in"); + if( iUIInterface ) + { + iUIInterface->DisplayWaitNote( aConnectionName ); + } + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::DisplayWaitNote out"); + } + +// ----------------------------------------------------------------------------- +// CVcxConnUtilImpl::CloseWaitNote() +// ----------------------------------------------------------------------------- +// +void CVcxConnUtilImpl::CloseWaitNote() + { + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::CloseWaitNote in"); + if( iUIInterface ) + { + iUIInterface->CloseWaitNote(); + } + MPX_DEBUG1( "vcxconnutil ## CVcxConnUtilImpl::CloseWaitNote out"); + } + +// End of File