zeroconf/server/src/cmdnsprobemanager.cpp
changeset 14 da856f45b798
--- /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"));
+	}
+
+