1: 
   2: 
   3: /**********************
   4: *                     *
   5: *  COMPILER INCLUDES  *
   6: *                     *
   7: **********************/
   8: 
   9: 
  10: #include <cassert> 
  11: 
  12: 
  13: /*********************
  14: *                    *
  15: *  PROJECT INCLUDES  *
  16: *                    *
  17: *********************/
  18: 
  19: 
  20: #include "mind.h" 
  21: #include "loghandle.h" 
  22: #include "rdata_name.h" 
  23: #include "rrcache.h" 
  24: #include "rrfactory.h" 
  25: #include "watchptr.h" 
  26: #include "wwwi/mutexholder.h" 
  27: #include "wwwi/rwlocker.h" 
  28: 
  29: 
  30: using WWWI::MutexHolder;
  31: using WWWI::RWLocker;
  32: 
  33: 
  34: /************************
  35: *                       *
  36: *  RRCACHE CONSTRUCTOR  *
  37: *                       *
  38: ************************/
  39: 
  40: 
  41: RRCache::RRCache() {
  42:   m_uEntries = 0;
  43:   m_uMaxEntries = 100000;
  44: }
  45: 
  46: 
  47: /****************
  48: *               *
  49: *  METHODS ADD  *
  50: *               *
  51: ****************/
  52: 
  53: 
  54: bool RRCache::Add(RRConstPtr ci_rrp) {
  55:   RWLocker rk(&m_rw,true);
  56:   LogHandle lh(LF_CACHE,LY_DEBUG);
  57:   assert(ci_rrp!=NULL);
  58:   lh << "cache add " << *ci_rrp << endl; lh();
  59:   CacheRRListPtr csp = this->GetNameList(ci_rrp->GetName(),true);
  60:   CacheRRPtr crpNew = RRFactory::NewCacheRR(ci_rrp);
  61:   return this->Add(csp,crpNew);
  62: }
  63: 
  64: 
  65: bool RRCache::Add(CacheRRListPtr io_csp, CacheRRPtr &i_crpr) {
  66:   LogHandle lh(LF_CACHE,LY_DEBUG);
  67:   CacheRRList::iterator c_crpi;
  68: 
  69:   for(c_crpi=io_csp->begin();c_crpi!=io_csp->end();++c_crpi) {
  70:     if ((*c_crpi)->Compare(i_crpr)==true) {
  71:       // Duplicate.  Update Expire and bail.
  72:       (*c_crpi)->SetTTL(i_crpr->GetTTL());
  73:       lh << "cache update " << *i_crpr << endl;
  74:       SoftDelete(i_crpr);
  75:       i_crpr = NULL;
  76:       return false;
  77:     } else {
  78:       lh << LY_EXTRA_DEBUG << "cache sibling " << **c_crpi << endl; lh();
  79:     }
  80:   }
  81:   
  82:   lh << "cache insert " << *i_crpr;
  83:   io_csp->push_back(i_crpr);
  84:   i_crpr = NULL;
  85:   m_uEntries++;
  86:   lh << " (" << io_csp->size() << "/" << m_uEntries << " entries)" <<  endl;
  87:   if(m_uEntries>m_uMaxEntries) {
  88:     lh << LY_INFO << "cache size of " << m_uEntries << " exceeds ceiling of " << m_uMaxEntries << " (requesting expire)" << endl;  lh();
  89:     this->SetNextExpire(0);
  90:   }
  91:   return true;
  92: }
  93: 
  94: 
  95: void RRCache::Add(ResponseConstPtr ci_rsp) {
  96:   assert(ci_rsp!=NULL);
  97:   if (ci_rsp==NULL) return;
  98:   this->Add(ci_rsp->GetANList());
  99:   this->Add(ci_rsp->GetNSList());
 100:   this->Add(ci_rsp->GetARList());
 101: }
 102: 
 103: 
 104: void RRCache::Add(RRListConstPtr i_rrListPtr) {
 105:   if (i_rrListPtr==NULL) return;
 106:   RRList::const_iterator it;
 107:   for(it=i_rrListPtr->begin();it!=i_rrListPtr->end();++it) {
 108:     this->Add(*it);
 109:   }
 110: }
 111: 
 112: 
 113: /*********************
 114: *                    *
 115: *  METHOD ADDRECORD  *
 116: *                    *
 117: *********************/
 118: 
 119: 
 120: bool RRCache::AddRecord(const char *i_strName, RRType i_ty, RRClass i_cl, unsigned i_uTTL, const char *i_strRData) {
 121:   LabelListPtr llpName = new LabelList(i_strName);
 122:   bool bOut = this->AddRecord(llpName,i_ty,i_cl,i_uTTL,i_strRData);
 123:   SoftDelete(llpName);
 124:   return bOut;
 125: }
 126: 
 127: 
 128: bool RRCache::AddRecord(LabelListConstPtr i_llpName, RRType i_ty, RRClass i_cl, unsigned i_uTTL, const char *i_strRData) {
 129:   CacheRRPtr crp;
 130: 
 131:   CacheRRListPtr csp = this->GetNameList(i_llpName,true);
 132:   crp = RRFactory::NewCacheRR(i_ty,i_cl,i_uTTL,i_strRData);
 133:   return this->Add(csp,crp);
 134: }  
 135: 
 136: 
 137: /*************************
 138: *                        *
 139: *  METHOD ADDROOTSERVER  *
 140: *                        *
 141: *************************/
 142: 
 143: 
 144: void RRCache::AddRootServer(const char *i_strName, const char *i_strIP) {
 145:   LabelListPtr llp = new LabelList(i_strName);
 146:   CacheRRPtr crp;
 147: 
 148:   crp = RRFactory::NewCacheRR(TY_A,CL_IN,1000000,i_strIP);
 149:   this->GetNameList(llp,true)->push_back(crp);
 150:   crp = RRFactory::NewCacheRR(TY_NS,CL_IN,1000000,i_strName);
 151:   m_cn.cspEntries->push_back(crp);
 152:   SoftDelete(llp);
 153: }
 154: 
 155: 
 156: /******************
 157: *                 *
 158: *  METHOD EXPIRE  *
 159: *                 *
 160: ******************/
 161: 
 162: 
 163: void RRCache::Expire() {
 164:   RWLocker rk(&m_rw,true);
 165:   LogHandle lh(LF_CEXPIRE,LY_INFO);
 166:   time_t tmNextExpire;
 167:   time_t tmNow;
 168: 
 169:   tmNow = time(NULL); 
 170:   tmNextExpire = tmNow + 600;
 171:   lh << "expire time pass begins with " << m_uEntries << " entries." << endl; lh();
 172:   m_uEntries -= m_cn.Expire(tmNow,tmNextExpire);
 173:   lh << "expire time pass finishes with " << m_uEntries << " entries." << endl; 
 174:   while (m_uEntries>m_uMaxEntries) {
 175:     tmNow = tmNextExpire + 60;
 176:     tmNextExpire = tmNow + 1000000;
 177:     lh << "expire space pass begins with " << m_uEntries << " entries." << endl; lh();
 178:     m_uEntries -= m_cn.Expire(tmNow,tmNextExpire);
 179:     lh << "expire space pass finishes with " << m_uEntries << " entries." << endl; 
 180:   } 
 181:   lh << "expire again in " << tmNextExpire-time(NULL) << " seconds." << endl;
 182:   this->SetNextExpire(tmNextExpire);
 183: }
 184: 
 185: 
 186: unsigned CacheNode::Expire(time_t i_tmNow, time_t &io_tmrNextExpire) {
 187:   CacheMap::iterator cmi;
 188:   unsigned uReaped = 0;
 189:   LogHandle lh(LF_CEXPIRE,LY_DEBUG);
 190: 
 191:   uReaped = cspEntries->Expire(i_tmNow,io_tmrNextExpire);
 192:   for(cmi=cmTree.begin(); cmi!=cmTree.end(); ++cmi) {
 193:     lh << LY_EXTRA_DEBUG << "expiring at " << (*cmi).first; lh();
 194:     uReaped += (*cmi).second->Expire(i_tmNow,io_tmrNextExpire);
 195:   }
 196:   return uReaped;
 197: }
 198: 
 199: 
 200: /****************
 201: *               *
 202: *  METHODS GET  *
 203: *               *
 204: ****************/
 205: 
 206: 
 207: ResponsePtr RRCache::Get(LabelListConstPtr i_llpName, RRType i_ty, RRClass i_cl) {
 208:   RRListPtr rlpAN = NULL;
 209:   RRListPtr rlpNS = NULL;
 210:   RRListPtr rlpAR = NULL;
 211:   WatchPtr<RRListPtr> watchAN(rlpAN);
 212:   WatchPtr<RRListPtr> watchAR(rlpAR);
 213:   WatchPtr<RRListPtr> watchNS(rlpNS);
 214: 
 215:   // STUB: TY_QAXFR, TY_QMAILA and TY_QMAILB are not implemented.
 216:   assert(i_ty!=TY_QAXFR);
 217:   assert(i_ty!=TY_QMAILB);
 218:   assert(i_ty!=TY_QMAILA);
 219: 
 220:   {
 221:     RWLocker rk(&m_rw,false);
 222:     rlpAN = this->GetSimple(i_llpName,i_ty,i_cl);
 223:   }
 224:   if (rlpAN==NULL) return NULL;
 225:   rlpNS = this->GetNS(rlpAN);
 226:   rlpAR = this->GetAR(rlpNS);
 227:   ResponsePtr rspOut = new Response(false,false,RCODE_NOERROR,rlpAN,rlpNS,rlpAR);
 228:   watchAN.Release();
 229:   watchNS.Release();
 230:   return rspOut;
 231: }
 232: 
 233: 
 234: /****************************
 235: *                           *
 236: *  METHOD GETBESTAUTHORITY  *
 237: *                           *
 238: ****************************/
 239: 
 240: 
 241: RRListPtr RRCache::GetBestAuthority(LabelListConstPtr ci_llp) const {
 242:   RRListPtr rlpOut = new RRList;
 243:   this->GetNS(rlpOut,ci_llp);
 244:   return rlpOut;
 245: }
 246: 
 247: 
 248: /***********************
 249: *                      *
 250: *  METHOD GETNAMELIST  *
 251: *                      *
 252: ***********************/
 253: 
 254: 
 255: CacheRRListPtr RRCache::GetNameList(LabelListConstPtr i_llpName, bool i_bCreate) {
 256:   CacheMap::const_iterator cmpi;
 257:   LabelList::const_reverse_iterator lbi;
 258:   LogHandle lh(LF_CACHE,LY_EXTRA_DEBUG);
 259:   CacheNodePtr cnp = &m_cn;
 260: 
 261:   for(lbi=i_llpName->rbegin();lbi!=i_llpName->rend();++lbi) {
 262:     lh << (*lbi).GetString();
 263:     cmpi = cnp->cmTree.find((*lbi));
 264:     if (cmpi==cnp->cmTree.end()) {
 265:       if (i_bCreate==false) return NULL;
 266:       cnp->cmTree[(*lbi)] = new CacheNode;
 267:       cmpi = cnp->cmTree.find((*lbi));
 268:     } 
 269:     cnp = (*cmpi).second;
 270:   }
 271:   return cnp->cspEntries;
 272: }
 273: 
 274: 
 275: CacheRRListConstPtr RRCache::GetNameList(LabelListPtr o_llpMatch, LabelListConstPtr i_llpName, RRType i_ty, RRClass i_cl, bool i_bBest) const {
 276:   CacheMap::const_iterator cmi;
 277:   LabelList::const_reverse_iterator lbi;
 278:   CacheMapConstPtr c_cmp = &m_cn.cmTree;
 279:   CacheRRListConstPtr c_csp = m_cn.cspEntries;
 280:   CacheRRListConstPtr c_cspOut = m_cn.cspEntries;
 281:   LabelListPtr llp = new LabelList;
 282: 
 283:   for(lbi=i_llpName->rbegin();lbi!=i_llpName->rend();++lbi) {
 284:     llp->insert(llp->begin(),*lbi);
 285:     cmi = c_cmp->find((*lbi));
 286:     if (cmi==c_cmp->end()) {
 287:       if (i_bBest==false) return NULL;
 288:       break;
 289:     }
 290:     c_csp = (*cmi).second->cspEntries;
 291:     c_cmp = &(*cmi).second->cmTree;
 292:     if (c_csp->HasTypeClass(i_ty,i_cl)==true) {
 293:       if (o_llpMatch!=NULL) (*o_llpMatch) = *llp;
 294:       c_cspOut = c_csp;
 295:     }
 296:   }
 297:   SoftDelete(llp);
 298:   if ((i_bBest==false)&&(c_csp!=c_cspOut)) return NULL;
 299:   return c_cspOut;
 300: }
 301: 
 302: 
 303: /*****************
 304: *                *
 305: *  METHOD GETNS  *
 306: *                *
 307: *****************/
 308: 
 309: //
 310: //  INFO: This function returns copies of cached NS records that indicate 
 311: //  where authoritative information about the specified (i_rlp) records can be found.
 312: //
 313: 
 314: RRListPtr RRCache::GetNS(RRListPtr i_rlp) const {
 315:   RRList::iterator rrpi;
 316:   RRListPtr rlpOut = new RRList;
 317:   WatchPtr<RRListPtr> wp(rlpOut);
 318: 
 319:   for(rrpi=i_rlp->begin();rrpi!=i_rlp->end();++rrpi) {
 320:     this->GetNS(rlpOut,(*rrpi)->GetName());
 321:   }
 322:   wp.Release();
 323:   return rlpOut;
 324: }
 325: 
 326: 
 327: void RRCache::GetNS(RRListPtr o_rlp, LabelListConstPtr i_llpName) const {
 328:   RWLocker rk(&m_rw,false);
 329:   CacheRRListConstPtr c_csp;
 330:   CacheRRList::const_iterator c_crpi;
 331:   LabelListPtr llpNS = new LabelList;
 332: 
 333:   c_csp = this->GetNameList(llpNS,i_llpName,TY_NS,CL_IN,true);
 334:   if (c_csp!=NULL) {
 335:     for(c_crpi=c_csp->begin();c_crpi!=c_csp->end();++c_crpi) {
 336:       if ((*c_crpi)->IsTypeClass(TY_NS,CL_IN)==false) continue;
 337:       if (o_rlp->HasResourceMatch(*c_crpi)==true) continue;
 338:       LabelListPtr llp = new LabelList(*llpNS);
 339:       o_rlp->push_back(RRFactory::NewRR(llp,*c_crpi));
 340:     }
 341:   }
 342:   SoftDelete(llpNS);
 343: }
 344: 
 345: 
 346: /*****************
 347: *                *
 348: *  METHOD GETAR  *
 349: *                *
 350: *****************/
 351: 
 352: 
 353: RRListPtr RRCache::GetAR(RRListPtr i_rlpNS) {
 354:   RRList::iterator rliNS;
 355:   RRList::iterator rliTemp;
 356:   RRListPtr rlpOut = new RRList;
 357:   RRListPtr rlpTemp;
 358: 
 359:   for(rliNS=i_rlpNS->begin();rliNS!=i_rlpNS->end();++rliNS) {
 360:     rlpTemp = this->GetSimple( (*rliNS)->GetRData()->As<RDataName>()->GetRDName(), TY_A, CL_IN);
 361:     if (rlpTemp!=NULL) {
 362:       for(rliTemp=rlpTemp->begin(); rliTemp!=rlpTemp->end(); ++rliTemp) {
 363:         rlpOut->push_back( *rliTemp ); 
 364:       }
 365:       rlpTemp->erase(rlpTemp->begin(),rlpTemp->end());
 366:       SoftDelete(rlpTemp);
 367:     }
 368:   }
 369:   return rlpOut;
 370: }
 371: 
 372: 
 373: /**********************
 374: *                     *
 375: *  METHODS GETSIMPLE  *
 376: *                     *
 377: **********************/
 378: 
 379: 
 380: RRListPtr RRCache::GetSimple(LabelListConstPtr ci_llpName, RRType i_ty, RRClass i_cl) {
 381:   CacheRRListPtr csp;
 382:   CacheRRList::const_iterator cspi;
 383:   unsigned uNow = time(NULL);
 384:   RRListPtr rlpOut = NULL;
 385:   LogHandle lh(LF_CACHE,LY_DEBUG);
 386: 
 387:   csp = this->GetNameList(ci_llpName,false);
 388:   if (csp==NULL) return NULL;
 389:   lh << "cache check " << ci_llpName << " " << GetClassName(i_cl) << " " << GetTypeName(i_ty) << endl;
 390: 
 391:   // STUB: TY_QAXFR, TY_QMAILA and TY_QMAILB are not implemented.
 392:   assert(i_ty!=TY_QAXFR);
 393:   assert(i_ty!=TY_QMAILB);
 394:   assert(i_ty!=TY_QMAILA);
 395: 
 396:   rlpOut = new RRList;
 397:   for(cspi=csp->begin();cspi!=csp->end();++cspi) {
 398:     lh << LY_EXTRA_DEBUG << "cache try " << *(*cspi) << endl; lh();
 399:     //lh << "cache try " << (*cspi) << endl;
 400:     if ((*cspi)->IsExpired(uNow)==true) {
 401:       lh << "cache stale " << **cspi << endl;
 402:       continue;
 403:     }
 404:     if ( (*cspi)->IsTypeClass(i_ty,i_cl) == false) {
 405:       if ( (*cspi)->IsTypeClass(TY_CNAME,i_cl) == false) continue;
 406:     }
 407:     LabelListPtr llp = new LabelList(*ci_llpName);
 408:     lh << "cache hit " << llp << " " << *(*cspi) << endl;
 409:     rlpOut->push_back(RRFactory::NewRR(llp,(*cspi)));
 410:   }
 411:   if (rlpOut->size()==0) {
 412:     lh << "cache miss " << ci_llpName << " " << GetClassName(i_cl) << " " << GetTypeName(i_ty) << endl;
 413:     SoftDelete(rlpOut);
 414:     return NULL;
 415:   }
 416:   return rlpOut;
 417:   
 418: }
 419: 
 420: 
 421: /****************
 422: *               *
 423: *  METHOD WALK  *
 424: *               *
 425: ****************/
 426: 
 427: 
 428: void RRCache::Walk(ostream &io_smr) const {
 429:   io_smr << "." << endl;
 430:   m_cn.Walk(io_smr,1);
 431: }
 432: 
 433: 
 434: void CacheNode::Walk(ostream &io_smr, int i_iDepth) const {
 435:   CacheMap::const_iterator cmi;
 436:   int i;
 437:  
 438:   cspEntries->Walk(io_smr,i_iDepth);
 439:   for(cmi=cmTree.begin();cmi!=cmTree.end();++cmi) {
 440:     for(i=0;i<i_iDepth;++i) io_smr << "  ";
 441:     io_smr << (*cmi).first << endl;
 442:     (*cmi).second->Walk(io_smr,i_iDepth+1);
 443:   }
 444: }
 445: 
 446: 
 447: /***********************
 448: *                      *
 449: *  RRCACHE DESTRUCTOR  *
 450: *                      *
 451: ***********************/
 452: 
 453: 
 454: RRCache::~RRCache() {
 455: //  cerr << "RRCache::~RRCache()" << endl;
 456: }
 457: 
 458: 
 459: CacheNode::~CacheNode() {
 460:   CacheMap::iterator cmi;
 461:   //cerr << "CacheNode::~CacheNode()" << endl;
 462:   SoftDelete(cspEntries);
 463:   for(cmi=cmTree.begin();cmi!=cmTree.end();++cmi) {
 464:     delete (*cmi).second;
 465:   }
 466: }
 467: 
 468: 
 469: