--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/zeroconf/server/src/cadvertizehandler.cpp Thu Jun 24 19:09:47 2010 +0530
@@ -0,0 +1,470 @@
+// 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:
+// cadvertizehandler.cpp
+//
+//
+/**
+@file
+@internalTechnology
+*/
+//System include
+#include <mdns/ccacheentry.h>
+
+//UserInclude
+#include "cadvertizehandler.h"
+__FLOG_STMT(_LIT8(KComponent,"MDNSServer");)
+
+/*
+ * Two phase constructor
+ * @param aMessagHandler areference to messagehandler object.
+ * @param aAutoResolveEnabled If true sercice name conflict will be handled.
+ * aAutoResolveEnabled is True by default
+ */
+CAdvertizeHandler* CAdvertizeHandler::NewL(CMessageHandler& aMessageHandler,TBool aAutoResolveEnabled)
+ {
+ CAdvertizeHandler* self = new (ELeave) CAdvertizeHandler(aMessageHandler,aAutoResolveEnabled);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+/*
+ * Destructor
+ */
+CAdvertizeHandler::~CAdvertizeHandler()
+ {
+ __FLOG(_L8("CAdvertizeHandler::~CAdvertizeHandler- Entry"));
+ iData.ResetAndDestroy();
+ iData.Close();
+ iName.Close();
+ iProbeName.Close();
+ iProbeType.Close();
+ __FLOG(_L8("CAdvertizeHandler::~CAdvertizeHandler- Exit"));
+ __FLOG_CLOSE;
+ }
+/*
+ * No incoming packet for this so no need to handle
+ */
+void CAdvertizeHandler::HandleIncomingPacketL(CDnsMessage& /*aMessage*/)
+ {
+ __FLOG(_L8("CAdvertizeHandler::HandleIncomingPacketL- Entry"));
+ //Nothing To Do ............
+ __FLOG(_L8("CAdvertizeHandler::HandleIncomingPacketL- Exit"));
+ }
+
+static void CleanUpCache(TAny* aAny)
+ {
+
+ //RPointerArray <CCacheEntry> records = static_cast < RPointerArray <CCacheEntry> > (*aAny);
+ RPointerArray <CCacheEntry>* records = static_cast < RPointerArray <CCacheEntry> *> (aAny);
+ records->ResetAndDestroy();
+ records->Close();
+ }
+/*
+ * Constructor
+ * @param aMessageHandler reference to messagehandler
+ * @param aAutoResolveEnabled will be true by default ,if true servicename conflict
+ * will be handled by default
+ */
+CAdvertizeHandler::CAdvertizeHandler(CMessageHandler& aMessageHandler,TBool aAutoResolveEnabled):CBaseHandler(aMessageHandler)
+ {
+ __FLOG(_L8("CAdvertizeHandler::CAdvertizeHandler- Entry"));
+ iAutoResolveEnabled = aAutoResolveEnabled;
+ iCurrentProbeState = EIdle;
+ iProbeCounter = 0 ;
+ __FLOG(_L8("CAdvertizeHandler::CAdvertizeHandler- Exit"));
+ }
+
+/*
+ * Twophase constructor
+ */
+void CAdvertizeHandler::ConstructL()
+ {
+ __FLOG_OPEN(KMDNSSubsystem, KComponent);
+ __FLOG(_L8("CAdvertizeHandler::ConstructL- Entry"));
+ CBaseHandler::ConstructL();
+ //Nothing
+ __FLOG(_L8("CAdvertizeHandler::ConstructL- Exit"));
+ }
+/*
+ * Keeps a copy of the records to be published and starts the active object.
+ * @param aData an array of records to be published.
+ * @param aSessionId session id initiating the advertizement.
+ */
+void CAdvertizeHandler::AdvertizePacketL(const RPointerArray<CDnsResourceData> aData, TInt aSessionId,TBool aIsUpdate)
+ {
+ __FLOG(_L8("CAdvertizeHandler::AdvertizePacketL- Entry"));
+ iName.Close();
+ iName.Create(aData[0]->Name());
+ iProbeName.Close();
+ iProbeName.CreateL(KMaxLength);
+ iProbeName.Append(iName);
+ iCurrentProbeState = EStart;
+ iData.ResetAndDestroy();
+ for(TInt i =0 ; i<aData.Count();i++)
+ {
+ iData.AppendL(aData[i]);
+ }
+ // assign the session id so that, we can send bye-bye packet when the session is closed
+ iSessionId = aSessionId;
+ if(aIsUpdate)
+ {
+ iCurrentProbeState = EIdle;
+ TBool isExist = DefensiveResponseL();
+ if(!isExist)
+ {
+ User::Leave(KErrNotFound);
+ }
+ SendAnnouncementL();
+ InsertInCache();
+ return;
+ }
+ Schedule();
+ __FLOG(_L8("CAdvertizeHandler::AdvertizePacketL- Exit"));
+ }
+/*
+ * This is a callback function will be notified whenever a packet sent from this
+ * client is sent to the network.
+ * @param aError any error in sending the packet.
+ */
+void CAdvertizeHandler::OnPacketSendL(TInt aError)
+ {
+ __FLOG(_L8("CAdvertizeHandler::OnPacketSendL- Entry"));
+ if(aError != KErrNone)
+ {
+ MessageHandler().NotifyServicePublishL(iName,EFail,iSessionId);
+ }
+
+ if( iCurrentProbeState != EIdle)
+ {
+ After(KProbeDelay*1000);//Give more delay than this
+ return;
+ }
+ //When a service is published successfully ,iCurrentProbe state will be
+ //EIdle ,this state change will be used to notify the client .
+ MessageHandler().NotifyServicePublishL(iName,ESuccess,iSessionId);
+ __FLOG(_L8("CAdvertizeHandler::OnPacketSendL- Exit"));
+ }
+
+void CAdvertizeHandler::RunL()
+ {
+ __FLOG(_L8("CAdvertizeHandler::RunL- Entry"));
+ TTime currentTime;
+
+ if(iCurrentProbeState <= EProbeComplete)
+ {
+ if(DefensiveResponseL())
+ {
+ iCurrentProbeState = EStart;
+ if(iAutoResolveEnabled)
+ {
+ GenerateNonConflictingName();
+ if(iProbeCounter >= KMaxFailures)
+ {
+ //If Probe Failure rate is greater then 15 per second, wait for
+ //5 seconds before probing again
+ iProbeCounter = 0;
+ After(5*1000*1000);
+ }
+ }
+ else // to intimate server of failure
+ {
+ MessageHandler().NotifyServicePublishL(iName,EConflictWithoutAutoResolve,iSessionId);
+ }
+
+ }
+ }
+
+ switch(iCurrentProbeState)
+ {
+ case EIdle:
+ break;//Do Nothing
+
+ case EStart:
+ {
+ currentTime.UniversalTime();
+ TInt64 randseed = currentTime.Int64();
+
+ //Random time between 0 & 250 ms
+ TInt delay = Math::Rand(randseed) % 250;
+ iCurrentProbeState = EProbeFirstUnicast;
+ //Convert to microsecond
+
+ After(delay*1000);
+ }
+ break;
+
+ case EProbeFirstUnicast:
+ {
+ SendProbeL(ETrue);
+ iCurrentProbeState = EProbeSecondUnicast;
+ }
+ break;
+
+ case EProbeSecondUnicast:
+ {
+ SendProbeL(ETrue);
+ iCurrentProbeState = EProbeMulticast;
+ }
+ break;
+
+ case EProbeMulticast:
+ {
+ SendProbeL(EFalse);
+ iCurrentProbeState = EProbeComplete;
+ }
+ break;
+
+ case EProbeComplete:
+ {
+ iCurrentProbeState = EFirstAnnouncement;
+ //Probe succeeded ,insert in cache
+ InsertInCache();
+ After(KProbeDelay*1000);
+ //Some Delay ?? Required or defensive response HAS TO come within 750ms?
+ }
+ break;
+
+ case EFirstAnnouncement:
+ {
+ SendAnnouncementL();
+ iCurrentProbeState = ESecondAnnouncement;
+ //After(1000);// A Millisecond delay: Required??
+ }
+ break;
+
+ case ESecondAnnouncement:
+ {
+ SendAnnouncementL();
+ iCurrentProbeState = EIdle;
+ }
+ break;
+ }
+ __FLOG(_L8("CAdvertizeHandler::RunL- Exit"));
+ }
+/*
+ * Handles any leave in RunL
+ * @param aError error with which runL leaves.
+ */
+TInt CAdvertizeHandler::RunError(TInt aError)
+ {
+ __FLOG(_L8("CAdvertizeHandler::RunError- Entry"));
+ return aError;
+ }
+
+/*
+ * Self completes the request.
+ */
+void CAdvertizeHandler::Schedule()
+ {
+ __FLOG(_L8("CAdvertizeHandler::Schedule- Entry"));
+ TRequestStatus* status(&iStatus);
+ *status = KRequestPending;
+ SetActive();
+ User::RequestComplete(status, KErrNone);
+ __FLOG(_L8("CAdvertizeHandler::Schedule- Exit"));
+ }
+
+/*
+ * Function will be called when there is a conflict.
+ * this will change the publishing name by appending a
+ * number at the end of it.
+ * @return iProbeCounter returns probecounter value.
+ */
+TInt CAdvertizeHandler::GenerateNonConflictingName()
+ {
+ __FLOG(_L8("CAdvertizeHandler::GenerateNonConflictingName- Entry"));
+ _LIT8(KDot,".");
+
+ RBuf8 oldName;
+ oldName.CreateL(iName);
+
+ ++iProbeCounter;
+ TBuf8 <KMaxLength> newName;
+ iName.Close();
+ iName.Create(KMaxLength);
+ iName.Append(iProbeName);
+
+ TInt pos = iName.Locate('.');
+ _LIT8(KOpenBrace,"(");
+ newName.Append(KOpenBrace);
+ newName.AppendNum(iProbeCounter);
+ _LIT8(KCloseBrace,")");
+ newName.Append(KCloseBrace);
+ iName.Insert(pos,newName);
+ ChangeDomainL(oldName);
+ oldName.Close();
+ __FLOG(_L8("CAdvertizeHandler::GenerateNonConflictingName- Exit"));
+ return iProbeCounter;
+ }
+
+/*
+ * Finds whether the service already exists in the network .
+ * If service is in the network ,same will be present in the cache.
+ * @return probFailed returns true if probe has failed.
+ */
+TBool CAdvertizeHandler::DefensiveResponseL()
+ {
+ __FLOG(_L8("CAdvertizeHandler::DefensiveResponseL- Entry"));
+ TBool probeFailed(EFalse);
+ RPointerArray <CCacheEntry> entries;
+ CleanupStack::PushL(TCleanupItem(TCleanupOperation(&CleanUpCache),&entries));
+
+ _LIT8(KDot,".");
+ TBuf8 <KMaxLength> buffer;
+
+ buffer.Copy(iName);
+ buffer.Append(KDot);
+ MessageHandler().DnsCache().FindServiceL(entries,buffer,EDnsQType_Any);
+ if(entries.Count()>0)
+ {
+ probeFailed = ETrue;
+ }
+ CleanupStack::PopAndDestroy();
+ //entries.ResetAndDestroy();
+ //entries.Close();
+ __FLOG(_L8("CAdvertizeHandler::DefensiveResponseL- Exit"));
+ return probeFailed;
+ }
+
+/*
+ * creates a DnsMessage object and send it to the messagehandler to handle it.
+ * @param aUnicast true if the packet to be sent is an unicast one;false for multicast.
+ *
+ */
+void CAdvertizeHandler::SendProbeL(TBool aUnicast)
+ {
+ __FLOG(_L8("CAdvertizeHandler::SendProbeL- Entry"));
+ //Construct DNS Message
+ CDnsMessage* message = CDnsMessage::NewL(0,ETrue);
+ CleanupStack::PushL(message);
+
+ //Form the Query/Question part of the message
+ CDnsQuestion* question = CDnsQuestion::NewL();
+ CleanupStack::PushL(question);
+ question->SetNameL(iName);
+ question->SetClass(EDnsClass_IN);
+ question->SetType(EDnsQType_Any);
+ if(aUnicast)
+ {
+ question->SetUnicast(ETrue);
+ }
+
+ //Append the Query to the Message
+ message->AppendQueryL(question);
+ //Append to the Authoritative Section
+ for(TInt i =0 ; i < iData.Count();i++)
+ {
+ message->AppendAuthorityL(iData[i]->CloneL());
+ }
+
+ //Send the query
+ MessageHandler().SendQueryL(message,*this);
+
+ CleanupStack::Pop();//question
+ CleanupStack::Pop();//message
+ __FLOG(_L8("CAdvertizeHandler::SendProbeL- Exit"));
+ }
+
+/*
+ * If probing is successfull ,new service record will
+ * be added to the cache using this.
+ */
+void CAdvertizeHandler::InsertInCache()
+ {
+ __FLOG(_L8("CAdvertizeHandler::InsertInCache- Entry"));
+ TBuf8<KMaxLength> name;
+ _LIT8(KDot,".");
+ //TODO name should be appended with dot
+
+ for(TInt i =0 ; i<iData.Count();i++)
+ {
+ //Append a "." at the end of the name
+ name.Copy(iData[i]->Name());
+ name.Append(KDot);
+ iData[i]->SetNameL(name);
+ MessageHandler().DnsCache().UpdateCacheL(*(iData[i]),ETrue,iSessionId);
+ }
+ __FLOG(_L8("CAdvertizeHandler::InsertInCache- Exit"));
+ }
+
+/*
+ * Announces the new service.
+ */
+void CAdvertizeHandler::SendAnnouncementL()
+ {
+ __FLOG(_L8("CAdvertizeHandler::SendAnnouncementL- Entry"));
+ RPointerArray<CCacheEntry> entries;
+ //An API in Cache Interface that returns a list of all Authoritative records
+ MessageHandler().DnsCache().AuthoritativeEntriesL(entries);
+ CDnsMessage* message = CDnsMessage::NewL(0,EFalse);
+ CleanupStack::PushL(message);
+
+ TDnsHeader header(message->Header());
+ header.SetAuthoritative(ETrue);
+ message->SetHeader(header);
+
+ //Append to the Authoritative Section
+ for(TInt i =0 ; i < iData.Count();i++)
+ {
+ message->AppendAuthorityL(iData[i]->CloneL());
+ }
+
+/*
+ for(TInt index =0; index<entries.Count();index++)
+ {
+ CCacheEntry* entry = entries[index];
+ //Send Announcements for all the Services we have published, and entered in Cache
+
+
+ if(entry->AddressRecord())
+ message->AppendAnswerL(entry->AddressRecord()->CloneL());
+ if(entry->ServiceRecord())
+ message->AppendAnswerL(entry->ServiceRecord()->CloneL());
+ if(entry->PtrRecord())
+ message->AppendAnswerL(entry->PtrRecord()->CloneL());
+ if(entry->TxtRecord())
+ message->AppendAnswerL(entry->TxtRecord()->CloneL());
+
+ //should've been a new API sendresponse
+
+ }
+*/
+ MessageHandler().SendQueryL(message,*this);
+ CleanupStack::Pop();//message
+ entries.ResetAndDestroy();
+ entries.Close();
+ __FLOG(_L8("CAdvertizeHandler::SendAnnouncementL- Exit"));
+ }
+void CAdvertizeHandler::ChangeDomainL(TDesC8& aName)
+ {
+ for(TInt i =0 ; i<iData.Count();i++)
+ {
+ if(iData[i]->Name().Compare(aName) == 0)
+ {
+ iData[i]->SetNameL(iName);
+ }
+ if(iData[i]->Type()==EDnsType_PTR)
+ {
+ CRdTypePtr* ptr = static_cast<CRdTypePtr*>(iData[i]);
+ if(ptr->DomainName().Compare(aName) == 0)
+ {
+ ptr->SetDomainNameL(iName);
+ }
+
+ }
+
+ }
+ }