Committing ZeroConf for 10.1 to the FCL.
// 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;
}