diff -r 7e41d162e158 -r abbed5a4b42a networkcontrol/ipcprshim/src/connectionSelectorShim.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/networkcontrol/ipcprshim/src/connectionSelectorShim.cpp Tue Aug 31 16:45:15 2010 +0300 @@ -0,0 +1,557 @@ + +// Copyright (c) 2005-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: +// Implementation file for the CConnectionSelectorShim +// +// + +/** + @file + @internalComponent +*/ + + +#include +#include +#ifndef SYMBIAN_NETWORKING_UMTSR5 +#include +#endif //SYMBIAN_NETWORKING_UMTSR5 +#include +#include +#include +#include "shimcprfactory.h" +#include "connectionSelectorShim.h" +#include "shimcpr.h" + +using namespace ESock; + +//PREQ399_REMOVE +#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS +#include +#endif +//SYMBIAN_NETWORKING_3GPPDEFAULTQOS //PREQ399_REMOVE + +TInt CConnectionSelectorShim::AsyncDestructorCb(TAny* aInstance) + { + CConnectionSelectorShim* selector = reinterpret_cast(aInstance); + delete selector; + return KErrNone; + } + +CConnectionSelectorShim::CConnectionSelectorShim(ISelectionNotify& aNotify) : + iNotify(aNotify), + iAsyncDestructor(CActive::EPriorityStandard + 1), + iConnProvider(NULL) +/** +C'tor. + +The priority of the async destructor is specifically set one higher than normal +to cater for the case whereby an RConnection is started asynchronously and +immediately closed. This ensures that the async destructor is called before +NetCon begins the selection procedure, and hence can cancel the NetCon request +before it starts. This causes immediate cancellation of the connection start +procedure. Otherwise, NetCon gets in first, the connection comes all the way +and then times out in the short timer. + +@param aNotify the ISelectionNotify that should be notified about the +selection progress. +*/ + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tCConnectionSelectorShim"), this)); + iAsyncDestructor.Set(TCallBack(AsyncDestructorCb, this)); + } + +CConnectionSelectorShim::~CConnectionSelectorShim() + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\t~CConnectionSelectorShim"), this)); + + iNotify.Detach(); //"PrevLayer"::Detach() will be called only once. + + delete iSelectorSession; + + iSelectionInfo.Close(); + } + + +void CConnectionSelectorShim::DeleteAsync() + { + if (!iAsyncDestructor.IsActive()) + { + if (iConnProvider) + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tDeleteAsync() RelaseRef(this)"), this)); + iConnProvider->ReleaseRef(this); + } + iAsyncDestructor.CallBack(); + } + } + +#ifdef SYMBIAN_NETWORKING_UMTSR5 +void CConnectionSelectorShim::SetFactoryIface(MIAPLockInfo * aFactoryIface) + { + iFactoryIface = aFactoryIface; + } + +#endif // #ifdef SYMBIAN_NETWORKING_UMTSR5 + +TInt CConnectionSelectorShim::Cancel() + { + return Cancel(KErrCancel,NULL); + } + +TInt CConnectionSelectorShim::Cancel(TInt aReason, const RMessage2* aMessage) + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tCancel(aReason %d)"), this, aReason)); + TInt error = KErrNone; + if (iSelectorSession) + { + error = iSelectorSession->Stop(aReason, aMessage); + delete iSelectorSession; + iSelectorSession = NULL; + } + + //"PrevLayer"::Detach() will be called only once. + //It is important to call iNotify.Detach() after all progress notifications + //resulting from NifSession::Stop() have been passed up towards the CConnection. + iNotify.Detach(); + DeleteAsync(); + return error; + } + +TInt CConnectionSelectorShim::Select(Meta::SMetaData& aPreferences, const RMessagePtr2* aMessage) +/** Implements CConnectorSelector::Select (async). The shim layer (this layer) +delegates the selection to NIFMAN. NIFMAN cannot be asked just to perform the +selection, as the selection is tighly coupled with starting connection provider. + +@param aPreferences connection preferences. +*/ + { + //Assume this is a TConnStart (as defined in ss_connprov.h) + STypeId type = aPreferences.GetTypeId(); + ASSERT(type.iUid.iUid == KESockMessagesImplementationUid); + ASSERT(type.iType == EESockMessageConnStart); + + const TConnPref* connPrefs = NULL; + TConnStartType stype = EConnStartImplicit; + + if (type.iType == EESockMessageConnStart) + { + connPrefs = reinterpret_cast(aPreferences).ConnPrefs(); + stype = reinterpret_cast(aPreferences).StartType(); + if (connPrefs && connPrefs->ExtensionId() == TConnPref::EConnPrefSnap) + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tSelect() with not supported preferences EConnPrefSnap"), this)); + iNotify.SelectComplete(NULL, KErrNotSupported); + DeleteAsync(); + return KErrNotSupported; + } + } + +#ifdef SYMBIAN_NETWORKING_UMTSR5 + + // The code here will check the secure ID of the application which is expected with the aMessage Ptr. + // The logic used here is that if a General purpose application locks an IAP then no other application + // should be allowed to start the connection ans should return with KErrAccessDenied. + if(aMessage!=NULL) + { + iAppSecureId = aMessage->SecureId(); + } + #endif //SYMBIAN_NETWORKING_UMTSR5 + + TRAPD(ret, + iSelectorSession = Nif::NewConnectionL(this, 0); + if (connPrefs) + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tSelect() with preferences, iSelectorSession %x"), this, iSelectorSession)); + iSelectorSession->StartL(stype, *connPrefs, aMessage ); + } + else + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tSelect() no preferences, iSelectorSession %x"), this, iSelectorSession)); + iSelectorSession->StartL(stype, aMessage ); + } + ); + if (ret != KErrNone) + { + iNotify.SelectComplete(NULL, ret); + DeleteAsync(); + } + return ret; + } + + +void CConnectionSelectorShim::SelectionComplete(TInt aError, const TDesC8& aSelectionInfo) +/** Called by NIFMAN when the selection (previously triggered by CConnectionSelectorShim::SelectL) +completes the selection. There are two methods NIFMAN will use to indicate progress to its client. This +method and the generic ::ProgressNotification. This method forwards selection complete to +this->ProgressNotification(KFinishedSelection). + +@param aError operation result. +@param aSelectionInfo selection info (to be converted to TSoIfConnectionInfo {iIAPId; iNetworkId;}) +*/ + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tSelectionComplete(), aError: %d"), this, aError)); + iSelectionInfo.Close(); + TInt err; + if((err = iSelectionInfo.Create(aSelectionInfo)) != KErrNone) + { + aError = err; + } +#ifdef SYMBIAN_NETWORKING_UMTSR5 + // The following line will extract connection information which is sent by nifman after agent selection.The information contains IAP , iNetworkId + //and connection information. + + Mem::Copy(&iConnectionInfo, aSelectionInfo.Ptr(),sizeof(iConnectionInfo)); +#endif + ProgressNotification(KFinishedSelection, aError); + } + +void CConnectionSelectorShim::CreateProviderL() + { + ASSERT(iSelectionInfo.Length());//this should only happen after the agent's been selected + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tCreateProviderL() iConnProvider %x"), this, iConnProvider)); + if (iConnProvider) + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tCreateProviderL() iConnProvider->GetNifSession() %x"), this, iConnProvider->GetNifSession())); + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tCreateProviderL() iConnProvider->ConnectionInfo() %S"), this, &iConnProvider->ConnectionInfo())); + } + //if we have a provider already and it's the existing one we have to check whether the conn info still matches since there could've been + //a reconnection + if ( iConnProvider && iConnProvider->GetNifSession() && iConnProvider->ConnectionInfo() != iSelectionInfo ) + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tCreateProviderL() -> ReleaseRef()"), this)); + iConnProvider->ReleaseRef(this); + iConnProvider = NULL; + } + if ( !iConnProvider ) + { + TSockManData* sockManData = SockManGlobals::Get(); + ASSERT(sockManData); + + CConnectionFactoryContainer* connectionFactories = sockManData->iConnectionFactories; + ASSERT(connectionFactories); + + CConnectionProviderFactoryBase* factory = connectionFactories->FindFactory(KShimConnectionProviderFactoryId); + ASSERT(factory); + if (IsConnectionStoppingL()) + { + // We must force the creation of a new provider because the old one is on its way out. + // This is required to ensure that we do not receive progresses generated as the connection + // comes down. We are only interested in progresses generated when the connection subsequently + // starts coming up again. Upper layers starting a connection just as it is coming down will + // otherwise receive these progresses. In particular, progresses with an error will otherwise + // be mistaken for an indication that the connection startup failed. + iConnProvider = (CConnectionProviderShim*)factory->CreateProviderL(); + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tCreateProviderL() - connection stopping, iConnProvider %x"), this, iConnProvider)); + } + else + { + XConnectionFactoryQueryInfo query(NULL, iSelectionInfo); + iConnProvider = (CConnectionProviderShim*)factory->FindOrCreateProviderL(query); + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tCreateProviderL() - found/created iConnProvider %x"), this, iConnProvider)); + } + //and keep provider up during the selection + iConnProvider->AddRefL(this); + } + } + +TBool CConnectionSelectorShim::IsConnectionStoppingL() + { + TPckg stopping(EFalse); + iSelectorSession->ControlL(KCOLProvider, KNifSessionGetStopping, stopping, NULL); + return stopping(); + } + +void CConnectionSelectorShim::HandleSelectionL() + { + // HandleSelection will set up the provider + + // Set default factory as the CConnectionProviderFactoryShim + CreateProviderL(); + if (iSelectorSession && !iConnProvider->GetNifSession()) + { + iConnProvider->SetConnectionInfo(iSelectionInfo); + // + // The factory didn't find an existing provider that matched the query. + // It's returned a brand new instance of CConnectionProviderShim. + // Hence we'll call Initialise. this will do 2 things: + // + // 1. Create a secure nif(man) session for the provider + // 2. Call ConnectionControlActivity for the provider so that + // + iConnProvider->InitialiseL(iSelectorSession); + iConnProvider->SetBlockProgressesL(iSelectorSession); + iSetProviderNull = ETrue; + } + } + + +#ifdef SYMBIAN_NETWORKING_UMTSR5 +void CConnectionSelectorShim::MaybeLockIapL() + { + //The value of Secure ID is fetched from DataBase againt IAP.Iap is taken agent selection is over.This will look + //into the database if secureID feild is NULL or not if it is NULL then IAP will not be locked + CMDBSession* cmdbSession; + CCDIAPRecord* ptrIapRecord; + ptrIapRecord = static_cast(CCDRecordBase::RecordFactoryL(KCDTIdIAPRecord)); + CleanupStack::PushL(ptrIapRecord); + + // Create a new CMDB session Object + cmdbSession = CMDBSession::NewL(KCDVersion1_1); + // If successm Get and Load the record. + CleanupStack::PushL(cmdbSession); + + ptrIapRecord->SetRecordId(iConnectionInfo.iIAPId); + ptrIapRecord->LoadL(*cmdbSession); + // Although the SecureID of the application is numerical, we have to take it into the string buffer + // because of the limitations of the CommsDat, which dont support hexadeciaml values, and truncate + // decimal values after 8 digits, for some unknown reasons. + // Because of the current project schedule, its not feasible to rectify commsdat as of now, so decided + // to take on string Buffers to be used for Secure Ids from commsdat + TUint32 secureId; + secureId=ptrIapRecord->iAppSid; + + if(secureId==iAppSecureId.iId && iAppSecureId.iId!=NULL) + { + // Inform the Factory that the Ids match so IAP will be locked. The IAP number is also given to + // the factory so that the application can start connection on other IAPs which are not locked + // by the program + iFactoryIface->SetIAPLockStatus(ETrue,iConnectionInfo.iIAPId); + } + + CleanupStack::Pop(cmdbSession); + delete cmdbSession; + CleanupStack::Pop(ptrIapRecord); + delete ptrIapRecord; + + } +#endif + +void CConnectionSelectorShim::ProgressNotification(TInt aStage, TInt aError) +/** + +@param +*/ + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tProgressNotification(%d, %d)"), + this, aStage, aError)); + + // In all cases we must pass the new progress up the chain of selectors + if (aError == KErrNone) + { + aError = iError; + } + // + // Depending on the progress and the progress error, we need to handle situations differently + // + // Normally, if progress has reached KFinishedSelection, we stop propogating the progress + // up, because, we would have already setup the provide (iProvider) with a new nif session + // pointing to the same agent as iSelectorSession, hence further messages from agent and + // nifman will be forwared to the provider. + // + // However, there are two exceptions to this situation: + // We have a provider that's already been initialized with a nif session + // signified by !iSetProviderNull, in which case, we forward the message up + // whether or not we have finished selection. Same goes for situations when + // we have progress error, instead of waiting for the provider to propogate the + // message upwards, we use iNotify to do that, since the client would expect the + // message (e.g. Stop) to be completed with error immidiately + // + + // Any error means that the selection (and startup of the interface) will be abandoned and reported to the client. + if (aError != KErrNone) + { + iNotify.ProgressNotification(aStage, aError); + iNotify.SelectComplete(NULL, aError); + DeleteAsync(); + } + else if (aStage <= KFinishedSelection || !iSetProviderNull) + { + iNotify.ProgressNotification(aStage, aError); + } + + if (aStage == KFinishedSelection && aError == KErrNone) + { + // The selection is complete so we want to reach the situation where the selector (this object) is + // joined by the appropriate provider. The provider will be set up with a pointer to the CNifSession + // allowing the calls to methods such as EnumerateSubConnections to work between KFinishedSelection and + // KLinkLayerOpen. The provider will be accessible from the selector until KLinkLayerOpen is reached + // (when the selector will be destroyed). + TRAP(aError,HandleSelectionL()); + if (aError == KErrNone) + { + iNotify.SelectComplete(iConnProvider, aError); + } +#ifdef SYMBIAN_NETWORKING_UMTSR5 + + // First Check IAP Locked, if yes Return, + TBool IapLocked = EFalse; + TInt IapNumber = -1; + + iFactoryIface->GetIAPLockStatus(IapLocked, IapNumber); + + if (IapLocked && IapNumber == iConnectionInfo.iIAPId) + { + //iNotify.ProgressNotification(aStage, KErrPermissionDenied); + iNotify.SelectComplete(iConnProvider, KErrPermissionDenied); + DeleteAsync(); + return; + } +#endif //SYMBIAN_NETWORKING_UMTSR5 + + } + else if (aStage == KConnectionUninitialised) + { + //KConnectionUninitialised means that the interface has been stopped. + DeleteAsync(); + } + else if (aStage == KLinkLayerOpen && !iIsLinkLayerOpen) + { + // Calling iNotify.LayerUp when we have a provider setup with a nif session already + // follows from the logic above justifying propogating progress up when we have a + // provider setup with a nif session + iNotify.LayerUp(aError); + DeleteAsync(); // The interface has successfully started and all responsibility should be taken over by the the provider. + } + +#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS + else if ( aStage == ENullAgtConnecting && aError == KErrNone ) + { +#ifdef SYMBIAN_NETWORKING_UMTSR5 + + TRAPD(ret,MaybeLockIapL()); +#ifdef __CFLOG_ACTIVE + if(ret!=KErrNone) + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tMaybeLockIap left with %d"), + this, ret)); + } +#endif + (void)ret; //TRAP is safe to ignore becuase if MaybeLockIapL: leave the correct behaviour is to leave Iap unlocked. + //We can safely ignore the trap because the function will only lock IAP. One should not be effected if someth +#endif //SYMBIAN_NETWORKING_UMTSR5 + } + +#endif //SYMBIAN_NETWORKING_3GPPDEFAULTQOS //PREQ399_REMOVE + } + + +void CConnectionSelectorShim::SubConnectionEvent(const TSubConnectionEvent& /*aSubConnectionEvent*/) +/** + +@param +*/ + { + } + +void CConnectionSelectorShim::ServiceChangeNotification(TUint32 aId, const TDesC& aType) +/** + +@param +*/ + { + iNotify.ServiceChangeNotification(aId, aType); + } + +void CConnectionSelectorShim::LinkLayerOpen(TInt aError) +/** + +@param +*/ + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tLinkLayerOpen(aError %d)"), + this, aError)); + iIsLinkLayerOpen = ETrue; + if (aError == KErrNone) + { + if (iSetProviderNull) + { + ASSERT(iConnProvider->GetNifSession()); + iConnProvider->ReleaseRef(this); + iConnProvider = NULL; + iSetProviderNull = EFalse; + } + + DeleteAsync(); + } + else + { + iNotify.SelectComplete(NULL, aError); + } + } + +void CConnectionSelectorShim::SetProviderNull() + { + __CFLOG_VAR((KShimCprTag, KShimCprSubTag, _L8("CConnectionSelectorShim %08x:\tSetProviderNull() iConnProvider %x"), this, iConnProvider)); + iConnProvider = NULL; + } + +void CConnectionSelectorShim::ConnectionError(TInt /*aError*/) +/** + +@param +*/ + { + //ignore the event + } + + +void CConnectionSelectorShim::LinkLayerClosed(TInt /*aError*/) +/** + +@param +*/ + { + //ignore the event + } + + + +void CConnectionSelectorShim::ProgressNotification(TSubConnectionUniqueId /*aSubConnectionUniqueId*/, TInt /*aStage*/, TInt /*aError*/) +/** + +@param +*/ + { + } + +void CConnectionSelectorShim::InterfaceStateChangeNotification(TDesC8& /*aInfo*/) +/** + +@param +*/ + { + //ignore the event + } + + +void CConnectionSelectorShim::NotifyDataSent(TSubConnectionUniqueId /*aSubConnectionUniqueId*/, TUint /*aUplinkVolume*/) +/** + +@param +*/ + { + //ignore the event + } + + +void CConnectionSelectorShim::NotifyDataReceived(TSubConnectionUniqueId /*aSubConnectionUniqueId*/, TUint /*aDownlinkVolume*/) +/** + +@param +*/ + { + //ignore the event + } +