datacommsserver/esockserver/ssock/ss_DataMonitoringProvider.cpp
changeset 0 dfb7c4ff071f
child 21 4ccf8e394726
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/esockserver/ssock/ss_DataMonitoringProvider.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,540 @@
+// Copyright (c) 2006-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:
+// DataMonitoringProvider.cpp
+// 
+//
+
+/**
+ @file
+ @internalComponent 
+*/
+
+#include <comms-infras/ss_nodemessages.h>
+#include "ss_datamonitoringprovider.h"
+
+#include <comms-infras/ss_log.h>
+
+using namespace ESock;
+using namespace Messages;
+using namespace MeshMachine;
+
+EXPORT_C ADataMonitoringProvider::ADataMonitoringProvider()
+	{
+	}
+
+EXPORT_C void ADataMonitoringProvider::ConstructL()
+	{
+	InsertWrapMarkerL(EReceived);
+	SetNextNotificationThreshold(EReceived);
+	InsertWrapMarkerL(ESent);
+	SetNextNotificationThreshold(ESent);
+	}
+
+EXPORT_C ADataMonitoringProvider::~ADataMonitoringProvider()
+	{
+	TUint requestIdx;
+	TUint requestCount;
+	TNotificationRequest* notificationRequest;
+
+	// Cancel any outstanding received notification requests
+	requestCount = iReceivedNotificationRequests.Count();
+	for(requestIdx=0;requestIdx<requestCount;requestIdx++)
+		{
+		notificationRequest = iReceivedNotificationRequests[requestIdx];		
+		if(!notificationRequest->Cancelled()) 
+			{
+			CDataMonitoringResponder::CancelRequest(notificationRequest->Responder());
+			}
+		}
+	iReceivedNotificationRequests.ResetAndDestroy();
+
+	// Cancel any outstanding sent notification requests
+	requestCount = iSentNotificationRequests.Count();
+	for(requestIdx=0;requestIdx<requestCount;requestIdx++)
+		{
+		notificationRequest = iSentNotificationRequests[requestIdx];
+		if(!notificationRequest->Cancelled())
+			{
+			CDataMonitoringResponder::CancelRequest(notificationRequest->Responder());
+			}
+		}
+	iSentNotificationRequests.ResetAndDestroy();
+	}
+
+/**
+	Responds to client request for immediate notification of the amount of data transferred.
+	@param aResponder The IPC responder for completing the client request
+	@param aClientId Not used
+*/
+EXPORT_C void ADataMonitoringProvider::RequestDataTransferred(CDataMonitoringResponder*& aResponder, TSubSessionUniqueId /* aClientId */)
+	{
+	CDataMonitoringResponder::DataTransferred(aResponder, iDataVolumes.iReceivedBytes, iDataVolumes.iSentBytes);
+	}
+
+/**
+	Cancels an outstanding client request for immediate notification of the amount of data transferred.
+	@param aClientId Not used
+	@note Method has no implementation as completion of request is immediate.
+	@see ADataMonitoringProvider::RequestDataTransferred
+*/
+EXPORT_C void ADataMonitoringProvider::CancelDataTransferredRequest(TSubSessionUniqueId /* aClientId */)
+	{
+	// Nothing to do
+	}
+
+/**
+	Responds to client request for notification of a particular volume of data having been
+	received.
+	@param aResponder The IPC responder for completing the client request
+	@param aDelta An offset from the current volume transferred at which to notify the client
+	@param aReceivedBytes An absolute data volume at which to notify the client
+	@param aClientId Id of the requesting client
+	@note Only one of the parameters aDelta and aReceivedBytes should be set for a given call
+		  to this method
+*/
+EXPORT_C void ADataMonitoringProvider::RequestDataReceivedNotification(CDataMonitoringResponder*& aResponder, TUint32 aDelta, TUint32 aReceivedBytes, TSubSessionUniqueId aClientId)
+	{	
+	TNotificationRequest* notificationRequest = new TNotificationRequest(aResponder, aClientId);
+	if (!notificationRequest)
+		{
+		CDataMonitoringResponder::Error(aResponder, KErrNoMemory);
+		return;
+		}
+
+	// Ensure this client has not registered before or if it has, any outstanding requests are
+	// marked as cancelled.
+	TInt requestIdx = iReceivedNotificationRequests.Find(notificationRequest, TIdentityRelation<TNotificationRequest>(TNotificationRequest::CompareClientIds));
+	if(requestIdx != KErrNotFound && !iReceivedNotificationRequests[requestIdx]->Cancelled())
+		{
+		delete notificationRequest;
+		CDataMonitoringResponder::Error(aResponder, KErrInUse);
+		return;
+		}
+	
+	if(aDelta)
+		{ 	// If the delta was set then set the threshold from that and the current received data volume
+		notificationRequest->SetThresholdFromDelta(iDataVolumes.iReceivedBytes, aDelta);
+		}
+	else
+		{	// Otherwise, we were given an absolute value for the threshold
+		if(iDataVolumes.iReceivedBytes >= aReceivedBytes) 
+			{	// If the required threshold has already been reached then send immediate notification
+			delete notificationRequest;
+			CDataMonitoringResponder::DataReceivedNotification(aResponder, iDataVolumes.iReceivedBytes);
+			return;
+			}
+		else
+			{
+			notificationRequest->SetThreshold(aReceivedBytes);
+			}
+		}
+
+	TInt error = InsertNotificationRequest(notificationRequest, EReceived);
+	if (error!=KErrNone)
+		{
+		delete notificationRequest;	
+		CDataMonitoringResponder::Error(aResponder, error);
+		return;
+		}
+
+	SetNextNotificationThreshold(EReceived);
+	}
+
+/**
+	Cancels an outstanding request for data received notification.
+	
+	@param aClientId Id of the requesting client
+*/
+EXPORT_C void ADataMonitoringProvider::CancelDataReceivedNotificationRequest(TSubSessionUniqueId aClientId)
+	{
+	// Set up an exemplar request using the specified client ID
+	TNotificationRequest exemplarRequest(NULL, aClientId);
+	
+	// Locate the request matching the specified client ID
+	TInt requestIdx = iReceivedNotificationRequests.Find(&exemplarRequest, TIdentityRelation<TNotificationRequest>(TNotificationRequest::CompareClientIds));	
+	if(requestIdx != KErrNotFound && !iReceivedNotificationRequests[requestIdx]->Cancelled())
+		{
+		TNotificationRequest* notificationRequest = iReceivedNotificationRequests[requestIdx];
+		
+		// Cancel it and complete the client
+		notificationRequest->SetCancelled();
+		CDataMonitoringResponder::CancelRequest(notificationRequest->Responder());
+		}
+	}
+
+/**
+
+*/
+EXPORT_C void ADataMonitoringProvider::RequestDataSentNotification(CDataMonitoringResponder*& aResponder, TUint32 aDelta, TUint32 aSentBytes, TSubSessionUniqueId aClientId)
+	{	
+	TNotificationRequest* notificationRequest = new TNotificationRequest(aResponder, aClientId);
+	if (!notificationRequest)
+		{
+		CDataMonitoringResponder::Error(aResponder, KErrNoMemory);
+		return;
+		}
+	
+	// Ensure this client has not registered before or if it has, any outstanding requests are
+	// marked as cancelled.
+	TInt requestIdx = iSentNotificationRequests.Find(notificationRequest, TIdentityRelation<TNotificationRequest>(TNotificationRequest::CompareClientIds));
+	if(requestIdx != KErrNotFound && !iSentNotificationRequests[requestIdx]->Cancelled())
+		{
+		delete notificationRequest;
+		CDataMonitoringResponder::Error(aResponder, KErrInUse);
+		return;
+		}
+		
+	if(aDelta)
+		{ 	// If the delta was set then set the threshold from that and the current sent data volume
+		notificationRequest->SetThresholdFromDelta(iDataVolumes.iSentBytes, aDelta);
+		}
+	else
+		{	// Otherwise, we were given an absolute value for the threshold
+		if(iDataVolumes.iSentBytes >= aSentBytes)
+			{	// If the required threshold has already been reached then send immediate notification
+			delete notificationRequest;
+			CDataMonitoringResponder::DataSentNotification(aResponder, iDataVolumes.iSentBytes);
+			return;
+			}
+		else
+			{
+			notificationRequest->SetThreshold(aSentBytes);
+			}
+		}
+
+	TInt error = InsertNotificationRequest(notificationRequest, ESent);
+	if (error!=KErrNone)
+		{
+		delete notificationRequest;	
+		CDataMonitoringResponder::Error(aResponder, error);
+		return;
+		}
+
+	SetNextNotificationThreshold(ESent);
+	}
+
+/**
+	Cancels an outstanding request for data sent notification.
+	
+	@param aClientId Client id of the request to be cancelled
+*/
+EXPORT_C void ADataMonitoringProvider::CancelDataSentNotificationRequest(TSubSessionUniqueId aClientId)
+	{
+	// Set up an exemplar request using the specified client id
+	TNotificationRequest exemplarRequest(NULL, aClientId);
+	
+	// Locate the request matching the specified client id
+	TInt requestIdx = iSentNotificationRequests.Find(&exemplarRequest, TIdentityRelation<TNotificationRequest>(TNotificationRequest::CompareClientIds));
+	if(requestIdx != KErrNotFound && !iSentNotificationRequests[requestIdx]->Cancelled())
+		{
+		TNotificationRequest* notificationRequest = iSentNotificationRequests[requestIdx];
+		
+		// Cancel it and complete the client
+		notificationRequest->SetCancelled();
+		CDataMonitoringResponder::CancelRequest(notificationRequest->Responder());
+		}
+	}
+
+/**
+	Call from data to control plane to indicate the received data volume notification
+	threshold has been reached.
+	
+	@param aNotificationValue The volume of data received
+*/
+EXPORT_C void ADataMonitoringProvider::DataReceivedNotificationL(TUint32 aNotificationValue)
+	{
+	TNotificationRequest* request;
+	
+	// Complete the first request in the array immediately and loop for any
+	// additional same value thresholds in the list.
+	while((iReceivedNotificationRequests.Count() > 0) && 
+		  (aNotificationValue >= iReceivedNotificationRequests[0]->Threshold()))
+		{
+		request = iReceivedNotificationRequests[0];
+		if(!request->Cancelled())
+			{	// Only complete if the request wasn't cancelled
+			CDataMonitoringResponder::DataReceivedNotification(request->Responder(), aNotificationValue);
+			}
+		iReceivedNotificationRequests.Remove(0);
+		delete request;
+		}
+
+	// If we've completed a wrap marker, we need to do a little housekeeping
+	if(aNotificationValue == KMaxTUint32) 
+		{	
+		TInt requestCount = iReceivedNotificationRequests.Count();
+		if(requestCount > 0)
+			{
+			// The remaining requests had been marked wrapped.  Now we've
+			// completed the wrap marker they need to be 'unmarked' to allow
+			// new wrapped requests to be positioned correctly in the request array
+			for(TUint requestIdx=0;requestIdx<requestCount;requestIdx++)
+				{
+				iReceivedNotificationRequests[requestIdx]->SetWrapped(EFalse);
+				}
+			}
+			InsertWrapMarkerL(EReceived);
+		}
+	SetNextNotificationThreshold(EReceived);
+	}
+	
+/**
+	Call from data to control plane to indicate the sent data volume notification
+	threshold has been reached.
+	
+	@param aNotificationValue The volume of data received
+*/
+EXPORT_C void ADataMonitoringProvider::DataSentNotificationL(TUint32 aNotificationValue)
+	{
+	TNotificationRequest* request;
+	
+	// Complete the first request in the array immediately and loop for any
+	// additional same value thresholds in the list.
+	while((iSentNotificationRequests.Count() > 0) && 
+		  (aNotificationValue >= iSentNotificationRequests[0]->Threshold()))
+		{
+		request = iSentNotificationRequests[0];
+		if(!request->Cancelled())
+			{	// Only complete if the request wasn't cancelled
+			CDataMonitoringResponder::DataSentNotification(request->Responder(), aNotificationValue);
+			}
+		iSentNotificationRequests.Remove(0);
+		delete request;
+		}
+
+	// If we've completed a wrap marker, we need to do a little housekeeping
+	if(aNotificationValue == KMaxTUint32) 
+		{	
+		TInt requestCount = iSentNotificationRequests.Count();
+		if(requestCount > 0)
+			{
+			// The remaining requests had been marked wrapped.  Now we've
+			// completed the wrap marker they need to be 'unmarked' to allow
+			// new wrapped requests to be positioned correctly in the request array
+			for(TUint requestIdx=0;requestIdx<requestCount;requestIdx++)
+				{
+				iSentNotificationRequests[requestIdx]->SetWrapped(EFalse);
+				}
+			}
+			InsertWrapMarkerL(ESent);
+		}
+	SetNextNotificationThreshold(ESent);
+	}
+
+
+EXPORT_C void ADataMonitoringProvider::CancelClientExtItfRequests(TSubSessionUniqueId aClientId)
+	{
+	CancelDataSentNotificationRequest(aClientId);
+	CancelDataReceivedNotificationRequest(aClientId);
+	}
+
+/**
+    Call from a node activity upon receiving TCFMessage::TDataMonitoringInternal 
+    message extension.
+*/
+EXPORT_C void ADataMonitoringProvider::DataNotificationL(const ESock::TCFDataMonitoringNotification::TDataMonitoringNotification& aNotification)
+    {
+	switch(aNotification.iValue1)
+		{
+		case EReceived:
+			DataReceivedNotificationL(aNotification.iValue2);
+			break;
+			
+		case ESent:
+			DataSentNotificationL(aNotification.iValue2);
+			break;
+			
+		default:
+			break;
+		}	
+    }
+    
+/**
+
+*/
+void ADataMonitoringProvider::InsertWrapMarkerL(TDataMonitoringDirection aDirection)
+	{
+	TNotificationRequest* wrapMarkerRequest = new(ELeave) TNotificationRequest(NULL, 0);
+	
+	wrapMarkerRequest->SetThreshold(KMaxTUint32);
+	wrapMarkerRequest->SetCancelled();
+	
+	TInt ret = NotificationRequestArray(aDirection)->InsertInOrder(wrapMarkerRequest, TLinearOrder<TNotificationRequest>(TNotificationRequest::CompareThresholds));
+	
+	if(ret != KErrNone)
+		{	
+		// If the insert failed then the most likely reason is a KErrAlreadyExists.  In any
+		// case, we definitely want to delete the wrap marker.  Then we'll try and carry on
+		// as best we can.
+		delete wrapMarkerRequest;
+		}				
+	}
+
+
+/**
+
+*/
+RNotificationRequestArray* ADataMonitoringProvider::NotificationRequestArray(TDataMonitoringDirection aDirection)
+	{
+	if(aDirection == EReceived)
+		{
+		return &iReceivedNotificationRequests;
+		}
+	else
+		{
+		return &iSentNotificationRequests;
+		}
+	}
+
+/**
+
+*/
+TInt ADataMonitoringProvider::InsertNotificationRequest(TNotificationRequest* aRequest, TDataMonitoringDirection aDirection)
+	{
+	TInt err;
+	err = NotificationRequestArray(aDirection)->InsertInOrderAllowRepeats(aRequest, TLinearOrder<TNotificationRequest>(TNotificationRequest::CompareThresholds));
+
+	LOG(
+		switch(aDirection)
+			{
+		case ESent:
+			ESockLog::Printf(_L("ADataMonitoringProvider(%08x)::InsertNotificationRequest - Direction: Sending"), this);
+			break;			
+		case EReceived:
+			ESockLog::Printf(_L("ADataMonitoringProvider(%08x)::InsertNotificationRequest - Direction: Receiving"), this);
+			break;
+			}
+		
+		for(TInt idx=0;idx<NotificationRequestArray(aDirection)->Count();idx++)
+			{
+			TNotificationRequest* req = (*NotificationRequestArray(aDirection))[idx];
+			ESockLog::Printf(_L("\tRequest %d, Threshold %d, Wrapped %d, Client id. 0x%08x"), idx, req->Threshold(), req->Wrapped(), req->ClientId());
+			}
+		)
+	
+	return err;
+	}
+
+/**
+*/
+void ADataMonitoringProvider::SetNextNotificationThreshold(TDataMonitoringDirection aDirection) 
+	{
+	if(NotificationRequestArray(aDirection)->Count())
+		{
+		switch(aDirection)
+			{
+		case EReceived:			
+			iThresholds.iReceivedThreshold = (*NotificationRequestArray(EReceived))[0]->Threshold();				
+			break;
+
+		case ESent:			
+			iThresholds.iSentThreshold = (*NotificationRequestArray(ESent))[0]->Threshold();			
+			break;
+			}
+		}
+	}
+
+
+/**
+
+*/
+EXPORT_C TDataMonitoringConnProvisioningInfo::TDataMonitoringConnProvisioningInfo(TDataVolumes* aDataVolumesPtr, TNotificationThresholds* aThresholdsPtr) :
+	TDataMonitoringProvisioningInfoBase(aDataVolumesPtr, aThresholdsPtr)
+	{
+	}
+
+
+/**
+
+*/
+EXPORT_C TDataMonitoringSubConnProvisioningInfo::TDataMonitoringSubConnProvisioningInfo(TDataVolumes* aDataVolumesPtr, TNotificationThresholds* aThresholdsPtr) :
+	TDataMonitoringProvisioningInfoBase(aDataVolumesPtr, aThresholdsPtr)
+	{
+	}
+
+
+/**
+	Sets the data volume notification threshold given the current transferred volume
+	and a delta from the current amount.
+	
+	@param aVolume Current data volume transferred
+	@param aDelta An offset from the current volume of data transferred
+*/
+void TNotificationRequest::SetThresholdFromDelta(TUint32 aVolume, TUint32 aDelta)
+	{
+	TUint64 threshold = aVolume + aDelta;
+	
+	if(threshold > KMaxTUint32) 
+		{
+		iWrapped = ETrue;
+		iThreshold = threshold - KMaxTUint32;
+		}
+	else
+		{
+		iWrapped = EFalse;
+		iThreshold = threshold;
+		}	
+	}
+		
+/**
+	Compares two TNotificationRequest objects using their thresholds as the criteria.
+*/
+TInt TNotificationRequest::CompareThresholds(const TNotificationRequest& aFirst, const TNotificationRequest& aSecond)
+	{
+	TUint64 effectiveFirstThreshold = aFirst.iThreshold;
+	TUint64 effectiveSecondThreshold = aSecond.iThreshold;
+	
+	if(aFirst.Wrapped()) effectiveFirstThreshold += KMaxTUint32;
+	if(aSecond.Wrapped()) effectiveSecondThreshold += KMaxTUint32;
+
+	if(effectiveFirstThreshold > effectiveSecondThreshold)
+		{
+		return 1;
+		}
+	else if(effectiveFirstThreshold < effectiveSecondThreshold) 
+		{
+		return -1;
+		}
+	else
+		{
+		return 0;
+		}
+	}
+
+/**
+	Compares two TNotificationRequest objects using their client ids as the criteria.
+*/
+TBool TNotificationRequest::CompareClientIds(const TNotificationRequest& aFirst, const TNotificationRequest& aSecond)
+	{
+	if(aFirst.ClientId() == aSecond.ClientId())
+		{
+		return ETrue;
+		}
+	else
+		{
+		return EFalse;
+		}
+	}
+
+EXPORT_START_ATTRIBUTE_TABLE_AND_FN(TDataMonitoringProvisioningInfoBase, TDataMonitoringProvisioningInfoBase::iUid, TDataMonitoringProvisioningInfoBase::iId)
+	REGISTER_ATTRIBUTE(TDataMonitoringProvisioningInfoBase, iDataVolumesPtr, TMeta<TDataMonitoringProvisioningInfoBase*>)
+	REGISTER_ATTRIBUTE(TDataMonitoringProvisioningInfoBase, iThresholdsPtr, TMeta<TDataMonitoringProvisioningInfoBase*>)
+END_ATTRIBUTE_TABLE()
+
+EXPORT_START_ATTRIBUTE_TABLE_AND_FN(TDataMonitoringConnProvisioningInfo, TDataMonitoringProvisioningInfoBase::iUid, TDataMonitoringConnProvisioningInfo::iId)
+END_ATTRIBUTE_TABLE_BASE(TDataMonitoringProvisioningInfoBase, 0)
+
+EXPORT_START_ATTRIBUTE_TABLE_AND_FN(TDataMonitoringSubConnProvisioningInfo, TDataMonitoringProvisioningInfoBase::iUid, TDataMonitoringSubConnProvisioningInfo::iId)
+END_ATTRIBUTE_TABLE_BASE(TDataMonitoringProvisioningInfoBase, 0)
+