--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/zeroconf/server/src/cmdnsprobemanager.cpp Thu Jun 24 19:09:47 2010 +0530
@@ -0,0 +1,561 @@
+// 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:
+// cmdnsprobemanager.cpp
+//
+//
+/**
+@file
+@internalTechnology
+*/
+//User include
+#include "e32math.h"
+#include "cmdnsprobemanager.h"
+//System include
+#include <mdns/ccacheentry.h>
+__FLOG_STMT(_LIT8(KComponent,"MDNSServer");)
+/*
+ * Two phase constructor
+ * @param aCache reference to cache
+ * @param aMessageHandler reference to message handler.
+ * @param aAutoresolveEnabled True if name conflict to be handled.
+ */
+CMDNSProbeManager* CMDNSProbeManager::NewL(MDNSCacheMgr& aCache,CMessageHandler& aMessageHandler,TBool aAutoResolveEnabled)
+ {
+ CMDNSProbeManager* self = CMDNSProbeManager::NewLC(aCache,aMessageHandler,aAutoResolveEnabled);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+static void CleanUpCache(TAny* aAny)
+ {
+ RPointerArray <CCacheEntry> * records = static_cast < RPointerArray <CCacheEntry>* > (aAny);
+ records->ResetAndDestroy();
+ records->Close();
+ }
+/*
+ * Two phase constructor
+ * @param aCache reference to cache
+ * @param aMessageHandler reference to message handler.
+ * @param aAutoresolveEnabled True if name conflict to be handled.
+ */
+CMDNSProbeManager* CMDNSProbeManager::NewLC(MDNSCacheMgr& aCache,CMessageHandler& aMessageHandler,TBool aAutoResolveEnabled)
+ {
+ CMDNSProbeManager* self = new (ELeave)CMDNSProbeManager(aCache,aMessageHandler,aAutoResolveEnabled);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+/*
+ * Constructor
+ */
+CMDNSProbeManager::CMDNSProbeManager(MDNSCacheMgr& aCache,CMessageHandler& aMessageHandler,TBool aAutoResolveEnabled)
+:CTimer(CActive::EPriorityStandard),iCache(aCache),iMessageHandler(aMessageHandler),iAutoResolveEnabled(aAutoResolveEnabled)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+/*
+ * Two phase Constructor
+ */
+void CMDNSProbeManager::ConstructL()
+ {
+ __FLOG_OPEN(KMDNSSubsystem, KComponent);
+ CTimer::ConstructL();
+ iCurrentProbeState = EIdle;
+ }
+/*
+ * Destructor
+ */
+CMDNSProbeManager::~CMDNSProbeManager()
+ {
+ __FLOG(_L8("CMDNSProbeManager::~CMDNSProbeManager - Entry"));
+ iName.Close();
+ iTarget.Close();
+ iProbeName.Close();
+ iProbeType.Close();
+ __FLOG(_L8("CMDNSProbeManager::~CMDNSProbeManager - Exit"));
+ __FLOG_CLOSE;
+ }
+
+/*
+ * State machine which probe send announcement and handle conflicts
+ * if autoresolve enabled.
+ */
+void CMDNSProbeManager::RunL()
+ {
+ __FLOG(_L8("CMDNSProbeManager::RunL - Entry"));
+ TTime currentTime;
+
+ if(iCurrentProbeState <= EProbeComplete)
+ {
+ if(DefensiveResponseL())
+ {
+ iCurrentProbeState = EStart;
+ if(iAutoResolveEnabled)
+ {
+ GenerateNonConflictingName();
+ }
+ // else { }// to intimate server of failure
+ 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);
+ }
+ }
+ }
+
+ 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();
+ iMessageHandler.Server().SetHostNameL(iName);
+ 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("CMDNSProbeManager::RunL - Exit"));
+ }
+
+/*
+ * Handles any leave from RunL
+ */
+TInt CMDNSProbeManager::RunError(TInt aError)
+ {
+ __FLOG(_L8("CMDNSProbeManager::RunError - Entry Exit"));
+ return aError;
+ }
+
+/*
+ * Probe host
+ * @param aUnicast True if unicast or else multicast.
+ */
+void CMDNSProbeManager::SendProbeL(TBool aUnicast)
+ {
+ __FLOG(_L8("CMDNSProbeManager::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);
+
+
+ //Form the Record to be filled in the Authoritative Field of the Query
+ switch(iType)
+ {
+ case EDnsType_A:
+ {
+ CRdTypeA* addRec = FormAddressRecordL();
+ //Append to the Authoritative Section
+ message->AppendAuthorityL(addRec);
+ }
+ break;
+
+ case EDnsType_SRV:
+ {
+ CRdTypeSrv* srvRec = FormServiceRecordL();
+ //Append to the Authoritative Section
+ message->AppendAuthorityL(srvRec);
+ }
+
+ break;
+ }
+ //Send the query
+ iMessageHandler.SendQueryL(message,*this);
+
+ CleanupStack::Pop();//question
+ CleanupStack::Pop();//message
+ __FLOG(_L8("CMDNSProbeManager::SendProbeL - Exit"));
+ }
+
+
+/*
+ * Send an announcement if probing is successfull.
+ */
+void CMDNSProbeManager::SendAnnouncementL()
+ {
+ __FLOG(_L8("CMDNSProbeManager::SendAnnouncementL - Entry"));
+ RPointerArray<CCacheEntry> entries;
+
+
+ //An API in Cache Interface that returns a list of all Authoritative records
+ iCache.AuthoritativeEntriesL(entries);
+
+ 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
+ CDnsMessage* message = CDnsMessage::NewL(0,EFalse);
+ CleanupStack::PushL(message);
+
+ TDnsHeader header(message->Header());
+ header.SetAuthoritative(ETrue);
+ message->SetHeader(header);
+
+ 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
+
+ iMessageHandler.SendQueryL(message,*this);
+
+ CleanupStack::Pop();//message
+ entries.ResetAndDestroy();
+ entries.Close();
+ }
+ __FLOG(_L8("CMDNSProbeManager::SendAnnouncementL - Exit"));
+ }
+
+/*
+ * Returns ture hostname exists in the cache.
+ * True means there is already a record in the network with the same name.
+ */
+TBool CMDNSProbeManager::DefensiveResponseL()
+ {
+ __FLOG(_L8("CMDNSProbeManager::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);
+
+ iCache.FindServiceL(entries,buffer,EDnsQType_Any);
+
+ if(entries.Count()>0)
+ {
+ probeFailed = ETrue;
+ }
+
+ CleanupStack::PopAndDestroy();
+ entries.ResetAndDestroy();
+ entries.Close();
+ __FLOG(_L8("CMDNSProbeManager::DefensiveResponseL - Exit"));
+ return probeFailed;
+ }
+
+TInt CMDNSProbeManager::StartNameProbeL(const TDesC8& aHostName,TInetAddr aAddr)
+ {
+ __FLOG(_L8("CMDNSProbeManager::StartNameProbeL - Entry"));
+ iName.Close();
+ iName.CreateL(aHostName);
+ iProbeName.Close();
+ iProbeName.CreateL(KMaxLength);
+ iProbeName.Append(iName);
+ iAddr = aAddr;
+ iCurrentProbeState = EStart;
+ iType = EDnsType_A;
+ iMessageHandler.SetStateHostProbing(ETrue);
+ Schedule();
+ __FLOG(_L8("CMDNSProbeManager::StartNameProbeL - Exit"));
+ return KErrNone;
+ }
+
+/*
+ * Start probing the service.
+ */
+TInt CMDNSProbeManager::StartServiceProbeL(const TDesC8& aServiceName,const TDesC8& aTargetMachine,TUint16 aPort)
+ {
+ __FLOG(_L8("CMDNSProbeManager::StartServiceProbeL - Entry"));
+ iName.Close();
+ iName.CreateL(aServiceName);
+
+ iTarget.Close();
+ iTarget.CreateL(aTargetMachine);
+
+ iPort = aPort;
+ iType = EDnsType_SRV;
+
+ iCurrentProbeState = EStart;
+
+ Schedule();
+ __FLOG(_L8("CMDNSProbeManager::StartServiceProbeL - Exit"));
+ return KErrNone;
+ }
+
+
+/*
+ * Callback method
+ * Will be notified on successfully sending a packet to the network .
+ * State will be EIdle when an address is successully announced twice.
+ */
+void CMDNSProbeManager::OnPacketSendL(TInt /*aError*/)
+ {
+ __FLOG(_L8("CMDNSProbeManager::OnPacketSendL - Entry"));
+ if( iCurrentProbeState != EIdle)
+ {
+ After(KProbeDelay*1000);//Give more delay than this
+ return;
+ }
+ iMessageHandler.SetStateHostProbing(EFalse);
+ __FLOG(_L8("CMDNSProbeManager::OnPacketSendL - Exit"));
+ }
+
+
+/*
+ * Create an address record
+ * @return returns an address record created.
+ */
+CRdTypeA* CMDNSProbeManager::FormAddressRecordL()
+ {
+ __FLOG(_L8("CMDNSProbeManager::FormAddressRecordL - Entry"));
+ CRdTypeA* addRec = CRdTypeA::NewL();
+ CleanupStack::PushL(addRec);
+
+ TInt dataLength(4);
+
+ addRec->SetNameL(iName);
+ addRec->SetType(EDnsType_A);
+ addRec->SetClass(EDnsClass_IN);
+ addRec->SetFlushBit(EFalse);
+ addRec->SetAddr(iAddr);
+ addRec->SetTtl(120);
+
+ CleanupStack::Pop();//addRec
+ __FLOG(_L8("CMDNSProbeManager::FormAddressRecordL - Exit"));
+ return addRec;
+ }
+
+/*
+ * Create a service record
+ * @return retrun the newly created service record.
+ */
+CRdTypeSrv* CMDNSProbeManager::FormServiceRecordL()
+ {
+ __FLOG(_L8("CMDNSProbeManager::FormServiceRecordL - Entry"));
+ CRdTypeSrv* srvRec = CRdTypeSrv::NewL();
+ CleanupStack::PushL(srvRec);
+
+ srvRec->SetClass(EDnsClass_IN);
+ srvRec->SetFlushBit(EFalse);
+ srvRec->SetNameL(iName);
+ srvRec->SetPort(iPort);
+ srvRec->SetPriority(/*Default Priority*/0 );
+ srvRec->SetTargetL(iTarget);
+ srvRec->SetTtl(120*60);
+ srvRec->SetType(EDnsType_SRV);
+ srvRec->SetWeight(/*Default Weight*/ 0);
+
+
+ CleanupStack::Pop();//srvRec
+ __FLOG(_L8("CMDNSProbeManager::FormServiceRecordL - Exit"));
+ return srvRec;
+ }
+
+void CMDNSProbeManager::InsertInCache()
+ {
+ __FLOG(_L8("CMDNSProbeManager::InsertInCache - Entry"));
+ TBuf8<KMaxLength> name;
+ _LIT8(KDot,".");
+
+ CDnsResourceData* data = NULL;
+
+ switch(iType)
+ {
+ case EDnsType_A:
+ {
+ data = FormAddressRecordL();
+ }
+ break;
+
+ case EDnsType_SRV:
+ {
+ data = FormServiceRecordL();
+ }
+ break;
+
+ }
+
+ //Append a "." at the end of the name
+ name.Copy(iName);
+ name.Append(KDot);
+ data->SetNameL(name);
+
+ iCache.UpdateCacheL(*data,ETrue,0/*session Id*/);
+
+ delete data;
+ __FLOG(_L8("CMDNSProbeManager::InsertInCache - Exit"));
+ }
+
+
+
+
+/*
+ * If autoresolve enable a non conflict name will be generated using this.
+ * @return returns the probecount.
+ */
+TInt CMDNSProbeManager::GenerateNonConflictingName()
+ {
+/*
+ __FLOG(_L8("CMDNSProbeManager::GenerateNonConflictingName - Entry"));
+ _LIT8(KDot,".");
+
+ if(iProbeCounter)
+ {
+ //From 2nd time, chop the last 3 characters
+ iProbeName.SetLength(iProbeName.Length() - 3);
+ }
+
+ ++iProbeCounter;
+
+ TBuf8 <KMaxLength> newName;
+ newName.Append(iProbeName);
+
+ _LIT8(KOpenBrace,"(");
+ newName.Append(KOpenBrace);
+
+ newName.AppendNum(iProbeCounter);
+
+ _LIT8(KCloseBrace,")");
+ newName.Append(KCloseBrace);
+
+ iProbeName.Close();
+ iProbeName.Create(KMaxNameLength);
+ iProbeName.Append(newName);
+
+ iName.Close();
+ iName.Create(KMaxLength);
+ iName.Append(iProbeName);
+
+ iName.Append(KDot);
+ iName.Append(iProbeType);
+
+ __FLOG(_L8("CMDNSProbeManager::GenerateNonConflictingName - Exit"));
+ return iProbeCounter;
+*/
+ //-------------------------------------------------------
+ __FLOG(_L8("CMDNSProbeManager::GenerateNonConflictingName- Entry"));
+ _LIT8(KDot,".");
+
+ ++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(iName);
+
+ __FLOG(_L8("CMDNSProbeManager::GenerateNonConflictingName- Exit"));
+ return iProbeCounter;
+
+
+
+
+
+ }
+
+/*
+ * Self complete the request.
+ */
+
+void CMDNSProbeManager::Schedule()
+ {
+ __FLOG(_L8("CMDNSProbeManager::Schedule - Entry"));
+ TRequestStatus* status(&iStatus);
+ *status = KRequestPending;
+ SetActive();
+ User::RequestComplete(status, KErrNone);
+ __FLOG(_L8("CMDNSProbeManager::Schedule - Exit"));
+ }
+
+