zeroconf/server/src/csendmessagequeue.cpp
changeset 14 da856f45b798
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zeroconf/server/src/csendmessagequeue.cpp	Thu Jun 24 19:09:47 2010 +0530
@@ -0,0 +1,338 @@
+// Copyright (c) 2008-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:
+// csendmessagequeue.cpp
+// 
+//
+/**
+@file
+@internalTechnology
+*/
+
+#include "f32file.h" 
+
+#include "cmessagehandler.h"
+#include "csendmessagequeue.h"
+__FLOG_STMT(_LIT8(KComponent,"MDNSServer");)
+/**
+Two phase constructor
+@param aDnsMessage Dns message to be sent 
+@param aUnicast True if it is a unicast response
+@param aAddr address to which the packet to be send
+@return CSendMessageData object
+*/
+CSendMessageData* CSendMessageData::NewL(CDnsMessage* aDnsMessage, TBool aUnicast,TSockAddr aAddr,MMessageHandler& aCallback)
+	{
+	CSendMessageData* self = new(ELeave)CSendMessageData(aDnsMessage,aUnicast,aAddr,aCallback);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;	
+	}
+
+/**
+Constant function which returns the reference to the Dns message object it wraps
+@return constant reference to dnsmessage object
+*/
+const CDnsMessage& CSendMessageData::GetDnsMessage()const
+	{
+	__FLOG(_L8("CSendMessageData::GetDnsMessage - Exit"));
+	return const_cast<CDnsMessage&> (*iMessage);	
+	}
+
+/**
+Constant function which returns the address of the data to be sent
+@return Constant reference to the address
+*/
+const TSockAddr& CSendMessageData::GetSockAddress()const
+	{
+	__FLOG(_L8("CSendMessageData::GetSockAddress - Exit"));
+	return iSockAddr;	
+	}
+
+/**
+Constant function which returns true if the message is unicast
+@return True if message is unicast
+*/
+const TBool& CSendMessageData::IsUnicast()const
+	{
+	__FLOG(_L8("CSendMessageData::IsUnicast - Exit"));
+	return iUnicast;	
+	}
+/**
+Destructor
+*/
+CSendMessageData::~CSendMessageData()
+	{
+	__FLOG(_L8("CSendMessageData::~CSendMessageData - Entry"));
+	delete iMessage;
+	__FLOG(_L8("CSendMessageData::~CSendMessageData - Exit"));
+	__FLOG_CLOSE;
+	}
+
+/**
+Two phase constructor
+@param aDnsMessage DnsMessage to be send
+*/
+void CSendMessageData::ConstructL()
+	{
+	__FLOG_OPEN(KMDNSSubsystem, KComponent);	
+	}
+	
+/**
+Constructor
+@param aUnicast True if it is a unicast response
+@param aAddr Address to which the data to be sent
+*/
+CSendMessageData::CSendMessageData(CDnsMessage* aDnsMessage,TBool aUnicast,TSockAddr aAddr,MMessageHandler& aCallback):iMessage(aDnsMessage),iUnicast(aUnicast),iSockAddr(aAddr),iCallback(aCallback)
+	{
+	
+	}
+
+MMessageHandler& CSendMessageData::Callback()
+	{
+	__FLOG(_L8("CSendMessageData::Callback - Exit"));
+	return iCallback;	
+	}
+/**
+Two phase Constructor
+@param aSocket reference to the RSocket
+*/
+CSendMessageQueue* CSendMessageQueue::NewL(RSocket& aSocket)
+	{
+	CSendMessageQueue* self = new (ELeave)CSendMessageQueue();
+	CleanupStack::PushL(self);
+	self->ConstructL(aSocket);
+	CleanupStack::Pop(self);
+	return self;		
+	}
+	
+/**
+Constructor
+*/
+CSendMessageQueue::CSendMessageQueue():CTimer(EPriorityStandard)
+	{
+	CActiveScheduler::Add(this);	
+	}
+	
+/**
+Function derived from MSocketHandler Observer.
+This method will be called on succesfull sending of the packet.
+*/
+void CSendMessageQueue::OnCompletionL(TDesC8& /*aData*/, const TSockAddr& /*aAddr*/, TInt /*aLength*/)
+	{
+	__FLOG(_L8("CSendMessageQueue::OnCompletionL - Entry"));
+	if(iSendMessageData)
+		{
+		iIsSocketActive = EFalse;
+		iSendMessageData->Callback().OnPacketSendL(KErrNone);	
+		}
+	delete iSendMessageData;
+	iSendMessageData = NULL;
+	if(iMessageQueue.Count() > 0 && !IsActive() )
+		{
+		StartTransmit();
+		}
+	__FLOG(_L8("CSendMessageQueue::OnCompletionL - Exit"));
+	}
+
+/*
+Function derived from MSocketHandler Observer.
+This method will be called on error in  sending the packet.
+*/	
+void CSendMessageQueue::OnError(TInt aError)
+	{
+	__FLOG(_L8("CSendMessageQueue::OnError - Entry"));
+	if(iSendMessageData)
+		{
+		iSendMessageData->Callback().OnPacketSendL(aError);	
+		}	
+	__FLOG(_L8("CSendMessageQueue::OnError - Exit"));
+	}
+	
+/**
+Destructor
+*/	
+CSendMessageQueue::~CSendMessageQueue()
+	{
+	__FLOG(_L8("CSendMessageQueue::~CSendMessageQueue - Entry"));
+	delete iSendSocket;
+	delete iSendMessageData;
+	iMessageQueue.ResetAndDestroy();
+	iMessageQueue.Close();	
+	iOutput.Close();
+	__FLOG(_L8("CSendMessageQueue::~CSendMessageQueue - Exit"));
+	__FLOG_CLOSE;
+	}
+
+/**
+Two phase constructor
+@param refernce to RSocket
+*/	
+void CSendMessageQueue::ConstructL(RSocket& aSocket)
+	{
+	__FLOG(_L8("CSendMessageQueue::ConstructL - Entry"));
+	iSendSocket = CSocketHandler::NewL(aSocket, *this, ESocketSend);
+	CTimer::ConstructL();
+	iIsSocketActive = EFalse;
+	__FLOG(_L8("CSendMessageQueue::ConstructL - Exit"));
+	}
+	
+/**
+Derived from CActive
+*/	
+void CSendMessageQueue::RunL()
+	{
+	__FLOG(_L8("CSendMessageQueue::RunL - Entry"));
+	if (MessageReady())
+		{
+		iSendMessageData = NextDnsMessageL();
+		CleanupStack::PushL(iSendMessageData);
+		const CDnsMessage& dnsMessage = iSendMessageData->GetDnsMessage();
+		// close the previously allocated memory.  
+		iOutput.Close();
+		//composes the message from the Dnsmessage object .
+		CDnsMessageComposerParser* comPos = CDnsMessageComposerParser::NewL();
+		CleanupStack::PushL(comPos);
+		comPos->CreateMessageL(iOutput, iSendMessageData->GetDnsMessage());
+		TSocketHandlerParams param(ESocketSendTo,&iOutput,&(iSendMessageData->GetSockAddress()));
+		iSendSocket->Activate(param);
+		iIsSocketActive = ETrue;
+		CleanupStack::PopAndDestroy();//comPos
+		CleanupStack::Pop();
+		}
+	__FLOG(_L8("CSendMessageQueue::RunL - Exit"));
+	}
+/*
+ * Nothing to do.
+ */
+void CSendMessageQueue::DoCancel()
+	{
+	__FLOG(_L8("CSendMessageQueue::DoCancel - Exit"));
+	}
+
+void CSendMessageQueue::QueueDnsMessageL(const CSendMessageData& aMessageData)
+	{
+	__FLOG(_L8("CSendMessageQueue::QueueDnsMessageL - Entry"));
+	if (aMessageData.IsUnicast())
+		{
+		// Unicast replies are to be given higher priority .
+		// Insert the  unicast response in the queue.
+		TInt count(iMessageQueue.Count());
+		TInt index(0);
+		for (; index < count; ++index)
+			{
+			if (!iMessageQueue[index]->IsUnicast())
+				{
+				break;
+				}
+			}
+		iMessageQueue.InsertL(&aMessageData, index);
+		
+		iNextTransmit.HomeTime();
+		Cancel();
+		}
+	else
+		{
+		// Queue the packet
+		iMessageQueue.AppendL(&aMessageData);
+		}
+	
+	// kick the transmit limiter, so we're sure the message will be sent
+	if(!iIsSocketActive)
+	    {
+	    NextTransmitTime(iNextTransmit);
+	    }
+	__FLOG(_L8("CSendMessageQueue::QueueDnsMessageL - Exit"));	
+	}
+	
+void CSendMessageQueue::NextTransmitTime(TTime aTime)
+	{
+	__FLOG(_L8("CSendMessageQueue::NextTransmitTime - Entry"));
+	// if we aren't already active, set the next TX time
+	if (!IsActive())
+		{
+		TTime now;
+		now.HomeTime();
+		
+		if (aTime > now)
+			{
+			At(aTime);
+			}
+		else
+			{
+			StartTransmit();
+			}
+		}	
+	__FLOG(_L8("CSendMessageQueue::NextTransmitTime - Exit"));
+	}
+
+void CSendMessageQueue::StartTransmit()
+	{
+	__FLOG(_L8("CSendMessageQueue::StartTransmit - Entry"));
+	SetActive();
+	TRequestStatus *status = &iStatus;
+	User::RequestComplete(status,KErrNone);
+	__FLOG(_L8("CSendMessageQueue::StartTransmit - Exit"));
+	}
+
+CSendMessageData* CSendMessageQueue::NextDnsMessageL()
+	{
+	__FLOG(_L8("CSendMessageQueue::NextDnsMessageL - Entry"));
+	if (0 == iMessageQueue.Count())
+		{
+		User::Leave(KErrNotReady);
+		}
+		
+	CSendMessageData* ret = iMessageQueue[0];
+	iMessageQueue.Remove(0);
+	// calculate the next possible transmit time.
+	iNextTransmit.HomeTime();
+	TInt delay = 20 + (Math::Rand(iRandomSeed) % 100);
+	iNextTransmit += TTimeIntervalMicroSeconds(delay * 1000);  
+	__FLOG(_L8("CSendMessageQueue::NextDnsMessageL - Exit"));
+	return ret;
+	}
+
+TBool CSendMessageQueue::MessageReady()
+	{
+	__FLOG(_L8("CSendMessageQueue::MessageReady - Entry"));
+	TBool ready = EFalse;
+	if (0 != iMessageQueue.Count())
+		{
+		if (iMessageQueue[0]->IsUnicast())
+			{
+			// unicast messages go out straight away.
+			ready = ETrue;
+			}
+		else
+		 	{
+		 	TTime now;
+		 	now.HomeTime();
+		 	if (!IsActive())
+		 		{
+		 		if (now >= iNextTransmit)
+		 			{
+		 			ready = ETrue;
+		 			}
+		 		else
+		 			{
+					NextTransmitTime(iNextTransmit);		 		
+		 			}
+		 		}
+			}
+		}
+	__FLOG(_L8("CSendMessageQueue::MessageReady - Exit"));
+	return ready;
+	}
+