videoconnutility/connutility/src/vcxconnutilimpl.cpp
branchRCL_3
changeset 23 13a33d82ad98
parent 0 822a42b6c3f1
--- /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 <e32cmn.h>
+#include <bldvariant.hrh>
+#include <commdb.h>            // CMDBSession
+#include <commsdattypesv1_1.h> // CCDWAPIPBearerRecord
+#include <ConnectionUiUtilities.h> 
+#include <cmdestination.h>
+#include <cdbcols.h>
+#include <commdbconnpref.h>
+#include <eikbtgrp.h>
+#include <WlanCdbCols.h>
+#include <connpref.h>
+#include <extendedconnpref.h>
+#include <mpxlog.h>
+
+#include <ipvideo/vcxconnectionutility.h>
+#include <ipvideo/vcxconnutilengineobserver.h>
+#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<CCDWAPIPBearerRecord*>( 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<TUint32>( 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