networkcontrol/ipcprshim/src/shimclient.cpp
changeset 29 c0a997472b1c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkcontrol/ipcprshim/src/shimclient.cpp	Fri Jun 11 15:15:43 2010 +0300
@@ -0,0 +1,733 @@
+// 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:
+// This is part of an ECOM plug-in
+// 
+//
+
+#include <ss_std.h>
+#include "shimnifmansconn.h"
+#include "es_prot.h"
+
+
+/**
+@internalComponent
+*/
+const TUint KMicrosecondsInASecond = 1000000;
+const TInt KMaxTimerPeriod = KMaxTInt32/KMicrosecondsInASecond; //< max period of a CTimer using After()
+
+
+CSubConnectionLinkShimClient::CSubConnectionLinkShimClient(const CConnection& aConnection, CNifManSubConnectionShim& aSubConnectionShim) :
+	iConnection(aConnection), 
+	iSubConnectionShim(aSubConnectionShim),
+	iOutstandingProgressNotification(EFalse), 
+	iOutstandingDataSentNotification(EFalse), 
+	iOutstandingDataReceivedNotification(EFalse), 
+	iOutstandingSubConnectionActivity(EFalse) 
+/**
+*/
+	{
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tCSubConnectionLinkShimClient() created for id %d, iConnection %08x"), 
+							 this, aSubConnectionShim.Id(), &iConnection));
+	}
+
+CSubConnectionLinkShimClient::~CSubConnectionLinkShimClient()
+/**
+Complete all outstanding RMessages
+
+*/
+	{	
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\t~CSubConnectionLinkShimClient(), id %d, iSubConnectionShim %08x"), 
+				 this, iSubConnectionShim.Id(), this, &iSubConnectionShim));
+
+	if(iActivityTimer)
+		{
+		iActivityTimer->Cancel();
+		delete iActivityTimer;
+		iActivityTimer = NULL;
+		}
+
+	if(iOutstandingProgressNotification)
+		iOutstandingProgressNotificationMessage.Complete(KErrCancel);
+	if(iOutstandingDataSentNotification)
+		iOutstandingDataSentNotificationMessage.Complete(KErrCancel);
+	if(iOutstandingDataReceivedNotification)
+		iOutstandingDataReceivedNotificationMessage.Complete(KErrCancel);
+	if(iOutstandingSubConnectionActivity)
+		iOutstandingSubConnectionActivityMessage.Complete(KErrCancel);
+	if (iSubConnectionShim.DataTransferShim())
+		{
+		iSubConnectionShim.DataTransferShim()->DeRegisterClient(*this);
+		}
+	}
+
+TBool CSubConnectionLinkShimClient::Match(const CConnection& aConnection) const
+	{
+	return &iConnection == &aConnection;
+	}
+	
+TSubConnectionUniqueId CSubConnectionLinkShimClient::Id()
+	{
+	return iSubConnectionShim.Id();
+	}
+
+TInt CSubConnectionLinkShimClient::ReturnCode() const
+	{
+	return iReturnCode;
+	}
+	
+TInt CSubConnectionLinkShimClient::GetCurrentProgress(TNifProgress& aProgress)
+/**
+Return the current progress state
+
+@param aProgress On return, contains the current progress from the subconnection
+@return KErrNone if successful; otherwise one of the system-wide error codes
+*/
+	{	
+	aProgress = iCurrentProgress;
+	
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tGetCurrentProgress() => (%d, %d)"), 
+			    this, aProgress.iStage, aProgress.iError));
+	return KErrNone;
+	}
+
+TBool CSubConnectionLinkShimClient::StopL(const RMessage2& aMessage)
+	{	
+	TInt stopCode = 0;
+	RConnection::TConnStopType stopType = static_cast<RConnection::TConnStopType>(aMessage.Int1());
+	switch (stopType)
+		{
+		case RConnection::EStopNormal:
+			stopCode = KErrCancel;
+			break;
+		case RConnection::EStopAuthoritative:
+			stopCode = KErrConnectionTerminated;
+			break;
+		default:
+			stopCode = KErrCancel; // to remove compile warning
+			User::Leave(KErrArgument);
+		}
+
+	TInt ret = iSubConnectionShim.Provider().Stop(iSubConnectionShim.Id(), stopCode, &aMessage);
+	if (ret != KErrNone)
+		{
+		User::Leave(ret);
+		}
+	return ETrue;
+	}
+
+TBool CSubConnectionLinkShimClient::DataTransferredL(const RMessage2& aMessage)
+	{
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tDataTransferredL(), id %d"),
+				this, iSubConnectionShim.Id()));
+
+	TUint uplinkDataVolume;
+	TUint downlinkDataVolume;
+
+	TInt ret = iSubConnectionShim.DataTransferShim()->DataTransferred(uplinkDataVolume, downlinkDataVolume);
+
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tDataTransferredL(), ret %d, uplink %d, downlink %d"),
+			    this, ret, uplinkDataVolume, downlinkDataVolume));
+
+	if (KErrNone == ret)
+		{
+		TPckg<TUint> uplinkDataVolumePckg(uplinkDataVolume);
+		TPckg<TUint> downlinkDataVolumePckg(downlinkDataVolume);
+
+		aMessage.WriteL(1, uplinkDataVolumePckg);
+		aMessage.WriteL(2, downlinkDataVolumePckg);
+		}
+	SetReturnCode(ret);
+	return ETrue;
+	}
+
+TBool CSubConnectionLinkShimClient::DataTransferredCancel(const RMessage2& /*aMessage*/)
+	{
+	return ETrue;		
+	}
+
+TBool CSubConnectionLinkShimClient::RequestSubConnectionProgressNotificationL(const RMessage2& aMessage)
+/**
+Request from client for notification of new progress
+
+@pre No outstanding request for data sent notifications for this subconnection on this RConnection
+@param aMessage The client message
+@return ETrue if the client message is to be completed immediately
+@leave leaves with KErrInUse if there is already an outstanding RMessage for progress notification
+*/
+	{
+	if(iOutstandingProgressNotification)
+		User::Leave(KErrInUse);
+
+	TInt clientRequestedProgress = 0;
+	clientRequestedProgress = static_cast<TUint>(aMessage.Int2());
+	// if	- the last progress we sent to the client differs from the current one
+	// and	- the current progress is the same as the client requested progress OR 
+	//        the client has no requested progress...
+	if(iLastProgressToClient!=iCurrentProgress.iStage &&
+		(iCurrentProgress.iStage == clientRequestedProgress || clientRequestedProgress==0))
+		{		
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tRequestSubConnectionProgressNotificationL() returning progress (%d, %d)"), 
+							 this, iCurrentProgress.iStage, iCurrentProgress.iError));
+
+		// ...send the current progress back
+		TPckg<TNifProgress> prog(iCurrentProgress);
+		aMessage.WriteL(1, prog);
+		return ETrue;
+		}
+	else	// store the client message until the next progress value arrives
+		{
+		//__FLOG_STATIC1(_L("ESock: "), _L("CSubConnectionLinkShimClient"), 
+		// _L("[id: %d]: client requested progress notification; storing client message for later completion"), 
+		// iSubConnectionsUniqueId);
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tRequestSubConnectionProgressNotificationL() storing client message for later completion"), this));
+
+		iClientRequestedProgress = clientRequestedProgress;	// may be 0
+		iOutstandingProgressNotificationMessage = aMessage;
+		iOutstandingProgressNotification = ETrue;
+		return EFalse;
+		}
+	}
+
+TBool CSubConnectionLinkShimClient::CancelSubConnectionProgressNotification(const RMessage2& /*aMessage*/)
+/**
+Complete outstanding progress notification RMessage
+
+@param aMessage The client message
+@return ETrue if the client message is to be completed immediately
+*/
+	{
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tCancelSubConnectionProgressNotification(), id %d, iSubConnectionShim %08x"), 
+						 iSubConnectionShim.Id(), this));
+
+	if(iOutstandingProgressNotification)
+		{
+		iOutstandingProgressNotificationMessage.Complete(KErrCancel);
+		iOutstandingProgressNotification = EFalse;
+		}
+	return ETrue;
+	}
+
+TBool CSubConnectionLinkShimClient::DataSentNotificationRequestL(const RMessage2& aMessage)
+/**
+Request notification when the specified (absolute or relative) volume of data has been sent
+
+@pre No outstanding request for data sent notifications for this subconnection on this RConnection
+@param aMessage The client message
+@return ETrue if the client message is to be completed immeadiately
+@leave leaves with KErrInUse if there is already an outstanding RMessage for data sent notification
+*/
+	{
+	if(iOutstandingDataSentNotification)
+		User::Leave(KErrInUse);
+
+	TUint requestedUplinkGranularity = static_cast<TUint>(aMessage.Int1());
+	if(requestedUplinkGranularity)	// the client is working in relative mode
+		{
+		iRemainingUplinkGranularity = requestedUplinkGranularity;
+		iDataSentNotificationsInAbsoluteMode = EFalse;
+
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tDataSentNotificationRequestL(), id %d (relative mode: %d bytes)"), 
+							 this, iSubConnectionShim.Id(), iRemainingUplinkGranularity));
+		}
+	else							// the client is working in absolute mode
+		{
+		TPckg<TUint> iUplinkVolumeBuf(iUplinkDataNotificationVolume);
+		aMessage.ReadL(2, iUplinkVolumeBuf);
+		iDataSentNotificationsInAbsoluteMode = ETrue;
+
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tDataSentNotificationRequestL() id %d (absolute mode: %d bytes)"), 
+							 this, iSubConnectionShim.Id(), iUplinkDataNotificationVolume));
+
+		if(iUplinkDataNotificationVolume >= iUplinkDataVolume)	// we've already sent this amount of data
+			{
+			__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tDataSentNotificationRequestL() id %d (completed immediately"), 
+								 this, iSubConnectionShim.Id()));
+			return ETrue;
+			}
+		}
+	
+	iOutstandingDataSentNotificationMessage = aMessage;
+	iOutstandingDataSentNotification = ETrue;
+	
+	iSubConnectionShim.DataTransferShim()->DataSentNotificationRequest(requestedUplinkGranularity, iUplinkDataNotificationVolume);
+
+	return EFalse;
+	}
+
+TBool CSubConnectionLinkShimClient::DataSentNotificationCancel(const RMessage2& /*aMessage*/)
+/**
+Complete outstanding data sent notification RMessage
+
+@param aMessage The client message
+@return ETrue if the client message is to be completed immediately
+*/
+	{
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tDataSentNotificationCancel() id %d"), 
+				 this, iSubConnectionShim.Id()));
+	iSubConnectionShim.DataTransferShim()->DataSentNotificationCancel();
+
+	if(iOutstandingDataSentNotification)
+		{
+		iOutstandingDataSentNotificationMessage.Complete(KErrCancel);
+		iOutstandingDataSentNotification= EFalse;
+		}
+	return ETrue;
+	}
+
+TBool CSubConnectionLinkShimClient::DataReceivedNotificationRequestL(const RMessage2& aMessage)
+/**
+Request notification when the specified (absolute or relative) volume of data has been sent
+
+@pre No outstanding request for data sent notifications for this subconnection on this RConnection
+@param aMessage The client message
+@return ETrue if the client message is to be completed immediately
+@leave leaves with KErrInUse if there is already an outstanding RMessage for data received notification
+*/
+	{
+
+	if(iOutstandingDataReceivedNotification)
+		User::Leave(KErrInUse);
+	
+	TUint requestedDownlinkGranularity = static_cast<TUint>(aMessage.Int1());
+	if(requestedDownlinkGranularity)	// the client is working in relative mode
+		{
+		iRemainingDownlinkGranularity = requestedDownlinkGranularity;
+		iDataReceivedNotificationsInAbsoluteMode = EFalse;
+		
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tDataReceivedNotificationRequestL() id %d (relative mode: %d bytes)"), 
+					 this, iSubConnectionShim.Id(), iRemainingDownlinkGranularity));
+		}
+	else							// the client is working in absolute mode
+		{
+		TPckg<TUint> iDownlinkVolumeBuf(iDownlinkDataNotificationVolume);
+		aMessage.ReadL(2, iDownlinkVolumeBuf);
+		iDataReceivedNotificationsInAbsoluteMode = ETrue;
+
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tDataReceivedNotificationRequestL() id %d (absolute mode: %d bytes)"), 
+							 this, iSubConnectionShim.Id(), iDownlinkDataNotificationVolume));
+		
+		if(iDownlinkDataNotificationVolume >= iDownlinkDataVolume)	// we've already received this amount of data
+			{
+			__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tDataReceivedNotificationRequestL() id %d(completed immediately)"), 
+						 this, iSubConnectionShim.Id()));
+			return ETrue;
+			}
+		}
+
+	iOutstandingDataReceivedNotificationMessage = aMessage;
+	iOutstandingDataReceivedNotification = ETrue;
+
+	iSubConnectionShim.DataTransferShim()->DataReceivedNotificationRequest(requestedDownlinkGranularity, iDownlinkDataNotificationVolume);
+
+	return EFalse;
+	}
+
+TBool CSubConnectionLinkShimClient::DataReceivedNotificationCancel(const RMessage2& /*aMessage*/)
+/**
+Complete outstanding data received notification RMessage
+
+@param aMessage The client message
+@return ETrue if the client message is to be completed immediately
+*/
+	{
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tDataReceivedNotificationCancel() id %d"), 
+						 this, iSubConnectionShim.Id()));
+
+	iSubConnectionShim.DataTransferShim()->DataReceivedNotificationCancel();
+
+	if(iOutstandingDataReceivedNotification)
+		{
+		iOutstandingDataReceivedNotificationMessage.Complete(KErrCancel);
+		iOutstandingDataReceivedNotification = EFalse;
+		}
+	return ETrue;
+	}
+
+TBool CSubConnectionLinkShimClient::IsSubConnectionActiveRequestL(const RMessage2& aMessage)
+/**
+Indicate whether the subconnection is active or not
+
+@note Checks at a period defined in the RMessage
+@note Only returns when the state varies from that provided by the client
+@param aMessage The client message
+@return ETrue if the client message is to be completed immediately
+*/
+	{
+	if(iOutstandingSubConnectionActivity)
+		User::Leave(KErrInUse);
+
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tIsSubConnectionActiveRequestL() id %d"), 
+				this, iSubConnectionShim.Id()));
+
+	// Create the activity timer if it doesn't already exist (from a previous request)
+	if(!iActivityTimer)
+		{
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tIsSubConnectionActiveRequestL() id %d - creating timer"), 
+					this, iSubConnectionShim.Id()));
+
+		iActivityTimer = CActivityTimer::NewL(this, KActivityTimerPriority);
+		}
+
+	TPckg<TBool> subConnectionActiveBuf(iClientBelievesSubConnectionActive);
+	aMessage.ReadL(2, subConnectionActiveBuf);
+
+	iSubConnectionShim.DataTransferShim()->DataTransferred(iPreviousUplinkDataVolume, iPreviousDownlinkDataVolume);	
+
+	// get clients request timer period and check validity
+	TInt timeInSeconds = static_cast<TUint>(aMessage.Int1());
+	if(timeInSeconds > KMaxTimerPeriod) // secs; underlying CTimer limitation
+		{
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tIsSubConnectionActiveRequestL() id %d - rejecting timer request (%d secs)"), 
+							 this, iSubConnectionShim.Id(), timeInSeconds));
+		
+		SetReturnCode(KErrArgument);
+		return ETrue;
+		}
+
+	// store in microsecs
+	iRequestedClientTimerPeriod = timeInSeconds * KMicrosecondsInASecond;
+	
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tIsSubConnectionActiveRequestL() id %d, iClientBelievesSubConnectionActive %d, iRequestedClientTimerPeriod %d - Starting timer."), 
+						 this, iSubConnectionShim.Id(), iClientBelievesSubConnectionActive, iRequestedClientTimerPeriod));
+
+	iOutstandingSubConnectionActivity = ETrue;
+	iOutstandingSubConnectionActivityMessage = aMessage;
+
+	iActivityTimer->After(iRequestedClientTimerPeriod);
+	return EFalse;
+	}
+
+TBool CSubConnectionLinkShimClient::IsSubConnectionActiveCancel(const RMessage2& /*aMessage*/)
+	{
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tIsSubConnectionActiveCancel() id %d, connection %08x"), 
+						 this, iSubConnectionShim.Id(), &iConnection));
+
+	if(iOutstandingSubConnectionActivity)
+		{
+		iActivityTimer->Cancel();
+		ASSERT(iOutstandingSubConnectionActivity); // assert that the timer cancelled rather than completing
+		iOutstandingSubConnectionActivityMessage.Complete(KErrCancel);
+		iOutstandingSubConnectionActivity = EFalse;
+		}
+	return ETrue;
+	}
+	
+TInt CSubConnectionLinkShimClient::GetSubConnectionInfo(const RMessage2& aMessage)
+	{
+	TUint index = static_cast<TUint>(aMessage.Int0());
+	
+	TInt result = KErrNone;
+	TRAP(result,
+
+   	// Find the size of the clients descriptor
+   	TInt sizeOfSubConnInfo = aMessage.GetDesLengthL(1);
+   
+   	// Create an appropriately sized descriptor server-side
+   	HBufC8* subConnectionInfo;
+   	subConnectionInfo = HBufC8::NewL(sizeOfSubConnInfo);
+   	CleanupStack::PushL (subConnectionInfo);
+   	
+   	TPtr8 subConnInfoPtr(subConnectionInfo->Des());
+
+   	// and read the client data across
+      aMessage.ReadL(1, subConnInfoPtr);
+
+   	// Pass it down to the connection provider using the appropriate call
+     	if(index==KUseEmbeddedUniqueId)
+   		{
+   		result = iSubConnectionShim.Provider().GetSubConnectionInfo(subConnInfoPtr);
+   		}
+   	else
+   		{
+   		result = iSubConnectionShim.Provider().GetSubConnectionInfo(index, subConnInfoPtr);
+   		}
+   
+   	if (KErrNone == result)
+   		{
+   		// Write result back into client's address space
+   		aMessage.WriteL(1, subConnInfoPtr);
+   		}
+   		
+   	CleanupStack::PopAndDestroy (subConnectionInfo);
+      );  // END TRAP
+      
+	SetReturnCode(result);
+	return ETrue;
+	}
+	
+void CSubConnectionLinkShimClient::ProgressNotification(TInt aStage, TInt aError, const TDesC8& /*aInfo*/)
+/**
+Notification of new progress stage from nif/agent via Nifman and CInterface
+
+@param aStage The progress stage that has been reached
+@param aError Any errors that have occured
+@param aInfo No idea what this is, it's inserted by CInterface and is currently null
+*/
+	{
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tProgressNotification(%d, %d) id %d"), 
+						this, aStage, aError, iSubConnectionShim.Id()));
+
+	iCurrentProgress.iStage = aStage;
+	iCurrentProgress.iError = aError;
+
+	if(iOutstandingProgressNotification)
+		{
+		if(iLastProgressToClient!=iCurrentProgress.iStage && /* we could assume this since we've probably just received a new progress value */
+			(iCurrentProgress.iStage == iClientRequestedProgress || iClientRequestedProgress==0))
+			{
+			TPckg<TNifProgress> prog(iCurrentProgress);
+			TInt err= iOutstandingProgressNotificationMessage.Write(1, prog);
+			iOutstandingProgressNotificationMessage.Complete(err);
+			iOutstandingProgressNotification= EFalse;
+			}
+		}
+	}
+
+TInt CSubConnectionLinkShimClient::NotifyDataSent(TUint aUplinkVolume, TUint aCurrentGranularity)
+/**
+Upcall from connection provider, via MConnDataTransferNotify. Update the sent bytes count, and if necessary
+complete any outstanding RMessages
+
+@param aUplinkVolume The total number of bytes sent on this subconnection
+@note Upcall from CInterface via CConnection
+*/
+	{	
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tNotifyDataSent(aUplinkVolume %d, aCurrentGranularity %d) id %d"), 
+						 this, aUplinkVolume, aCurrentGranularity, iSubConnectionShim.Id()));
+
+	iUplinkDataVolume = aUplinkVolume;
+
+	TBool completeMessage = EFalse;
+
+	if(iOutstandingDataSentNotification)
+		{
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - outstanding client request"), 
+							 this, iSubConnectionShim.Id()));
+		switch(iDataSentNotificationsInAbsoluteMode)
+			{
+			case ETrue:
+				__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - %d bytes remaining to be sent before client completion (absolute mode)"), 
+									 this, iSubConnectionShim.Id(), (iUplinkDataNotificationVolume - iUplinkDataVolume)));
+				
+				if (iUplinkDataVolume >= iUplinkDataNotificationVolume)
+					{
+					completeMessage = ETrue;
+					}
+				break;
+				
+			case EFalse:	// in relative mode
+				iRemainingUplinkGranularity -= aCurrentGranularity;
+				
+				__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - %d bytes remaining to be sent before client completion (relative mode)."), 
+									 this, iSubConnectionShim.Id(), iRemainingUplinkGranularity));
+				
+				if(iRemainingUplinkGranularity <= 0)
+					{
+					completeMessage = ETrue;
+					}
+				break;
+
+			default:
+				break;
+			}
+		}
+
+	if(completeMessage)
+		{
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - completing client request."), 
+							 iSubConnectionShim.Id(), this));
+		TPckg<TUint> iUplinkDataVolumePckg(iUplinkDataVolume);
+		TInt ret= iOutstandingDataSentNotificationMessage.Write(2, iUplinkDataVolumePckg);
+		iOutstandingDataSentNotificationMessage.Complete(ret);
+		iOutstandingDataSentNotification= EFalse;
+		}
+	return KErrNone;
+	}
+
+TInt CSubConnectionLinkShimClient::NotifyDataReceived(TUint aDownlinkVolume, TUint aCurrentGranularity)
+/**
+Update the received bytes count, and if necessary complete any outstanding RMessages
+
+@param aDownlinkVolume The total number of bytes sent on this subconnection
+@param aCurrentGranularity The currently set granularity of notifications from the CInterface object
+@note Upcall from CInterface via CConnection
+*/
+	{
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tNotifyDataReceived(aDownlinkVolume %d, aCurrentGranularity %d)"), 
+						 this, iSubConnectionShim.Id(), aDownlinkVolume, aCurrentGranularity));
+
+	iDownlinkDataVolume = aDownlinkVolume;
+
+	TBool completeMessage = EFalse;
+
+	if(iOutstandingDataReceivedNotification)
+		{
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - outstanding client request"), 
+							 this, iSubConnectionShim.Id()));
+		switch(iDataReceivedNotificationsInAbsoluteMode)
+			{
+			case ETrue:
+				__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - %d bytes remaining to be sent before client completion (absolute mode)."), 
+									 this, iSubConnectionShim.Id(), (iDownlinkDataNotificationVolume - iDownlinkDataVolume)));
+
+				if (iDownlinkDataVolume >= iDownlinkDataNotificationVolume)
+					{
+					completeMessage = ETrue;
+					}
+				break;
+
+			case EFalse:	// in relative mode
+				iRemainingDownlinkGranularity -= aCurrentGranularity;
+		
+				__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - %d bytes remaining to be sent before client completion (relative mode)."), 
+									 this, iSubConnectionShim.Id(), iRemainingDownlinkGranularity));
+
+				if(iRemainingDownlinkGranularity <= 0)
+					{
+					completeMessage = ETrue;
+					}
+				break;
+
+			default:
+				break;
+			}
+		}
+
+	if(completeMessage)
+		{
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - completing client request."), 
+					 this, &iSubConnectionShim));
+		TPckg<TUint> iDownlinkDataVolumePckg(iDownlinkDataVolume);
+		TInt ret= iOutstandingDataReceivedNotificationMessage.Write(2, iDownlinkDataVolumePckg);
+		iOutstandingDataReceivedNotificationMessage.Complete(ret);
+		iOutstandingDataReceivedNotification= EFalse;
+		}
+	return KErrNone;
+	}
+
+TInt CSubConnectionLinkShimClient::NotifyDataTransferred(const TUint aUplinkVolume, const TUint aDownlinkVolume)
+/**
+Upcall from CConnection, indicating that it has performed a DataTransferred request and notifying us of the results
+
+@param aUplinkVolume The total amount of data sent so far on this subconnection
+@param aDownlinkVolume The total amount of data received so far on this subconnection
+*/
+	{
+	// Update internal data counters, complete any outstanding RMessages if appropriate
+	// No granularities because we don't know what they are, and because we're taking the 
+	// opportunity of using the client's call to update our counters, ie. it's not an 
+	// actual notification
+	NotifyDataSent(aUplinkVolume, 0);
+	NotifyDataReceived(aDownlinkVolume, 0);
+	return KErrNone;
+	}
+
+void CSubConnectionLinkShimClient::CheckSubConnectionActivity()
+/**
+Check for activity on the subconnection since the last call (to IsSubConnectionActiveRequest() )
+
+*/
+	{
+	__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tCheckSubConnectionActivity() id %d"), 
+						 this, iSubConnectionShim.Id()));
+
+	ASSERT(iOutstandingSubConnectionActivity);
+
+	TUint newUplinkDataVolume;
+	TUint newDownlinkDataVolume;
+	
+	iSubConnectionShim.DataTransferShim()->DataTransferred(newUplinkDataVolume, newDownlinkDataVolume);
+
+	TBool dataTransferred = (newUplinkDataVolume!=iPreviousUplinkDataVolume) || 
+		                    (newDownlinkDataVolume!=iPreviousDownlinkDataVolume);
+
+	// If the data transferred volumes haven't change but the client thinks the connection is active...
+	if(iClientBelievesSubConnectionActive)
+		{
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - client believes subconnection active"), 
+							 this, iSubConnectionShim.Id()));
+
+		if(dataTransferred)	// ...and it is, so just start another timer cycle
+			{
+			__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - ...and it is.  Restart timer for another cycle."), 
+								 this, iSubConnectionShim.Id()));
+
+			iPreviousUplinkDataVolume = newUplinkDataVolume;
+			iPreviousDownlinkDataVolume = newDownlinkDataVolume;
+			iActivityTimer->After(iRequestedClientTimerPeriod);
+			}
+		else				// ...tell them it's not
+			{
+			__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - ...and it isn't.  Notify client."), 
+								 this, iSubConnectionShim.Id()));
+
+			TPckg<TBool> subConnectionActiveBuf(dataTransferred);
+			TInt ret= iOutstandingSubConnectionActivityMessage.Write(2, subConnectionActiveBuf);
+			iOutstandingSubConnectionActivityMessage.Complete(ret);
+			iOutstandingSubConnectionActivity = EFalse;
+			}
+		}
+	else					// client believes subconnection is idle...
+		{
+		__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - client believes subconnection idle..."), 
+							 this, iSubConnectionShim.Id()));
+
+		if(dataTransferred)
+			{
+			__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - ...and it isn't.  Notify client."), 
+								 this, iSubConnectionShim.Id()));
+
+			TPckg<TBool> subConnectionActiveBuf(dataTransferred);
+			TInt ret= iOutstandingSubConnectionActivityMessage.Write(2, subConnectionActiveBuf);
+			iOutstandingSubConnectionActivityMessage.Complete(ret);
+			iOutstandingSubConnectionActivity = EFalse;
+			}
+		else				// ...and it is, so just start another timer cycle
+			{
+			__CFLOG_VAR((KShimScprTag, KShimScprClientTag, _L8("CSubConnectionLinkShimClient %08x:\tid %d - ...and it is.  Restart timer for another cycle."), 
+								 this, iSubConnectionShim.Id()));
+
+			iPreviousUplinkDataVolume = newUplinkDataVolume;
+			iPreviousDownlinkDataVolume = newDownlinkDataVolume;
+			iActivityTimer->After(iRequestedClientTimerPeriod);
+			}
+		}
+	}
+
+CSubConnectionLinkShimClient::CActivityTimer* CSubConnectionLinkShimClient::CActivityTimer::NewL(CSubConnectionLinkShimClient* aOwner, TInt aPriority)
+/**
+Construct a new CActivityTimer()
+
+@param aOwner The owning CSubConnectionLinkShimClient (on which we call methods upon timer completion)
+@param aPriority The priority of the active object underlying this timer object
+@return A pointer to the newly constructed CActivityTimer object
+*/
+	{
+	CSubConnectionLinkShimClient::CActivityTimer* newActivityTimer = 
+		new(ELeave) CSubConnectionLinkShimClient::CActivityTimer(aOwner, aPriority);
+
+	CleanupStack::PushL(newActivityTimer);
+	newActivityTimer->ConstructL();
+	CleanupStack::Pop(newActivityTimer);
+	return newActivityTimer;
+	}
+
+void CSubConnectionLinkShimClient::CActivityTimer::RunL()
+/**
+Call the owning object's check activity method
+
+*/
+	{ 
+	iOwner->CheckSubConnectionActivity(); 
+	}