datacommsserver/networkcontroller/src/CNetworkController.cpp
changeset 0 dfb7c4ff071f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/networkcontroller/src/CNetworkController.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,811 @@
+// Copyright (c) 2003-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:
+//
+
+/**
+ @file CNetworkController.cpp
+*/
+
+#include "CNetworkController.h"
+#include <comms-infras/nifagt.h>
+#include <comms-infras/nifif.h>
+#include <cdblen.h>
+#include "NetConPanic.h"
+#include "NetConLog.h"
+#include "CTelBearer.h"
+#include "CNetConDlgProcessor.h"
+
+CNetworkController::~CNetworkController()
+/**
+Destuctor
+
+Implementation of CNetworkController
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("~CNetworkController()")); )
+
+	if (iImplicitNotificationCb)
+		{
+		delete iImplicitNotificationCb;
+		}
+
+	iImplicitNotifyList.Close();
+
+	if(iImplicitConnectionAgentName)
+		{
+		delete iImplicitConnectionAgentName;
+		iImplicitConnectionAgentName = NULL;
+		}
+
+	// delete all CNetConRequestBase objects
+	while(!iRequestQueue.IsEmpty())
+		{
+		CNetConRequestBase* request = iRequestQueue.First();
+		iRequestQueue.Remove(*request);
+		delete request;
+		}
+	iRequestQueue.Reset();
+
+	if (iCurrentRequest)
+		{
+		iCurrentRequest->CancelRequest();
+		delete iCurrentRequest;
+		iCurrentRequest = NULL;
+		}
+
+	if (iProcessRequestCb)
+		{
+		delete iProcessRequestCb;
+		}
+
+
+	LOG ( NetConLog::Printf(_L("--------------- Network Controller Finished ---------------")); )
+	}
+
+CNetworkController* CNetworkController::NewL()
+/**
+Factory function
+
+@return the new CNetworkController object
+@exception leaves if memory allocation fails
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::NewL()")); )
+	CNetworkController* self = new(ELeave) CNetworkController();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(); // self
+	return self;
+	}
+
+CNetworkController::CNetworkController()
+/**
+Constructor
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController()")); )
+
+	iRequestQueue.SetOffset(_FOFF(CNetConRequestBase, iLink));
+	}
+
+void CNetworkController::ConstructL()
+/**
+2nd phase of construction
+
+@exception leaves if callback, database, dialog processor or bearer construction fails
+*/
+	{
+	LOG ( NetConLog::Printf(_L("--------------- Network Controller Starting ---------------")); )
+	LOG_DETAILED( NetConLog::Printf(_L("Detailed logging enabled")); )
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::ConstructL()")); )
+
+	// create a callback for processing requests
+	TCallBack callback(ProcessRequestCb, this);
+	iProcessRequestCb = new(ELeave) CAsyncCallBack(callback, CActive::EPriorityStandard);
+
+	// there is no existing implicitly started connection
+	iImplicitConnectionAgentName = NULL;
+
+	// set up callback for implicit connection event notification
+	TCallBack implicitCallBack(ImplicitNotificationCb, this);
+	iImplicitNotificationCb = new(ELeave) CAsyncCallBack(implicitCallBack, CActive::EPriorityStandard);
+
+	// set up telephony bearer with this object as observer and dbaccess
+	// note that all bearers are deleted in the CNetworkControllerBase d'tor
+	CTelBearer* telBearer = CTelBearer::NewLC(this);
+	AddBearerL(telBearer);
+	CleanupStack::Pop(); // telBearer
+
+	// ensure that the telephony bearer was added where we expect
+	__ASSERT_DEBUG(iBearers[KTelBearerPosition] == telBearer, NetConPanic(NetworkController::ENetConTelBearerMissing));
+	}
+
+TInt CNetworkController::FindExistingAgentForSelection(CNifAgentBase*& aAgent, CCommsDbAccess* aDatabase) const
+/**
+Searches for an Agent associated with the selected IAP
+
+@note that there is a one-to-one relationship between agents and IAPs
+@param aAgent if found a pointer to the CNifAgentBase
+@return KErrNotFound if the agent with selected IAP is not found else KErrNone
+@pre the selected IAP setting is stored in the DbAccess object.
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::FindExistingAgentForSelection()")); )
+
+	// read the CommDb ID of the current IAP
+	TUint32 iapId(0);
+	TInt err(KErrNone);
+
+	TRAP(err, aDatabase->GetIntL(TPtrC(IAP), TPtrC(COMMDB_ID), iapId));
+	if (err != KErrNone)
+		{
+		return KErrNotFound;
+		}
+
+	// read network ID of the current IAP
+	TUint32 networkId(0);
+	TRAP(err, aDatabase->GetIntL(TPtrC(IAP), TPtrC(IAP_NETWORK), networkId));
+	if (err != KErrNone)
+		{
+		return KErrNotFound;
+		}
+
+	// find the network
+	CNetwork* network = NULL;
+	err = FindNetworkById(networkId, network);
+	if (err!=KErrNone)
+		{
+		return err;
+		}
+
+	// ask network to find the agent
+	return network->FindAgentByIap(iapId, aAgent);
+	}
+
+void CNetworkController::SelectAgent(MNetworkControllerObserver* aObserver, MServiceChangeObserver* apServiceChangeObserver, TConnStartType aStartType, TInt aConnectionAttempt, TInt aLastConnectionError, const TConnPref& aPrefs)
+
+/**
+Adds a selection request to the queue and calls the Process Request Callback
+This allows the current callstack to unwind.  Processing is resumed at ProcessRequestCb
+
+@param aObserver the pointer to the MNetworkControllerObserver that requested the selection
+@param apServiceChangeObserver that requests service change notification
+@param aStartType how this connection request was started - either Implicit or Explicit
+@param aConnectionAttempt the connection attempt
+@param aLastConnectionError if this is not the first connection attempt the error from the last connection
+@param aPrefs the connection preferences to use in preference(?!) to the ones stored in commdb
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::SelectAgent()")); )
+
+	// create a new request and add it to the queue
+	CNetConRequestBase* newRequest = NULL;
+	TRAPD(err, newRequest = CSelectionRequest::NewL(this, aObserver, aStartType, aPrefs, aConnectionAttempt, aLastConnectionError));
+	if(err!=KErrNone)
+		{
+		aObserver->SelectComplete(err);
+		return;
+		}
+
+    newRequest->ipServiceChangeObserver = apServiceChangeObserver;
+	iRequestQueue.AddLast(*newRequest);
+
+	LOG( NetConLog::Printf(_L("\tAdded request [0x%08x] to queue"), newRequest); )
+
+	// start to process request if not already processing
+	if(!iCurrentRequest)
+		{
+		iProcessRequestCb->CallBack();
+		}
+	}
+
+void CNetworkController::SelectAgent(MNetworkControllerObserver* aObserver, MServiceChangeObserver* apServiceChangeObserver, TConnStartType aStartType, TInt aConnectionAttempt, TInt aLastConnectionError)
+
+/**
+SelectAgent
+
+@param aObserver the pointer to the MNetworkControllerObserver that requested the selection
+@param apServiceChangeObserver that requests service change notification
+@param aStartType how this connection request was started - either Implicit or Explicit
+@param aConnectionAttempt the connection attempt
+@param aLastConnectionError if this is not the first connection attempt the error from the last connection
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::SelectAgent2()")); )
+
+	// construct some default connection preference - this will cause the default commdb settings to be used
+	TConnPref prefs;
+
+	SelectAgent(aObserver, apServiceChangeObserver, aStartType, aConnectionAttempt, aLastConnectionError, prefs);
+	}
+
+void CNetworkController::Reconnect(MNetworkControllerObserver* aObserver, CNifAgentBase* aAgent)
+/**
+Reconnect
+
+@param aObserver the pointer to the MNetworkControllerObserver that requested the selection
+@param aAgent,the agent who's connection failed
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::Reconnect()")); )
+
+	Reconnect(aObserver, aAgent, NULL);
+	}
+
+void CNetworkController::Reconnect(MNetworkControllerObserver* aObserver, CNifAgentBase* aAgent, CStoreableOverrideSettings* aOverrides)
+/**
+Adds a reconnect request to the queue and calls the Process Request Callback
+This allows the current callstack to unwind.  Processing is resumed at ProcessRequestCb
+
+@param aObserver the pointer to the MNetworkControllerObserver that requested the selection
+@param aAgent,the agent who's connection failed
+@param aOverrides,pointer to the override settings to store.
+@note that ownership of these overrides is retained by the caller.
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::Reconnect2()")); )
+
+	CNetConRequestBase* newRequest = NULL;
+	TRAPD(err, newRequest = CReconnectRequest::NewL(this, aObserver, aAgent, aOverrides);)
+	if(err!=KErrNone)
+		{
+		aObserver->ReconnectComplete(err);
+		return;
+		}
+
+	iRequestQueue.AddLast(*newRequest);
+
+	LOG( NetConLog::Printf(_L("\tAdded request [0x%08x] to queue"), newRequest); )
+
+	// start to process request if not already processing
+	if(!iCurrentRequest)
+		{
+		iProcessRequestCb->CallBack();
+		}
+	}
+
+TInt CNetworkController::CancelRequest(MNetworkControllerObserver* aObserver)
+/**
+Cancel the request made by aObserver.
+If this request is currently being processed then stop processing immediately.
+
+@param aObserver pointer to the object that initiated the request
+@return KErrNone if the request was found and cancelled ok otherwise KErrNotFound
+ */
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::CancelRequest()")); )
+
+	TInt retval(KErrNotFound);
+	CNetConRequestBase* request = NULL;
+
+	// find the request to cancel
+	if (iCurrentRequest && iCurrentRequest->Observer() == aObserver)
+		{
+		LOG( NetConLog::Printf(_L("\tCancelled request [0x%08x]"), iCurrentRequest); )
+
+		// cancel the active request - this will cancel all bearer checking and any dialog box activity
+		iCurrentRequest->CancelRequest();
+
+		// delete the request
+		delete iCurrentRequest;
+		iCurrentRequest = NULL;
+
+		// trigger callback to process next request in the queue
+		iProcessRequestCb->CallBack();
+
+		retval = KErrNone;
+		}
+	else
+		{
+		TSglQueIter<CNetConRequestBase> iter(iRequestQueue);
+
+		while ((request = iter++) != NULL)
+			{
+			if (request->Observer() == aObserver)
+				{
+				// remove request from queue
+				iRequestQueue.Remove(*request);
+
+				LOG( NetConLog::Printf(_L("\tCancelled request [0x%08x]"), request); )
+
+				// note: don't call Cancel() on this request as it is not active
+
+				// delete the request
+				delete request;
+				request = NULL;
+
+				retval = KErrNone;
+				break;
+				}
+			}
+		}
+
+	return retval;
+	}
+
+void CNetworkController::AgentConnectionFailure(CNifAgentBase* aAgent, TInt aError)
+/**
+A connection has failed.
+
+@param aAgent the agent who's connection failed
+@param aError the reason for the failure
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::AgentConnectionFailure()")); )
+
+	if(!aAgent)
+		{
+		return;
+		}
+
+	// retrieve agent name
+	TNifAgentInfo info;
+	aAgent->Info(info);
+
+	LOG( NetConLog::Printf(_L("\tAgent '%S' has disconnected with error %d"), &info.iName, aError); )
+
+	// remove warning - the error code is not used in all builds
+	(void)aError;
+
+	// if the agent was the one for implicit connections
+	// then remove the stored name
+	if(iImplicitConnectionAgentName && info.iName == *iImplicitConnectionAgentName)
+		{
+		delete iImplicitConnectionAgentName;
+		iImplicitConnectionAgentName = NULL;
+
+		(void)GetConnectionInfo(aAgent, iImplicitNotifyInfo);
+		iImplicitNotifyEvent = MImplicitConnectionNotify::EImplicitConnectionDown;
+		iImplicitNotificationCb->CallBack();
+		}
+
+	TInt i(0);
+	// remove this agent from any bearers
+	for (i=0; i<iBearers.Count(); ++i)
+		{
+		CBearerBase* bearer = iBearers[i];
+		// try and remove the agent from this bearer - ignore Not Found error
+		TRAPD(err, bearer->RemoveAgentL(aAgent));
+		if (KErrNone != err)
+			{	
+			LOG( NetConLog::Printf(_L("\tERROR: Agent has disconnected from bearer with error %d"), err); )
+			}
+		}
+
+	// remove this agent from its network
+	for (i=0; i<iNetworks.Count(); ++i)
+		{
+		CNetwork* network = iNetworks[i];
+		// try and remove the agent from this network - ignore Not Found error
+		TRAPD(err, network->RemoveAgentL(aAgent));
+		if (KErrNone != err)
+			{	
+			LOG( NetConLog::Printf(_L("\tERROR: Agent has disconnected from network with error %d"), err); )
+			}
+		}
+	}
+
+TInt CNetworkController::GetConnectionInfo(CNifAgentBase* aAgent, TDes8& aConnectionInfo)
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::GetConnectionInfo()")); )
+
+	_LIT(KIapId, "IAP\\Id");
+	_LIT(KNetId, "IAP\\IAPNetwork");
+
+	TSoIfConnectionInfo info;
+	TInt err = aAgent->ReadInt(KIapId(), info.iIAPId);
+	if(err!=KErrNone)
+		{
+		return err;
+		}
+
+	err = aAgent->ReadInt(KNetId(), info.iNetworkId);
+	if(err!=KErrNone)
+		{
+		return err;
+		}
+
+
+	aConnectionInfo = TPckg<TSoIfConnectionInfo>(info);
+	return KErrNone;
+	}
+
+TInt CNetworkController::ProcessRequestCb(TAny* aThisPtr)
+/**
+ProcessRequestCb
+
+@param aThisPtr the pointer to the object that initiated the callback
+@return KErrNone always
+*/
+	{
+	CNetworkController* self = static_cast<CNetworkController*>(aThisPtr);
+	self->ProcessRequest();
+	return KErrNone;
+	}
+
+void CNetworkController::ProcessRequest()
+/**
+ProcessRequest
+Deque a request and start to process it.
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::ProcessRequest()")); )
+	LOG (
+		if (iCurrentRequest)
+			NetConLog::Printf(_L("\tCurrently processing request [0x%08x]"), iCurrentRequest);
+		else
+			NetConLog::Printf(_L("\tNot currently processing any request"));
+
+		if (!iRequestQueue.IsEmpty())
+			NetConLog::Printf(_L("\tSome requests are queued"));
+		else
+			NetConLog::Printf(_L("\tRequest queue is empty"));
+		)
+
+	if (iCurrentRequest)
+		{
+		return;	// we are already processing a request
+		}
+
+	if (!iRequestQueue.IsEmpty())
+		{
+		iCurrentRequest = iRequestQueue.First();
+		iRequestQueue.Remove(*iCurrentRequest);
+		LOG( NetConLog::Printf(_L("--------------- Starting to process request [0x%08x] ---------------"), iCurrentRequest); )
+		iCurrentRequest->StartRequest();
+		}
+	}
+
+void CNetworkController::RequestComplete(const CSelectionRequest* aRequest, TInt aError)
+/**
+A selection request has been processed - queue another one.
+
+@param aRequest pointer to the actual selection request
+@param aError contains the reason for failure of processing the request or KErrNone
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::RequestComplete()")); )
+	__ASSERT_ALWAYS((CNetConRequestBase*)aRequest == iCurrentRequest, NetConPanic(NetworkController::ENetConBadRequestCallback));
+
+	LOG( NetConLog::Printf(_L("--------------- Finished processing request [0x%08x] ---------------"), iCurrentRequest); )
+
+	// Trigger callback to process next request in the queue
+	iProcessRequestCb->CallBack();
+
+	// if this was an implicit request then store the name of the agent for other implicit requests
+	if (aError == KErrNone && aRequest->ConnectionStartType() == EConnStartImplicit)
+		{
+		if(!iImplicitConnectionAgentName)
+			{
+			TRAPD(err, iImplicitConnectionAgentName = (aRequest->AgentName()).AllocL());
+			if (err != KErrNone)
+				{
+				aError = err;
+				}
+			else
+				{
+				iImplicitConnectionPrefs = aRequest->ConnPrefs();
+				iImplicitNotifyInfo = aRequest->AgentConnectionInfo();
+				iImplicitNotifyEvent = MImplicitConnectionNotify::EImplicitConnectionUp;
+				iImplicitNotificationCb->CallBack();
+				}
+			}
+		else
+			{
+			ASSERT(*iImplicitConnectionAgentName == aRequest->AgentName());
+			}
+		}
+
+	ASSERT(aRequest->Observer());
+
+	// signal the observer that the selection is complete
+	if(aError==KErrNone)
+		{
+		aRequest->Observer()->SelectComplete(aRequest->AgentName());
+		}
+	else
+		{
+		aRequest->Observer()->SelectComplete(aError);
+		}
+
+	delete iCurrentRequest;
+	iCurrentRequest = NULL;
+
+	CancelBearerAvailabilityCheck();
+	}
+
+void CNetworkController::RequestComplete(const CReconnectRequest* aRequest, TInt aError)
+/**
+RequestComplete
+
+A reconnect request has been processed - queue another one.
+
+@param aRequest pointer to the actual reconnect request
+@param aError contains the reason for failure of processing the request or KErrNone
+*/
+	{
+	__ASSERT_ALWAYS( (CReconnectRequest*)aRequest == iCurrentRequest, NetConPanic(NetworkController::ENetConBadRequestCallback));
+
+	LOG_DETAILED ( NetConLog::Printf(_L("CNetworkController::RequestComplete(CReconnectRequest aRequest = 0x%08x, aError = %d)"), aRequest, aError); )
+	LOG( NetConLog::Printf(_L("--------------- Finished processing request [0x%08x] ---------------"), iCurrentRequest); )
+
+	// Trigger callback to process next request in the queue
+	iProcessRequestCb->CallBack();
+
+	// signal the observer that the selection is complete
+	aRequest->Observer()->ReconnectComplete(aError);
+
+	delete iCurrentRequest;
+	iCurrentRequest = NULL;
+	}
+
+TInt CNetworkController::RequestImplicitConnectionNotification(MImplicitConnectionNotify* aObserver)
+/**
+Register for implicit connection event notification
+Implicit Connection Notification
+
+@param aObserver to notify of event changes
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::RequestImplicitConnectionNotification()")); )
+
+	if(iImplicitConnectionAgentName)
+		{
+		aObserver->ImplicitConnectionEvent(iImplicitNotifyInfo, MImplicitConnectionNotify::EImplicitConnectionUp);
+		}
+
+	return iImplicitNotifyList.Append(aObserver);
+	}
+
+void CNetworkController::CancelImplicitConnectionNotification(MImplicitConnectionNotify* aObserver)
+/**
+Deregister for implicit connection event notification
+
+@param aObserver to notify of event changes
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::CancelImplicitConnectionNotification()")); )
+
+	TInt index = iImplicitNotifyList.Find(aObserver);
+	if(index>=0)
+		{
+		iImplicitNotifyList.Remove(index);
+		}
+	}
+
+TInt CNetworkController::ImplicitNotificationCb(TAny* aThisPtr)
+/**
+Static callback function
+
+@param aThisPtr the pointer to the instance of this class that triggered the callback
+*/
+	{
+	CNetworkController* self = STATIC_CAST(CNetworkController*, aThisPtr);
+	self->SendImplicitConnectionNotification(self->iImplicitNotifyInfo, self->iImplicitNotifyEvent);
+	return KErrNone;
+	}
+
+void CNetworkController::SendImplicitConnectionNotification(const TDesC8& aConnectionInfo, MImplicitConnectionNotify::TEvent aEvent)
+/**
+Notify all registered observers about the implicit connection event
+
+@param aConnectionInfo a TSoIfConnectionInfo describing the implicit connection IapId and NetId
+@param aEvent either Up or Down
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::SendImplicitConnectionNotification()")); )
+
+	for(TInt i=0; i<iImplicitNotifyList.Count(); ++i)
+		{
+		iImplicitNotifyList[i]->ImplicitConnectionEvent(aConnectionInfo, aEvent);
+		}
+	}
+
+//
+//                                              //
+// Bearer Availability Checking                 //
+//                                              //
+//
+
+void CNetworkController::CheckBearerAvailability(TBool aIsReconnect)
+/**
+Check Bearer Availability
+
+@param aIsReconnect if this is a reconnection then any asynchronous requests are skipped in order to speed things up
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::CheckBearerAvailability()")); )
+
+	// ensure that the telephony bearer is in the array
+	__ASSERT_DEBUG(iBearers[KTelBearerPosition], NetConPanic(NetworkController::ENetConTelBearerMissing));
+
+	// ask the telephony bearer to start checking for availability
+	TBool ret = iBearers[KTelBearerPosition]->StartChecking(aIsReconnect);
+	__ASSERT_DEBUG(ret, NetConPanic(NetworkController::ENetConTelBearerAlreadyChecking));
+	(void)ret;  // remove warning in release builds
+	}
+
+void CNetworkController::CancelBearerAvailabilityCheck()
+/**
+CancelBearerAvailabilityCheck
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::CancelBearerAvailabilityCheck()")); )
+
+	// ensure that the telephony bearer is in the array
+	__ASSERT_DEBUG(iBearers[KTelBearerPosition], NetConPanic(NetworkController::ENetConTelBearerMissing));
+
+	iBearers[KTelBearerPosition]->StopChecking();
+	}
+
+/**
+   Construct a new database accessor
+   @returns the new database accessor
+*/
+CCommsDbAccess* CNetworkController::NewDatabaseL()
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::NewDatabaseL()")); )
+
+	CCommsDbAccess *database = CCommsDbAccess::NewL(ETrue);
+	ASSERT( database );
+	return database;
+	}
+
+
+/**
+   Construct a new dialog processor
+   @returns the new dialog processor
+*/
+CNetConDlgProcessor* CNetworkController::NewDialogProcessorL()
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::NewDialogProcessorL()")); )
+
+	return CNetConDlgProcessor::NewL();
+	}
+
+
+TInt CNetworkController::RequestSecondPhaseAvailability()
+/**
+Check Second Phase Bearer Availability - e.g. signal strength
+
+@returns KErrNone if the bearer availability is above the threshold stored in CommDB, otherwise KErrNetConInadequateSignalStrengh
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::RequestSecondPhaseAvailability()")); )
+
+	CBearerBase* const telBearer = iBearers[KTelBearerPosition];
+
+	// ensure that the telephony bearer is in the array
+	__ASSERT_DEBUG(telBearer, NetConPanic(NetworkController::ENetConTelBearerMissing));
+
+	// ask the telephony bearer to start checking for availability
+	TInt availability = telBearer->SecondPhaseAvailability();
+
+	// we have to tell the bearer to stop checking for availability here, otherwise
+	// subsequent availability requests will fail
+	// the logic is that every selection request triggers a *new* bearer availabilty
+	// check - in a one box device this could be optimised to a single check.
+	telBearer->StopChecking();
+	return availability;
+	}
+
+void CNetworkController::BearerStateChange(CBearerBase* aBearer)
+/**
+The bearer set available has changed - update the current
+request
+
+
+Implementation of MBearerObserver Interface
+
+@param aBearer the bearer who's availability has changed
+@note that this is quite a simple implementation
+of bearer availability checking because we only
+have a single bearer.  If further bearers are
+implemented then a 'bearer manager' class may
+be used to take the responsibility of retrieveing
+the availability of all bearers and then returing
+to the network controller
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::BearerStateChange()")); )
+
+	__ASSERT_DEBUG(iCurrentRequest, NetConPanic(NetworkController::ENetConNoCurrentRequest));
+
+	// fetch the available bearer set from the telephony bearer
+	TUint32 availableBearerSet(aBearer->AvailableBearerSet());
+
+	// the LAN bearer is assumed to be always available so mask it in
+	availableBearerSet |= (KCommDbBearerLAN|KCommDbBearerVirtual);
+
+	// update the current request
+	iCurrentRequest->SetAvailableBearers(availableBearerSet);
+	}
+
+CCommsDbAccess* CNetworkController::DbAccess()
+/** Provide a pointer to the CCommsDbAccess class to facilitate access to commdb
+@return CCommsDbAccess
+*/
+ 	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::DbAccess()")); )
+
+ 	ASSERT(iCurrentRequest);
+ 	ASSERT(iCurrentRequest->DbAccess());
+ 	return iCurrentRequest->DbAccess();
+ 	}
+
+//
+//                        //
+//  MNetConEnv Interface  //
+//                        //
+//
+
+const HBufC* CNetworkController::ImplicitConnectionAgentName() const
+/**
+Retrieve the name of the Agent that is used for implicit connection
+requests - i.e. connection startup from RSocket SendTo()/Connect() or
+RHostResolver GetByName()
+
+@returns an Agent name
+*/
+	{
+    LOG_DETAILED(
+        if (iImplicitConnectionAgentName)	    
+            NetConLog::Printf(_L("CNetworkController::ImplicitConnectionAgentName() %S"), iImplicitConnectionAgentName);
+        else
+            NetConLog::Printf(_L("CNetworkController::ImplicitConnectionAgentName() returns NULL"));
+        )
+
+	return iImplicitConnectionAgentName;
+	}
+
+const TConnPref& CNetworkController::ImplicitConnectionPrefs() const
+/**
+Retrieve the connection preferences associated with the current
+implicit connection
+
+@returns a TConnPref reference
+*/
+	{
+
+	return iImplicitConnectionPrefs;
+	}
+
+void CNetworkController::AddAgentToNetworkL(CNifAgentBase* aAgent, TUint32 aNetworkId)
+/**
+Create an association between an Agent and a Network ID.
+
+@param aAgent pointer to the Agent
+@param aNetworkId the CommDb ID of the Network
+*/
+	{
+	LOG_DETAILED( NetConLog::Printf(_L("CNetworkController::AddAgentToNetworkL()")); )
+	
+	// Is the network already available?
+	CNetwork* network = NULL;
+	TInt findErr = FindNetworkById(aNetworkId, network);
+
+	// ...if not create a new network
+	if(findErr!=KErrNone)
+		{
+		network=CNetwork::NewLC(aNetworkId, this);
+		AddNetworkL(network);
+		CleanupStack::Pop();  // network
+		}
+
+	// add this agent to the network.
+	network->AddAgentL(aAgent);
+
+	LOG( NetConLog::Printf(_L("\tAdded agent [0x%08x] to Network %d [0x%08x]"), aAgent, aNetworkId, network); )
+	}
+