locationrequestmgmt/networkrequesthandler/src/ngmessageswitch.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 17 Sep 2010 08:37:32 +0300
changeset 60 9a7e3d5f461a
parent 0 9cfd9a3ee49c
child 54 0c2046328c85
permissions -rw-r--r--
Revision: 201037 Kit: 201037

// 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:
//

#include <e32base.h>

// LBS-specific
#include <lbs.h>
#include <lbs/lbslocerrors.h>
#include "lbsdevloggermacros.h"

#include "lbsprocessuiddefs.h"
#include "ngmessageswitch.h"
#include "lbsnetinternalapi.h"
#include "nrhpanic.h"


//
// CNGMessageSendBufferBase
//

CNGMessageSendBufferBase::CNGMessageSendBufferBase(RLbsNetChannel& aGatewayChannel, CLbsAdmin& aAdmin) :
	CActive(EPriorityStandard),
	iAdmin(aAdmin),
	iNetGatewayChannel(aGatewayChannel)
	
	{
	CActiveScheduler::Add(this);
	}
	
CNGMessageSendBufferBase::~CNGMessageSendBufferBase()
	{
	Cancel();
	}

void CNGMessageSendBufferBase::RunL()
	{
	// This must be implemented by the child class, so leave here
	User::Leave(KErrNotSupported);
	}

void CNGMessageSendBufferBase::DoCancel()
	{
	iNetGatewayChannel.CancelSendMessageNotification();
	}

void CNGMessageSendBufferBase::SendMessageToNetwork(const TLbsNetInternalMsgBase& aMessage)
	{
	iNetGatewayChannel.SendMessage(aMessage, iStatus);
	SetActive();
	}
	
//
// CNGMessageSendBuffer
//

// Dummy params used for initialising member variables
const TLbsNetSessionIdInt KInvalidSessionId;
const TPositionInfo KInvalidPosInfo;
const TTime KInvalidTTime(0);


//
// CNGMessageSendBuffer
//

	
CNGMessageSendBuffer::CNGMessageSendBuffer(RLbsNetChannel& aGatewayChannel, CLbsAdmin& aAdmin) :
	CNGMessageSendBufferBase(aGatewayChannel, aAdmin),
	iEmergencyBuffer(2), // two spaces allocated - all we need to process an emergency
	iEmergencyPrivacyResponseData(KInvalidSessionId, TLbsNetworkEnumInt::EPrivacyResponseUnknown, KErrNone),
	iEmergencyLocationResponseData(KInvalidSessionId, KErrNone, KInvalidPosInfo, KInvalidTTime)
	{
	}
	
CNGMessageSendBuffer::~CNGMessageSendBuffer()
	{
	iEmergencyBuffer.Reset();
	iBuffer.ResetAndDestroy();
	}

CNGMessageSendBuffer* CNGMessageSendBuffer::NewL(RLbsNetChannel& aGatewayChannel, CLbsAdmin& aAdmin)
	{
	CNGMessageSendBuffer* self = new (ELeave) CNGMessageSendBuffer(aGatewayChannel, aAdmin);
	return self;
	}
	
void CNGMessageSendBuffer::RunL()
	{
	User::LeaveIfError(iStatus.Int());
	
	// Send the next message in the buffer,
	// if there is one there.
	if (iEmergencyBuffer.Count() > 0)
		{
		// Send the emergency related message to the Network Gateway
		TLbsNetInternalMsgBase* msg = iEmergencyBuffer[0];
		SendMessageToNetwork(*msg);
		iEmergencyBuffer.Remove(0);
		}
	else if (iBuffer.Count() > 0)
		{
		// Send the message to the Network Gateway
		TLbsNetInternalMsgBase* msg = iBuffer[0];
		SendMessageToNetwork(*msg);
		
		// Remove and delete the item from the buffer if it was a "newed" one
		iBuffer.Remove(0);
		delete msg;
		}
	}

/* Error function that catches the leave from RunL.

For this class, it is not a fatal error if the property
returns an error, so only log the error with LBS devlogger.
*/
TInt CNGMessageSendBuffer::RunError(TInt aError)
	{
	LBSLOG_ERR2(ELogP3, "CNGMessageSendBuffer::RunError : %d", aError);
	return KErrNone;
	}

void CNGMessageSendBuffer::BufferData(TLbsNetInternalMsgBase* aData)
	{	
	// Add the data to the buffer
	TInt err = iBuffer.Append(aData);
	if( err != KErrNone )
		{
		LBSLOG_ERR2(ELogP3, "CNGMessageSendBuffer::BufferData Append failed: %d", err);
		delete aData;
		}
	}

void CNGMessageSendBuffer::BufferEmergencyData(TLbsNetInternalMsgBase* aData)
	{	
	// Add the data to the emergency buffer
	TInt err = iEmergencyBuffer.Append(aData);
	// there should always be enough space in this array of pointers because we pre-alloated
	__ASSERT_DEBUG(KErrNone == err, Panic(ENrhPanicOOMWhenProcessingEmergency));

	}
	
	
void CNGMessageSendBuffer::SendNetLocResponseToNetwork(
		const TLbsNetSessionIdInt& aSessionId, 
		TInt aCompletionCode,
		const TPositionInfoBase& aPosInfo,
		const TTime& aTimeStamp,
		TBool aEmergency)
	{
	TLbsNetLocationResponseMsg msg(aSessionId,
								   aCompletionCode,
								   aPosInfo,
								   aTimeStamp);

	if (!IsActive())
		{
		SendMessageToNetwork(msg);
		}
	else
		{
		TLbsNetLocationResponseMsg* bufMsg = NULL;
		if (aEmergency)
			{
			iEmergencyLocationResponseData = msg;
			bufMsg = &iEmergencyLocationResponseData;
			BufferEmergencyData(bufMsg);	
			}
		else
			{
			bufMsg = new TLbsNetLocationResponseMsg(msg);
			if (bufMsg)
				{
				BufferData(bufMsg);	
				}
			else
				{
				LBSLOG_ERR(ELogP3, "CNGMessageSendBuffer::SendNetLocResponseToNetwork: Failed to allocate memory.");
				}
			}
				
		// coverity [memory_leak]
		// we do not delete bufMsg here as it is now owned by iBuffer
		}
	}
	
void CNGMessageSendBuffer::SendMtlrResponseToNetwork(
		const TLbsNetSessionIdInt& aSessionId, 
		TLbsNetworkEnumInt::TLbsPrivacyResponseInt aResult,
		TInt /* aReason */,
		TBool aEmergency)
	{
	
	TLbsNetMtLrReponseMsg* bufMsg = NULL;
	
	TLbsNetMtLrReponseMsg msg(aSessionId, aResult, KErrNone);
	
	if (!IsActive())
		{
		SendMessageToNetwork(msg);
		}
	else
		{

		if (aEmergency)
			{
			iEmergencyPrivacyResponseData = msg;
			bufMsg = &iEmergencyPrivacyResponseData;
			BufferEmergencyData(bufMsg);	
			}
		else
			{
			bufMsg = new TLbsNetMtLrReponseMsg(msg);
			if (bufMsg)
				{
				BufferData(bufMsg);	
				}
			else
				{
				LBSLOG_ERR(ELogP3, "CNGMessageSendBuffer::SendMtlrResponseToNetwork: Failed to allocate memory.");
				}
			}
	
		// coverity [memory_leak]
		// we do not delete bufMsg here as it is now owned by iBuffer
		}	
	}
	
void CNGMessageSendBuffer::SendX3pRequestToNetwork(
		const TLbsNetSessionIdInt& aSessionId,
		const TDesC& aDestId,
		TUint aTransmitPriority,
		const TLbsNetPosRequestOptionsTechnologyInt& aOptions)
	{
	TLbsNetTransmitLocationRequestMsg msg(aSessionId, 
										  aDestId, 
										  aTransmitPriority,
										  aOptions);	
	

	if (!IsActive())
		{
		SendMessageToNetwork(msg);
		}
	else
		{
		TLbsNetTransmitLocationRequestMsg* bufMsg = new TLbsNetTransmitLocationRequestMsg(msg);
		if (bufMsg)
			{
			BufferData(bufMsg);	
			}
		else
			{
			LBSLOG_ERR(ELogP3, "CNGMessageSendBuffer::SendX3pRequestToNetwork: Failed to allocate memory.");
			}
		
		// coverity [memory_leak]
		// we do not delete bufMsg here as it is now owned by iBuffer
		}	
	}
	
void CNGMessageSendBuffer::SendX3pCancelToNetwork(
		const TLbsNetSessionIdInt& aSessionId,
		TInt aReason)
	{
	TLbsNetTransmitLocationCancelMsg msg(aSessionId, aReason);

	if (!IsActive())
		{
		SendMessageToNetwork(msg);
		}
	else
		{
		TLbsNetTransmitLocationCancelMsg* bufMsg = new TLbsNetTransmitLocationCancelMsg(msg);
		if (bufMsg)
			{
			BufferData(bufMsg);	
			}
		else
			{
			LBSLOG_ERR(ELogP3, "CNGMessageSendBuffer::SendX3pCancelToNetwork: Failed to allocate memory.");
			}
		
		// coverity [memory_leak]
		// we do not delete bufMsg here as it is now owned by iBuffer
		}	
	}

void CNGMessageSendBuffer::SendExternalLocateCancelToNetwork(const TLbsNetSessionIdInt& aSessionId,
												  TInt aReason)
	{
	TLbsNetCancelFromPrivacyControllerMsg msg(aSessionId, 
											 aReason);

	if (!IsActive())
		{
		SendMessageToNetwork(msg);
		}
	else
		{
		TLbsNetCancelFromPrivacyControllerMsg* bufMsg = new TLbsNetCancelFromPrivacyControllerMsg(msg);
		if (bufMsg)
			{
			BufferData(bufMsg);	
			}
		else
			{
			LBSLOG_ERR(ELogP3, "CNGMessageSendBuffer::SendExternalLocateCancelToNetwor: Failed to allocate memory.");
			}
        
		// coverity [memory_leak]
        // we do not delete bufMsg here as it is now owned by iBuffer
		}	
	}


//
// CNGMessageSwitch
//	

CNGMessageSwitch::CNGMessageSwitch(CLbsAdmin& aAdmin):	
	iAdmin(aAdmin)
    {	
    }
    
CNGMessageSwitch* CNGMessageSwitch::NewL(CLbsAdmin& aAdmin)
    {
	CNGMessageSwitch* self = new (ELeave) CNGMessageSwitch(aAdmin);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);	
	return(self);
    }
        
void CNGMessageSwitch::ConstructL()
    {
    iObservers.ReserveL(2);
    iNetworkGateway.OpenL(RLbsNetChannel::EChannelNRH2NG, *this);
    	
    iNetworkGatewaySendBuffer = CNGMessageSendBuffer::NewL(iNetworkGateway, iAdmin);

    }
    
CNGMessageSwitch::~CNGMessageSwitch()
    {

    iRefPosBuffer.Close();
    
    iFNPPosBuffer.ResetAndDestroy();

    delete iNetworkGatewaySendBuffer;

    iNetworkGateway.Close();
    
    iObservers.Close();
    }
    
TInt CNGMessageSwitch::RegisterObserver(MNGMessageSwitchObserver* aObserver)
    {
	return iObservers.Append(aObserver);
    }

void CNGMessageSwitch::SendX3pRequest(const TLbsNetSessionIdInt& aSessionId,
									  const TDesC& aDestId,
									  TUint aTransmitPriority,
									  const TLbsNetPosRequestOptionsTechnologyInt& aOptions)
    {
    iNetworkGatewaySendBuffer->SendX3pRequestToNetwork(aSessionId, aDestId, aTransmitPriority, aOptions);
    }

void CNGMessageSwitch::SendX3pCancel(const TLbsNetSessionIdInt& aSessionId,
									 TInt aReason)
    {
    iNetworkGatewaySendBuffer->SendX3pCancelToNetwork(aSessionId, aReason);
    }
        
void CNGMessageSwitch::SendMTLRResponse(const TLbsNetSessionIdInt& aSessionId, 
										TLbsNetworkEnumInt::TLbsPrivacyResponseInt aResult,
										TInt aReason,
										TBool aEmergency)
    {
    iNetworkGatewaySendBuffer->SendMtlrResponseToNetwork(aSessionId, aResult, aReason, aEmergency);
    }
void CNGMessageSwitch::SendExternalLocateCancel(const TLbsNetSessionIdInt& aSessionId, TInt aReason)
	{
	iNetworkGatewaySendBuffer->SendExternalLocateCancelToNetwork(aSessionId, aReason);
	}

void CNGMessageSwitch::SendNetLocResponse(
		const TLbsNetSessionIdInt& aSessionId, 
		TInt aCompletionCode,
		const TLbsNetPosRequestQualityInt& aRequestQuality,
		const TPositionInfoBase& aPosInfo,
		const TTime& aTimeStamp,
		TBool aEmergency)
	{
	// Send a Network Location Response to the network
	iNetworkGatewaySendBuffer->SendNetLocResponseToNetwork(aSessionId, 
														aCompletionCode,
														aPosInfo, 
														aTimeStamp,
														aEmergency);
	
	// Let the observers know what the quality criteria were, so that if
	// the network modifies teht final position the client can see if it
	// matches the orignal criteria.
	const TInt count = iObservers.Count();
	for (TInt i = 0; i < count; i++)
		{
		iObservers[i]->OnNetLocResponse(aSessionId,aRequestQuality);
		}
	}

/**
 From MLbsNetChannelObserver.
 Called when a message is sent by the Network Gateway.
 */    
void CNGMessageSwitch::ProcessNetChannelMessage(RLbsNetChannel::TLbsNetChannelId aChannelId, const TLbsNetInternalMsgBase& aMessage)
	{
	__ASSERT_DEBUG(aChannelId == RLbsNetChannel::EChannelNRH2NG, Panic(ENrhPanicUnexpectedNetChannelId));
	(void) aChannelId;
    
	switch(aMessage.Type())
		{
		case TLbsNetInternalMsgBase::ELocationRequest:
			{
			const TLbsNetLocationRequestMsg* msg = 
							static_cast<const TLbsNetLocationRequestMsg*>(&aMessage);
			const TInt count = iObservers.Count();
			// for an NI the REF location may arrive before the location request
			TPositionInfo posInfo;
			TInt err = GetNetworkReferencePosition(msg->SessionId(), posInfo);

			for (TInt i = 0; i < count; i++)
				{
				iObservers[i]->OnNetLocRequest(msg->SessionId(), 
														msg->Method(),
														msg->Service(), 
														msg->IsEmergency(), 
														msg->Quality());
				if (KErrNone == err) // if no error then there is a reference position so pass it on
					{
					iObservers[i]->OnNetLocReferenceUpdate(msg->SessionId(), posInfo);
					}
				}
			break;
			}
		   
		case TLbsNetInternalMsgBase::ESessionComplete:
			{
			const TLbsNetSessionCompleteMsg* msg = 
						static_cast<const TLbsNetSessionCompleteMsg*>(&aMessage);

			const TInt count = iObservers.Count();
			for (TInt i = 0; i < count; i++)
				{
				iObservers[i]->OnSessionComplete(msg->SessionId(), 
												 msg->Reason());
				}

			// We know the request session has finished now, so remove
			// any buffered reference or final network positions.
			RemoveBufferedNetworkPositions(msg->SessionId());
			break;
			}
		   
		case TLbsNetInternalMsgBase::EPrivacyRequest: 
			{
			const TLbsNetMtLrRequestMsg* msg = 
						static_cast<const TLbsNetMtLrRequestMsg*>(&aMessage);

			const TInt count = iObservers.Count();
			for (TInt i = 0; i < count; i++)
				{
				iObservers[i]->OnMTLRRequest(msg->SessionId(), 
										 	 TLbsNetworkEnumInt::EServiceMobileTerminated, 
										 	 msg->IsEmergency(),
											 msg->RequestInfo(),
											 msg->Privacy());
				}
			break;
			}

		case TLbsNetInternalMsgBase::ENetworkLocationUpdate:
				{
				const TLbsNetLocationUpdateMsg * msg = 
							static_cast<const TLbsNetLocationUpdateMsg*>(&aMessage);
				// its either a REF location or a FNP
				const TPositionInfoBase& positionInfo =  msg->PositionInfo();
				
				TPositionModuleInfo::TTechnologyType techType = positionInfo.PositionMode();
			
				const TInt count = iObservers.Count();
				
						
				if (TPositionModuleInfo::ETechnologyNetwork == techType)
					{ // reference position add to ref pos list 
					TNetPosItem item;
					item.iSessionId = msg->SessionId();
					Mem::Copy(&item.iPosInfo, &positionInfo, positionInfo.PositionClassSize());
					
					// OOM  - do nothing here - just ignore the error which results in the REF pos 
					// not being saved. Note we do enure that the mobiles position
					// does get sent out to the network - its juts means that the callback
					// that delivers the REF pos to the privacy system does not happen!
					TInt err = iRefPosBuffer.Append(item);
					if( KErrNone != err )
						{
						LBSLOG_ERR(ELogP3, "CNGMessageSwitch::ProcessNetChannelMessage: iRefPosBuffer.Append Failed!!");
						}
					for (TInt i = 0; i < count; i++)
						{
						iObservers[i]->OnNetLocReferenceUpdate(msg->SessionId(), positionInfo);
						}
					}
				else
					{ 
					// save  FNP here - for processing 
					// completion of X3Ps when session completes
					TNetFNPPosItem* item = new TNetFNPPosItem();
					if (item == NULL)
						{
						// OOM  - do nothing here - just discard the FNP.. 
						// Note thats OK becuase we don't need to save the FNP for tp process 
						// emergencies just X3Ps. 
						}
					else
						{
						item->iSessionId = msg->SessionId();
					
						Mem::Copy(&item->iPosInfo, &positionInfo, positionInfo.PositionClassSize());
						TInt err = iFNPPosBuffer.Append(item); // here, ownership passes to pointer array!
						if( KErrNone != err )
							{
							delete item;
							LBSLOG_ERR(ELogP3, "CNGMessageSwitch::ProcessNetChannelMessage: iFNPPosBuffer.Append Failed!!");
							}
						}
					for (TInt i = 0; i < count; i++)
						{
						iObservers[i]->OnNetLocFinalUpdate(msg->SessionId(), positionInfo);
						}
					}
				break;
				}
		case TLbsNetInternalMsgBase::ETransmitLocationRequest:// outgoing only
		case TLbsNetInternalMsgBase::ELocationResponse:       // outgoing only
		case TLbsNetInternalMsgBase::EPrivacyResponse:        // outgoing only
		default:
			{
			break;
			}
		}
    }


/** SessionId comparison for RArray<TNetPosItem>::Find().
*/
TBool CNGMessageSwitch::IsSessionIdEqual(
		const TLbsNetSessionIdInt* aSessionId,
    	const TNetPosItem& aItem)
	{
	return (*aSessionId == aItem.iSessionId);
	}
/** SessionId comparison for RPointerArray<TNetFNPPosItem>::Find().
*/
TBool CNGMessageSwitch::IsFNPSessionIdEqual(
		const TLbsNetSessionIdInt* aSessionId,
    	const TNetFNPPosItem& aItem)
	{
	return (*aSessionId == aItem.iSessionId);
	}
 
/**
*/
TInt CNGMessageSwitch::GetNetworkReferencePosition(
		const TLbsNetSessionIdInt& aSessionId,
		TPositionInfoBase& aPosInfo)
	{
	// Try to find the update if it has already happened.
	TInt index = iRefPosBuffer.Find(aSessionId, IsSessionIdEqual);
	if (index >= 0)
		{
		const TNetPosItem& item = iRefPosBuffer[index];
		Mem::Copy(&aPosInfo, &item.iPosInfo, item.iPosInfo.PositionClassSize());
		return KErrNone;
		}
	else
		{
		return KErrNotFound;
		}
	}

/**
*/
TInt CNGMessageSwitch::GetNetworkFinalPosition(
		const TLbsNetSessionIdInt& aSessionId,
		TPositionInfoBase& aPosInfo)
	{
	// Try to find the update if it has already happened.
	TInt index = iFNPPosBuffer.Find(aSessionId, IsFNPSessionIdEqual);
	if (index >= 0)
		{
		const TNetFNPPosItem* item = iFNPPosBuffer[index];
		Mem::Copy(&aPosInfo, &item->iPosInfo, item->iPosInfo.PositionClassSize());
		return KErrNone;
		}
	else
		{
		return KErrNotFound;
		}
	}

void CNGMessageSwitch::RemoveBufferedNetworkPositions(const TLbsNetSessionIdInt& aSessionId)
	{
	// Remove any reference positions
	TInt index = iRefPosBuffer.Find(aSessionId, IsSessionIdEqual);
	while (index >= 0)
		{
		iRefPosBuffer.Remove(index);
		index = iRefPosBuffer.Find(aSessionId, IsSessionIdEqual);
		}
	
	index = iFNPPosBuffer.Find(aSessionId, IsFNPSessionIdEqual);
	while (index >= 0)
		{
		TNetFNPPosItem* fnpPsItem = iFNPPosBuffer[index];
		delete fnpPsItem;
		iFNPPosBuffer.Remove(index);
		index = iFNPPosBuffer.Find(aSessionId, IsFNPSessionIdEqual);
		}
	}