zeroconf/server/src/cadvertizehandler.cpp
changeset 14 da856f45b798
equal deleted inserted replaced
12:78fbd574edf4 14:da856f45b798
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // cadvertizehandler.cpp
       
    15 // 
       
    16 //
       
    17 /**
       
    18 @file
       
    19 @internalTechnology
       
    20 */
       
    21 //System include 
       
    22 #include <mdns/ccacheentry.h>
       
    23 
       
    24 //UserInclude
       
    25 #include "cadvertizehandler.h"
       
    26 __FLOG_STMT(_LIT8(KComponent,"MDNSServer");)
       
    27 
       
    28 /*
       
    29  * Two phase constructor
       
    30  * @param aMessagHandler areference to messagehandler object.
       
    31  * @param aAutoResolveEnabled If true sercice name conflict will be handled.
       
    32  * aAutoResolveEnabled is True by default
       
    33  */
       
    34 CAdvertizeHandler* CAdvertizeHandler::NewL(CMessageHandler& aMessageHandler,TBool aAutoResolveEnabled)
       
    35 	{
       
    36 	CAdvertizeHandler* self = new (ELeave) CAdvertizeHandler(aMessageHandler,aAutoResolveEnabled);
       
    37 	CleanupStack::PushL(self);
       
    38 	self->ConstructL();
       
    39 	CleanupStack::Pop();
       
    40 	return self;
       
    41 	}
       
    42 	
       
    43 /*
       
    44  * Destructor
       
    45  */
       
    46 CAdvertizeHandler::~CAdvertizeHandler()
       
    47 	{
       
    48 	__FLOG(_L8("CAdvertizeHandler::~CAdvertizeHandler- Entry"));
       
    49 	iData.ResetAndDestroy();
       
    50 	iData.Close();
       
    51 	iName.Close();
       
    52 	iProbeName.Close();
       
    53 	iProbeType.Close();
       
    54 	__FLOG(_L8("CAdvertizeHandler::~CAdvertizeHandler- Exit"));
       
    55 	__FLOG_CLOSE;
       
    56 	}
       
    57 /*
       
    58  * No incoming packet for this so no need to handle
       
    59  */	
       
    60 void CAdvertizeHandler::HandleIncomingPacketL(CDnsMessage& /*aMessage*/)
       
    61 	{
       
    62 	__FLOG(_L8("CAdvertizeHandler::HandleIncomingPacketL- Entry"));
       
    63 	//Nothing To Do ............
       
    64 	__FLOG(_L8("CAdvertizeHandler::HandleIncomingPacketL- Exit"));
       
    65 	}
       
    66 	
       
    67 static void CleanUpCache(TAny* aAny)
       
    68     {
       
    69     
       
    70     //RPointerArray <CCacheEntry>  records = static_cast < RPointerArray <CCacheEntry> > (*aAny);
       
    71     RPointerArray <CCacheEntry>*  records = static_cast < RPointerArray <CCacheEntry> *> (aAny);
       
    72     records->ResetAndDestroy();
       
    73     records->Close();
       
    74     }
       
    75 /*
       
    76  * Constructor
       
    77  * @param aMessageHandler reference to messagehandler
       
    78  * @param aAutoResolveEnabled will be true by default ,if true servicename conflict
       
    79  * will be handled by default
       
    80  */
       
    81 CAdvertizeHandler::CAdvertizeHandler(CMessageHandler& aMessageHandler,TBool aAutoResolveEnabled):CBaseHandler(aMessageHandler)
       
    82 	{
       
    83 	__FLOG(_L8("CAdvertizeHandler::CAdvertizeHandler- Entry"));
       
    84 	iAutoResolveEnabled = aAutoResolveEnabled;
       
    85 	iCurrentProbeState = EIdle;
       
    86 	iProbeCounter = 0 ;
       
    87 	__FLOG(_L8("CAdvertizeHandler::CAdvertizeHandler- Exit"));
       
    88 	}
       
    89 	
       
    90 /*
       
    91  * Twophase constructor
       
    92  */
       
    93 void CAdvertizeHandler::ConstructL()
       
    94 	{
       
    95 	__FLOG_OPEN(KMDNSSubsystem, KComponent);
       
    96 	__FLOG(_L8("CAdvertizeHandler::ConstructL- Entry"));
       
    97 	CBaseHandler::ConstructL();
       
    98 	//Nothing 
       
    99 	__FLOG(_L8("CAdvertizeHandler::ConstructL- Exit"));
       
   100 	}
       
   101 /*
       
   102  * Keeps a copy of the records to be published and starts the active object.
       
   103  * @param aData an array of records to be published.
       
   104  * @param aSessionId session id initiating the advertizement.
       
   105  */
       
   106 void CAdvertizeHandler::AdvertizePacketL(const RPointerArray<CDnsResourceData> aData, TInt aSessionId,TBool aIsUpdate)
       
   107     {
       
   108     __FLOG(_L8("CAdvertizeHandler::AdvertizePacketL- Entry"));
       
   109     iName.Close();
       
   110     iName.Create(aData[0]->Name());
       
   111     iProbeName.Close();
       
   112     iProbeName.CreateL(KMaxLength);
       
   113     iProbeName.Append(iName);
       
   114     iCurrentProbeState = EStart;
       
   115     iData.ResetAndDestroy();
       
   116     for(TInt i =0 ; i<aData.Count();i++)
       
   117         {
       
   118         iData.AppendL(aData[i]);
       
   119         }
       
   120      // assign the session id so that, we can send bye-bye packet when the session is closed
       
   121     iSessionId = aSessionId;
       
   122     if(aIsUpdate)
       
   123         {
       
   124         iCurrentProbeState = EIdle;
       
   125         TBool isExist = DefensiveResponseL();
       
   126         if(!isExist)
       
   127             {
       
   128             User::Leave(KErrNotFound);
       
   129             }
       
   130         SendAnnouncementL();
       
   131         InsertInCache();
       
   132         return;
       
   133         }
       
   134     Schedule();
       
   135     __FLOG(_L8("CAdvertizeHandler::AdvertizePacketL- Exit"));
       
   136     }
       
   137 /*
       
   138  * This is a callback function will be notified whenever a packet sent from this
       
   139  * client is sent to the network.
       
   140  * @param aError any error in sending the packet.
       
   141  */
       
   142 void CAdvertizeHandler::OnPacketSendL(TInt aError)
       
   143     {
       
   144     __FLOG(_L8("CAdvertizeHandler::OnPacketSendL- Entry"));
       
   145     if(aError != KErrNone)
       
   146         {
       
   147         MessageHandler().NotifyServicePublishL(iName,EFail,iSessionId);
       
   148         }
       
   149     
       
   150     if( iCurrentProbeState != EIdle)
       
   151             {
       
   152             After(KProbeDelay*1000);//Give more delay than this
       
   153             return;
       
   154             }
       
   155     //When a service is published successfully ,iCurrentProbe state will be 
       
   156     //EIdle ,this state change will be used to notify the client .
       
   157     MessageHandler().NotifyServicePublishL(iName,ESuccess,iSessionId);
       
   158     __FLOG(_L8("CAdvertizeHandler::OnPacketSendL- Exit"));
       
   159     }
       
   160 
       
   161 void CAdvertizeHandler::RunL()
       
   162     {    
       
   163     __FLOG(_L8("CAdvertizeHandler::RunL- Entry"));
       
   164     TTime currentTime;
       
   165 
       
   166     if(iCurrentProbeState <= EProbeComplete)
       
   167         {
       
   168         if(DefensiveResponseL())
       
   169             {       
       
   170             iCurrentProbeState = EStart;                
       
   171             if(iAutoResolveEnabled)
       
   172                 {
       
   173                 GenerateNonConflictingName(); 
       
   174                 if(iProbeCounter >= KMaxFailures)
       
   175                     {
       
   176                     //If Probe Failure rate is greater then 15 per second, wait for 
       
   177                     //5 seconds before probing again
       
   178                     iProbeCounter = 0;
       
   179                     After(5*1000*1000);             
       
   180                     }
       
   181                 }       
       
   182               else //  to intimate server of failure
       
   183                   {
       
   184                   MessageHandler().NotifyServicePublishL(iName,EConflictWithoutAutoResolve,iSessionId);
       
   185                   }
       
   186             
       
   187             }       
       
   188         }
       
   189 
       
   190     switch(iCurrentProbeState)
       
   191         {       
       
   192         case EIdle:
       
   193         break;//Do Nothing
       
   194     
       
   195         case EStart:
       
   196             {
       
   197             currentTime.UniversalTime();
       
   198             TInt64 randseed = currentTime.Int64();                  
       
   199     
       
   200             //Random time between 0 & 250 ms
       
   201             TInt delay = Math::Rand(randseed) % 250;
       
   202             iCurrentProbeState = EProbeFirstUnicast;
       
   203             //Convert to microsecond
       
   204     
       
   205             After(delay*1000);          
       
   206             }               
       
   207             break;
       
   208     
       
   209         case EProbeFirstUnicast:
       
   210             {
       
   211             SendProbeL(ETrue);  
       
   212             iCurrentProbeState = EProbeSecondUnicast;                           
       
   213             }
       
   214             break;
       
   215     
       
   216         case EProbeSecondUnicast:
       
   217             {               
       
   218             SendProbeL(ETrue);  
       
   219             iCurrentProbeState = EProbeMulticast;                                       
       
   220             }
       
   221             break;      
       
   222     
       
   223         case EProbeMulticast:
       
   224             {
       
   225             SendProbeL(EFalse); 
       
   226             iCurrentProbeState = EProbeComplete;            
       
   227             }
       
   228             break;
       
   229     
       
   230         case EProbeComplete:
       
   231             {
       
   232             iCurrentProbeState = EFirstAnnouncement;
       
   233             //Probe succeeded ,insert in cache 
       
   234             InsertInCache();    
       
   235             After(KProbeDelay*1000);
       
   236             //Some Delay ?? Required or defensive response HAS TO come within 750ms?
       
   237             }
       
   238             break;
       
   239     
       
   240         case EFirstAnnouncement:
       
   241             {
       
   242             SendAnnouncementL();
       
   243             iCurrentProbeState = ESecondAnnouncement;
       
   244             //After(1000);// A Millisecond delay: Required??    
       
   245             }
       
   246             break;
       
   247     
       
   248         case ESecondAnnouncement:
       
   249             {
       
   250             SendAnnouncementL();
       
   251             iCurrentProbeState = EIdle;
       
   252             }
       
   253             break;  
       
   254         }
       
   255     __FLOG(_L8("CAdvertizeHandler::RunL- Exit"));
       
   256     }
       
   257 /*
       
   258  * Handles any leave in RunL
       
   259  * @param aError error with which runL leaves.
       
   260  */
       
   261 TInt CAdvertizeHandler::RunError(TInt aError)
       
   262     {
       
   263     __FLOG(_L8("CAdvertizeHandler::RunError- Entry"));
       
   264     return aError;
       
   265     }
       
   266 
       
   267 /*
       
   268  * Self completes the request.
       
   269  */
       
   270 void CAdvertizeHandler::Schedule()
       
   271     {
       
   272     __FLOG(_L8("CAdvertizeHandler::Schedule- Entry"));
       
   273     TRequestStatus* status(&iStatus);
       
   274     *status = KRequestPending;
       
   275     SetActive();
       
   276     User::RequestComplete(status, KErrNone);
       
   277     __FLOG(_L8("CAdvertizeHandler::Schedule- Exit"));
       
   278     }
       
   279 
       
   280 /*
       
   281  * Function will be called when there is a conflict.
       
   282  * this will change the publishing name by appending a 
       
   283  * number at the end of it. 
       
   284  * @return iProbeCounter returns probecounter value.
       
   285  */
       
   286 TInt CAdvertizeHandler::GenerateNonConflictingName()
       
   287     {
       
   288     __FLOG(_L8("CAdvertizeHandler::GenerateNonConflictingName- Entry"));
       
   289     _LIT8(KDot,".");
       
   290 
       
   291         RBuf8 oldName;
       
   292         oldName.CreateL(iName);
       
   293         
       
   294         ++iProbeCounter;
       
   295         TBuf8 <KMaxLength> newName;
       
   296         iName.Close();  
       
   297         iName.Create(KMaxLength);
       
   298         iName.Append(iProbeName);
       
   299         
       
   300         TInt pos = iName.Locate('.');
       
   301         _LIT8(KOpenBrace,"(");
       
   302         newName.Append(KOpenBrace);
       
   303         newName.AppendNum(iProbeCounter);
       
   304         _LIT8(KCloseBrace,")");
       
   305         newName.Append(KCloseBrace);
       
   306         iName.Insert(pos,newName); 
       
   307         ChangeDomainL(oldName);
       
   308         oldName.Close();
       
   309         __FLOG(_L8("CAdvertizeHandler::GenerateNonConflictingName- Exit"));
       
   310         return iProbeCounter;
       
   311     }
       
   312 
       
   313 /*
       
   314  * Finds whether the service already exists in the network .
       
   315  * If service is in the network ,same will be present in the cache.
       
   316  * @return probFailed returns true if probe has failed.
       
   317  */
       
   318 TBool CAdvertizeHandler::DefensiveResponseL()
       
   319     {
       
   320     __FLOG(_L8("CAdvertizeHandler::DefensiveResponseL- Entry"));
       
   321     TBool probeFailed(EFalse);      
       
   322     RPointerArray <CCacheEntry> entries;
       
   323     CleanupStack::PushL(TCleanupItem(TCleanupOperation(&CleanUpCache),&entries));
       
   324             
       
   325      _LIT8(KDot,".");
       
   326      TBuf8 <KMaxLength> buffer;  
       
   327         
       
   328      buffer.Copy(iName);
       
   329      buffer.Append(KDot);
       
   330      MessageHandler().DnsCache().FindServiceL(entries,buffer,EDnsQType_Any);   
       
   331      if(entries.Count()>0)
       
   332         {
       
   333         probeFailed = ETrue;
       
   334         }
       
   335      CleanupStack::PopAndDestroy();	
       
   336      //entries.ResetAndDestroy();
       
   337      //entries.Close();
       
   338      __FLOG(_L8("CAdvertizeHandler::DefensiveResponseL- Exit"));
       
   339      return probeFailed;
       
   340     }
       
   341 
       
   342 /*
       
   343  * creates a DnsMessage object and send it to the messagehandler to handle it.
       
   344  * @param aUnicast true if the packet to be sent is an unicast one;false for multicast.
       
   345  * 
       
   346  */
       
   347 void CAdvertizeHandler::SendProbeL(TBool aUnicast)
       
   348     {
       
   349     __FLOG(_L8("CAdvertizeHandler::SendProbeL- Entry"));
       
   350     //Construct DNS Message
       
   351     CDnsMessage* message = CDnsMessage::NewL(0,ETrue);
       
   352     CleanupStack::PushL(message);
       
   353 
       
   354     //Form the Query/Question part of the message
       
   355     CDnsQuestion* question = CDnsQuestion::NewL();
       
   356     CleanupStack::PushL(question);
       
   357     question->SetNameL(iName);
       
   358     question->SetClass(EDnsClass_IN);
       
   359     question->SetType(EDnsQType_Any);
       
   360     if(aUnicast)
       
   361         {
       
   362         question->SetUnicast(ETrue);
       
   363         }
       
   364 
       
   365     //Append the Query to the Message
       
   366     message->AppendQueryL(question);
       
   367     //Append to the Authoritative Section
       
   368     for(TInt i =0 ; i < iData.Count();i++)
       
   369         {
       
   370         message->AppendAuthorityL(iData[i]->CloneL());
       
   371         }
       
   372          
       
   373     //Send the query
       
   374     MessageHandler().SendQueryL(message,*this);
       
   375 
       
   376     CleanupStack::Pop();//question
       
   377     CleanupStack::Pop();//message
       
   378     __FLOG(_L8("CAdvertizeHandler::SendProbeL- Exit"));
       
   379     }
       
   380 
       
   381 /*
       
   382  * If probing is successfull ,new service record will 
       
   383  * be added to the cache using this.
       
   384  */
       
   385 void CAdvertizeHandler::InsertInCache()
       
   386     {
       
   387     __FLOG(_L8("CAdvertizeHandler::InsertInCache- Entry"));
       
   388     TBuf8<KMaxLength> name;
       
   389     _LIT8(KDot,".");
       
   390     //TODO name should be appended with dot
       
   391     
       
   392     for(TInt i =0 ; i<iData.Count();i++)
       
   393         {
       
   394         //Append  a "." at the end of the name
       
   395        name.Copy(iData[i]->Name());
       
   396        name.Append(KDot);  
       
   397        iData[i]->SetNameL(name);
       
   398        MessageHandler().DnsCache().UpdateCacheL(*(iData[i]),ETrue,iSessionId);
       
   399         }
       
   400     __FLOG(_L8("CAdvertizeHandler::InsertInCache- Exit"));   
       
   401     }
       
   402 
       
   403 /*
       
   404  * Announces the new service.
       
   405  */
       
   406 void CAdvertizeHandler::SendAnnouncementL()
       
   407     {
       
   408     __FLOG(_L8("CAdvertizeHandler::SendAnnouncementL- Entry"));
       
   409     RPointerArray<CCacheEntry> entries;
       
   410     //An API in Cache Interface that returns a list of all Authoritative records
       
   411     MessageHandler().DnsCache().AuthoritativeEntriesL(entries);
       
   412     CDnsMessage* message = CDnsMessage::NewL(0,EFalse);
       
   413     CleanupStack::PushL(message);  
       
   414     
       
   415     TDnsHeader header(message->Header());
       
   416     header.SetAuthoritative(ETrue);
       
   417     message->SetHeader(header);
       
   418 
       
   419     //Append to the Authoritative Section
       
   420     for(TInt i =0 ; i < iData.Count();i++)
       
   421         {
       
   422         message->AppendAuthorityL(iData[i]->CloneL());
       
   423         }
       
   424              
       
   425 /*    
       
   426     for(TInt index =0; index<entries.Count();index++)
       
   427         {
       
   428         CCacheEntry* entry = entries[index];
       
   429         //Send Announcements for all the Services we have published, and entered in Cache           
       
   430             
       
   431 
       
   432         if(entry->AddressRecord())
       
   433             message->AppendAnswerL(entry->AddressRecord()->CloneL());
       
   434         if(entry->ServiceRecord())
       
   435             message->AppendAnswerL(entry->ServiceRecord()->CloneL());
       
   436         if(entry->PtrRecord())
       
   437             message->AppendAnswerL(entry->PtrRecord()->CloneL());
       
   438         if(entry->TxtRecord())
       
   439             message->AppendAnswerL(entry->TxtRecord()->CloneL());
       
   440                
       
   441         //should've been a new API sendresponse
       
   442                   
       
   443         }
       
   444 */        
       
   445     MessageHandler().SendQueryL(message,*this);
       
   446     CleanupStack::Pop();//message
       
   447     entries.ResetAndDestroy();
       
   448     entries.Close();
       
   449     __FLOG(_L8("CAdvertizeHandler::SendAnnouncementL- Exit"));
       
   450     }
       
   451 void CAdvertizeHandler::ChangeDomainL(TDesC8& aName)
       
   452     {
       
   453     for(TInt i =0 ; i<iData.Count();i++)
       
   454         {
       
   455         if(iData[i]->Name().Compare(aName) == 0)
       
   456             {
       
   457             iData[i]->SetNameL(iName);
       
   458             }
       
   459         if(iData[i]->Type()==EDnsType_PTR)
       
   460             {
       
   461             CRdTypePtr* ptr = static_cast<CRdTypePtr*>(iData[i]);
       
   462             if(ptr->DomainName().Compare(aName) == 0)
       
   463                 {
       
   464                 ptr->SetDomainNameL(iName);
       
   465                 }
       
   466             
       
   467             }
       
   468         
       
   469         }
       
   470     }