diff -r 78fbd574edf4 -r da856f45b798 zeroconf/server/src/cmdnsprobemanager.cpp --- /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 +__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 * records = static_cast < RPointerArray * > (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 entries; + + + //An API in Cache Interface that returns a list of all Authoritative records + iCache.AuthoritativeEntriesL(entries); + + for(TInt index =0; indexHeader()); + 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 entries; + CleanupStack::PushL(TCleanupItem(TCleanupOperation(&CleanUpCache),&entries)); + + _LIT8(KDot,"."); + TBuf8 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 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 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 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")); + } + +