Committing ZeroConf for 10.1 to the FCL.
/*
* Copyright (c) 2010 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:
*
*/
#include "cmdnscachemanager.h"
#include "cserviceinfo.h"
#include "ccacheentry.h"
#include "dnsconstants.h"
using namespace HashInfo;
EXPORT_C CMDNSCacheManager* CMDNSCacheManager::NewL(TUint aMaxCacheEntries)
{
CMDNSCacheManager* self = CMDNSCacheManager::NewLC(aMaxCacheEntries);
CleanupStack::Pop(self);
return self;
}
EXPORT_C CMDNSCacheManager* CMDNSCacheManager::NewLC(TUint aMaxCacheEntries)
{
CMDNSCacheManager* self = new (ELeave)CMDNSCacheManager();
CleanupStack::PushL(self);
self->ConstructL(aMaxCacheEntries);
return self;
}
EXPORT_C CMDNSCacheManager* CMDNSCacheManager::NewL()
{
CMDNSCacheManager* self = new (ELeave)CMDNSCacheManager();
return self;
}
void CMDNSCacheManager::ConstructL(TUint aMaxCacheEntries)
{
iHashMap=CMDNSCacheMap::NewL(aMaxCacheEntries);
}
CMDNSCacheManager::CMDNSCacheManager()
{
}
CMDNSCacheManager::~CMDNSCacheManager()
{
delete iHashMap;
iAuthoritativeEntries.ResetAndDestroy();
iAuthoritativeEntries.Close();
}
/*Method to Insert / Update entries into Cache
* @param aEntry Record Entry to Insert
* @param aAuthoritative Flag to indicate whether the entry is Authoritative
* @param aSessionId To Store the Session Id for each entry
* @leave KErrNoMemory If Insert into Cache Failed because memory unavailability
* @leave KErrNotSupported if any record other than SRV, PTR, TXT ot A come
*/
EXPORT_C void CMDNSCacheManager::UpdateCacheL(CDnsResourceData& aEntry,TBool aAuthoritative,TUint32 aSessionId)
{
CDnsResourceData* resourceRecord = NULL;
CServiceInfo* foundEntry = NULL;
TBuf8<255> name;
_LIT8(KDot,".");
//Clone the entry to Insert in Cache
resourceRecord = aEntry.CloneL();
TUint16 recType(resourceRecord->Type());
if(recType == EDnsType_SRV || recType == EDnsType_TXT || recType == EDnsType_A || recType == EDnsType_PTR)
{
if(recType == EDnsType_PTR)
{
//Extract the Key- Service Instance Name
CRdTypePtr* ptrRecord = static_cast <CRdTypePtr*> (resourceRecord);
// before that insert the dot.
name.Copy(ptrRecord->DomainName());
if(name[name.Size()-1]!='.')
name.Append(KDot);
ptrRecord->SetDomainNameL(name);
foundEntry = iHashMap->Find(ptrRecord->DomainName());
}
else
{
//Extract the Key- Service Instance Name or Host Name
foundEntry = iHashMap->Find(resourceRecord->Name());
}
if(foundEntry)
{
//Update if the entry is already present in the Cache.
UpdateCacheEntry(foundEntry,resourceRecord);
}
else
{
//Entry not found in Cache,Insert it fresh
CServiceInfo* recordInfo = NULL;
recordInfo = CServiceInfo::NewL();
switch(recType)
{
case EDnsType_SRV:
CRdTypeSrv* srvRecord = static_cast <CRdTypeSrv*> (resourceRecord);
recordInfo->SetServiceRecord(srvRecord);
break;
case EDnsType_TXT:
CRdTypeTxt* txtRecord = static_cast <CRdTypeTxt*> (resourceRecord);
recordInfo->SetTxtRecord(txtRecord);
break;
case EDnsType_PTR:
CRdTypePtr* ptrRecord = static_cast <CRdTypePtr*> (resourceRecord);
recordInfo->SetPtrRecord(ptrRecord);
break;
case EDnsType_A:
CRdTypeA* addressRecord = static_cast <CRdTypeA*> (resourceRecord);
recordInfo->SetAddressRecord(addressRecord);
break;
default:
User::Leave(KErrNotSupported);
break;
}
recordInfo->SetAuthoritative(aAuthoritative);
recordInfo->SetSessionId(aSessionId);
// insert the entry
if(recType == EDnsType_PTR )
{
CRdTypePtr* ptrRecord = static_cast <CRdTypePtr*> (resourceRecord);
iHashMap->UpdateL(ptrRecord->DomainName(),recordInfo);
}
else
{
iHashMap->UpdateL(resourceRecord->Name(),recordInfo);
}
/*Maintain a list of all Services Published by us
(Authoritative records)*/
if(recordInfo->IsAuthoritative())
{
iAuthoritativeEntries.Append(recordInfo->CloneL());
}
}
}
else
{
User::Leave(KErrNotSupported);
}
}
/*Caters to finding varying types of records, for e.g:- find all the entries
that correspond to a particular service type or find the host name through the address record
@param aEntries List of entries that match the search constraint
@param aName could represent any search constraint Service Instance Type/ Name or the HostName
@param aType the desired record type
*/
EXPORT_C TInt CMDNSCacheManager::FindServiceL(RPointerArray <CCacheEntry> & aEntries,const TDesC8& aName,TDnsType aType)const
{
TInt error(KErrNotFound);
TPtrC8 keyToFind(aName);
TInt count;
switch(aType)
{
case EDnsType_A:
case EDnsType_SRV:
case EDnsType_TXT:
{
//Search for a specific CacheEntry
CServiceInfo* cacheEntry = iHashMap->Find(aName);
if(cacheEntry)
{
CCacheEntry* entry = CCacheEntry::NewL();
CacheEntryL(entry,cacheEntry);
aEntries.Append(entry);
error = KErrNone;
}
}
break;
case EDnsType_PTR:
//Match for all Cache Entries of the given Service Type
RPointerArray <const CServiceInfo> entries;
CleanupClosePushL(entries);
iHashMap->FindEntries(aName,entries);
for(count =0; count< entries.Count();count++)
{
if((*entries[count]).PtrRecord())
{
//The entries are considered only if they have PTR records
CCacheEntry* entry = CCacheEntry::NewL();
CacheEntryL(entry,entries[count]);
aEntries.Append(entry);
error = KErrNone;
}
}
CleanupStack::PopAndDestroy(&entries);
break;
case EDnsQType_Any:
{
//Search for a specific CacheEntry
CServiceInfo* cacheEntry = iHashMap->Find(aName);
if(cacheEntry)
{
CCacheEntry* entry = CCacheEntry::NewL();
CacheEntryL(entry,cacheEntry);
aEntries.Append(entry);
error = KErrNone;
}
else // may be its a PTR record
{
RPointerArray <const CServiceInfo> entries;
CleanupClosePushL(entries);
iHashMap->FindEntries(aName,entries);
for(count =0; count< entries.Count();count++)
{
if((*entries[count]).PtrRecord())
{
//The entries are considered only if they have PTR records
CCacheEntry* entry = CCacheEntry::NewL();
CacheEntryL(entry,entries[count]);
aEntries.Append(entry);
error = KErrNone;
}
}
CleanupStack::PopAndDestroy(&entries);
}
}
break;
default:
User::Leave(KErrNotSupported);
break;
}
return error;
}
/*Deletes the specified entry from the Cache
@param aServiceInstanceName Instance Name , whose entry needs to be deleted
@leave KErrNotFound if specified entry is not found
*/
EXPORT_C TInt CMDNSCacheManager::DeleteEntryL(const TDesC8& aServiceInstanceName)
{
TInt err = iHashMap->DeleteL(aServiceInstanceName);
// check if it also on the authoritative list, if so delete it
for(TInt i=0; i<iAuthoritativeEntries.Count();i++)
{
if(iAuthoritativeEntries[i]->Key().Compare(aServiceInstanceName)==0)
{
// found the entry, now delete it;
CServiceInfo* info = iAuthoritativeEntries[i];
iAuthoritativeEntries.Remove(i);
delete info;
}
}
return err;
}
EXPORT_C void CMDNSCacheManager::FlushCache()
{
iHashMap->DeleteAllEntries();
}
EXPORT_C CCacheEntry* CMDNSCacheManager::NextStaleEntry(TBool aActiveCacheMgmtEnabled,TBool aIteratorReset)
{
CServiceInfo* nextEntry = iHashMap->NextStaleEntry(aActiveCacheMgmtEnabled,aIteratorReset);
CCacheEntry* nextCacheEntry = NULL;
if(nextEntry)
{
nextCacheEntry = CCacheEntry::NewL();
//Construct CCacheEntry object
CacheEntryL(nextCacheEntry,nextEntry);
//Mark whether the entry has to be deleted or to be queried for (i.e., has exceeded 80%)
nextCacheEntry->SetEntryExpired(nextEntry->StaleEntry());
}
return nextCacheEntry;
}
void CMDNSCacheManager::UpdateCacheEntry(CServiceInfo* aEntry,CDnsResourceData* aRecordInfo)
{
TUint16 recType(aRecordInfo->Type());
switch(recType)
{
case EDnsType_SRV:
CRdTypeSrv* srvRecord = static_cast <CRdTypeSrv*> (aRecordInfo);
//Delete the previous Service Record and Insert the fresh one
delete aEntry->ServiceRecord();
aEntry->SetServiceRecord(srvRecord);
break;
case EDnsType_TXT:
CRdTypeTxt* txtRecord = static_cast <CRdTypeTxt*> (aRecordInfo);
//Delete the previous Text Record and Insert the fresh one
delete aEntry->TxtRecord();
aEntry->SetTxtRecord(txtRecord);
break;
case EDnsType_PTR:
CRdTypePtr* ptrRecord = static_cast <CRdTypePtr*> (aRecordInfo);
//Delete the previous Ptr Record and Insert the fresh one
delete aEntry->PtrRecord();
aEntry->SetPtrRecord(ptrRecord);
break;
case EDnsType_A:
CRdTypeA* addressRecord = static_cast <CRdTypeA*> (aRecordInfo);
//Delete the previous Address Record and Insert the fresh one
delete aEntry->AddressRecord();
aEntry->SetAddressRecord(addressRecord);
break;
default:
//Do nothing
break;
}
}
EXPORT_C void CMDNSCacheManager::DumpCacheL()
{
iHashMap->DumpCacheL();
}
EXPORT_C TUint32 CMDNSCacheManager::CacheEntryCount()
{
return iHashMap->NumberOfEntries();
}
void CMDNSCacheManager::CacheEntryL(CCacheEntry* aTargetEntry,const CServiceInfo* aSourceEntry)const
{
//Check whether the specific records existed before making a copy
if(aSourceEntry->PtrRecord())
{
aTargetEntry->SetPtrRecord(static_cast <CRdTypePtr*>( aSourceEntry->PtrRecord()->CloneL()));
}
if(aSourceEntry->AddressRecord())
{
//This case occurs only for an idividual Address Record
aTargetEntry->SetAddressRecord(static_cast <CRdTypeA*>(aSourceEntry->AddressRecord()->CloneL()));
}
if(aSourceEntry->ServiceRecord())
{
aTargetEntry->SetServiceRecord(static_cast <CRdTypeSrv*>(aSourceEntry->ServiceRecord()->CloneL()));
//Set Address Record ; if it exists
CServiceInfo* entry = iHashMap->Find(aTargetEntry->ServiceRecord()->Target());
if(entry)
{
aTargetEntry->SetAddressRecord(static_cast <CRdTypeA*>(entry->AddressRecord()->CloneL()));
}
}
if(aSourceEntry->TxtRecord())
{
aTargetEntry->SetTxtRecord(static_cast <CRdTypeTxt*>(aSourceEntry->TxtRecord()->CloneL()));
}
aTargetEntry->SetAuthoritative(aSourceEntry->IsAuthoritative());
aTargetEntry->SetSessionId(aSourceEntry->SessionId());
}
void CMDNSCacheManager::AuthoritativeEntriesL(RPointerArray <CCacheEntry>& aCacheEntries)
{
for(TInt index =0; index < iAuthoritativeEntries.Count();index++)
{
CCacheEntry* entry = CCacheEntry::NewL();
CacheEntryL(entry,iAuthoritativeEntries[index]);
aCacheEntries.Append(entry);
}
}
TUint CMDNSCacheManager::NumberOfEntries()
{
return iHashMap->NumberOfEntries();
}