reSIProcate/repro  9694
AbstractDb.cxx
Go to the documentation of this file.
00001 #include <cassert>
00002 
00003 #include "rutil/Data.hxx"
00004 #include "rutil/DataStream.hxx"
00005 #include "rutil/ParseBuffer.hxx"
00006 #include "resip/stack/Symbols.hxx"
00007 #include "rutil/Logger.hxx"
00008 
00009 
00010 #include "repro/UserStore.hxx"
00011 #include "repro/AbstractDb.hxx"
00012 
00013 
00014 using namespace resip;
00015 using namespace repro;
00016 using namespace std;
00017 
00018 #define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
00019 
00020 
00021 static void 
00022 encodeString(oDataStream& s, const Data& data)
00023 {
00024    short len = (short)data.size();
00025    s.write( (char*)(&len) , sizeof( len ) );
00026    s.write( data.data(), len );
00027 }
00028 
00029 
00030 static void
00031 decodeString(iDataStream& s, Data& data)
00032 {
00033    data.clear();
00034 
00035    if(s.eof()) return;
00036 
00037    short len;
00038    s.read((char*)(&len), sizeof(len));
00039    if(s.eof()) return;
00040 
00041    // [TODO] This is probably OK for now, but we can do better than this.
00042    if (len > 8192)
00043    {
00044       ErrLog( << "Tried to decode a database record that was much larger (>8k) than expected.  Returning an empty Data instead." );
00045       return;
00046    }
00047 
00048    s.read(data.getBuf(len), len);
00049 }
00050 
00051 
00052 AbstractDb::AbstractDb()
00053 {
00054 }
00055 
00056 
00057 AbstractDb::~AbstractDb()
00058 {
00059 }
00060 
00061 
00062 Data 
00063 AbstractDb::dbFirstKey(const AbstractDb::Table table)
00064 {
00065    return dbNextKey(table,true/*first*/);
00066 }
00067 
00068 
00069 bool
00070 AbstractDb::dbFirstRecord(const AbstractDb::Table table, 
00071                           const Data& key,
00072                           Data& data,
00073                           bool forUpdate)
00074 {
00075    return dbNextRecord(table, key, data, forUpdate, true/*first*/);
00076 }
00077 
00078 
00079 // Callback used by BerkeleyDb for secondary table support.  Returns key to use in
00080 // secondary database table
00081 // secondaryKey should point to persistent data (ie. typically something from data itself)
00082 int
00083 AbstractDb::getSecondaryKey(const Table table, 
00084                             const Key& key, 
00085                             const Data& data, 
00086                             void** secondaryKey, 
00087                             unsigned int* secondaryKeyLen)
00088 {
00089    if(table == SiloTable)
00090    {
00091       // Secondary Key for Silo table is DestUri
00092       Data nonConstData(Data::Share, data.data(), data.size());
00093       iDataStream s(nonConstData);
00094 
00095       short version;
00096       assert(sizeof(version) == 2);
00097       s.read((char*)(&version), sizeof(version));
00098       assert(version == 1);
00099       if (version == 1)
00100       {
00101          // DestUri is first element after version
00102          short len;
00103          s.read( (char*)(&len), sizeof(len));
00104          *secondaryKeyLen = (unsigned int)len;
00105          *secondaryKey = (void*)(nonConstData.data() + (sizeof(version)+sizeof(len)));
00106          return 0;
00107       }
00108    }
00109    return -1;
00110 }
00111 
00112 
00113 void 
00114 AbstractDb::encodeUser(const UserRecord& rec, resip::Data& data)
00115 {
00116    oDataStream s(data);
00117       
00118    short version=2;
00119    assert( sizeof( version) == 2 );
00120    s.write( (char*)(&version) , sizeof(version) );
00121       
00122    encodeString( s, rec.user );
00123    encodeString( s, rec.domain);
00124    encodeString( s, rec.realm);
00125    encodeString( s, rec.passwordHash);
00126    encodeString( s, rec.name);
00127    encodeString( s, rec.email);
00128    encodeString( s, rec.forwardAddress);
00129    s.flush();
00130 }
00131 
00132 bool
00133 AbstractDb::addUser( const AbstractDb::Key& key, const AbstractDb::UserRecord& rec )
00134 {  
00135    assert( !key.empty() );
00136    
00137    Data data;
00138    encodeUser(rec, data);
00139    
00140    return dbWriteRecord(UserTable,key,data);
00141 }
00142 
00143 
00144 void 
00145 AbstractDb::eraseUser( const AbstractDb::Key& key )
00146 {
00147    dbEraseRecord( UserTable, key);
00148 }
00149 
00150 
00151 AbstractDb::UserRecord 
00152 AbstractDb::getUser( const AbstractDb::Key& key ) const
00153 {
00154    AbstractDb::UserRecord rec;
00155    Data data;
00156    bool stat = dbReadRecord( UserTable, key, data );
00157    if ( !stat )
00158    {
00159       return rec;
00160    }
00161    if ( data.empty() )
00162    {
00163       return rec;
00164    }
00165 
00166    iDataStream s(data);
00167 
00168    short version;
00169    assert( sizeof(version) == 2 );
00170    s.read( (char*)(&version), sizeof(version) );
00171    
00172    if ( version == 2 )
00173    {
00174       decodeString(s, rec.user);
00175       decodeString(s, rec.domain);
00176       decodeString(s, rec.realm);
00177       decodeString(s, rec.passwordHash);
00178       decodeString(s, rec.name);
00179       decodeString(s, rec.email);
00180       decodeString(s, rec.forwardAddress);
00181    }
00182    else
00183    {
00184       // unknown version 
00185       ErrLog( <<"Data in user database with unknown version " << version );
00186       ErrLog( <<"record size is " << data.size() );
00187    }
00188       
00189    return rec;
00190 }
00191 
00192 
00193 Data 
00194 AbstractDb::getUserAuthInfo(  const AbstractDb::Key& key ) const
00195 { 
00196    AbstractDb::UserRecord rec = getUser(key);
00197    
00198    return rec.passwordHash;
00199 }
00200 
00201 
00202 AbstractDb::Key 
00203 AbstractDb::firstUserKey()
00204 {
00205    return dbFirstKey(UserTable);
00206 }
00207 
00208 
00209 AbstractDb::Key 
00210 AbstractDb::nextUserKey()
00211 {
00212    return dbNextKey(UserTable);
00213 }
00214  
00215 
00216 void 
00217 AbstractDb::encodeRoute(const RouteRecord& rec, resip::Data& data)
00218 {
00219    oDataStream s(data);
00220       
00221    short version=1;
00222    assert( sizeof( version) == 2 );
00223    s.write( (char*)(&version) , sizeof(version) );
00224       
00225    encodeString( s, rec.mMethod );
00226    encodeString( s, rec.mEvent );
00227    encodeString( s, rec.mMatchingPattern );
00228    encodeString( s, rec.mRewriteExpression );
00229    s.write( (char*)(&rec.mOrder) , sizeof( rec.mOrder ) );
00230    assert( sizeof( rec.mOrder) == 2 );
00231   
00232    //!cj! TODO - add the extra local use only flag 
00233 
00234    s.flush();
00235 }
00236 
00237 
00238 bool
00239 AbstractDb::addRoute( const AbstractDb::Key& key, 
00240                  const AbstractDb::RouteRecord& rec )
00241 { 
00242    assert( !key.empty() );
00243    
00244    Data data;
00245    encodeRoute(rec, data);
00246    
00247    return dbWriteRecord( RouteTable, key, data );
00248 }
00249 
00250 
00251 void 
00252 AbstractDb::eraseRoute(  const AbstractDb::Key& key )
00253 {  
00254    dbEraseRecord (RouteTable, key);
00255 }
00256 
00257 
00258 AbstractDb::RouteRecord 
00259 AbstractDb::getRoute( const AbstractDb::Key& key) const
00260 { 
00261    AbstractDb::RouteRecord rec;
00262    Data data;
00263    bool stat = dbReadRecord( RouteTable, key, data );
00264    if ( !stat )
00265    {
00266       return rec;
00267    }
00268    if ( data.empty() )
00269    {
00270       return rec;
00271    }
00272 
00273    iDataStream s(data);
00274 
00275    short version;
00276    assert( sizeof(version) == 2 );
00277    s.read( (char*)(&version), sizeof(version) );
00278    
00279    if ( version == 1 )
00280    {
00281       decodeString(s, rec.mMethod);
00282       decodeString(s, rec.mEvent);
00283       decodeString(s, rec.mMatchingPattern);
00284       decodeString(s, rec.mRewriteExpression);
00285       s.read( (char*)(&rec.mOrder), sizeof(rec.mOrder) ); 
00286       assert( sizeof( rec.mOrder) == 2 );
00287    }
00288    else
00289    {
00290       // unknown version 
00291       ErrLog( <<"Data in route database with unknown version " << version );
00292       ErrLog( <<"record size is " << data.size() );
00293    }
00294       
00295    return rec;
00296 }
00297 
00298 
00299 AbstractDb::RouteRecordList 
00300 AbstractDb::getAllRoutes()
00301 {
00302    AbstractDb::RouteRecordList ret;
00303    
00304    AbstractDb::Key key = firstRouteKey();
00305    while ( !key.empty() )
00306    {
00307       AbstractDb::RouteRecord rec = getRoute(key);
00308       
00309       ret.push_back(rec);
00310             
00311       key = nextRouteKey();
00312    }
00313    
00314    return ret;
00315 }
00316 
00317 
00318 AbstractDb::Key 
00319 AbstractDb::firstRouteKey()
00320 { 
00321    return dbFirstKey(RouteTable);
00322 }
00323 
00324 
00325 AbstractDb::Key 
00326 AbstractDb::nextRouteKey()
00327 { 
00328    return dbNextKey(RouteTable);
00329 }
00330 
00331 
00332 bool
00333 AbstractDb::addAcl( const AbstractDb::Key& key, 
00334                     const AbstractDb::AclRecord& rec )
00335 { 
00336    assert( !key.empty() );
00337    
00338    Data data;
00339    {
00340       oDataStream s(data);
00341       
00342       short version=1;
00343       assert( sizeof( version) == 2 );
00344       s.write( (char*)(&version) , sizeof(version) );
00345 
00346       encodeString( s, rec.mTlsPeerName );
00347       encodeString( s, rec.mAddress );
00348       s.write( (char*)(&rec.mMask) , sizeof( rec.mMask ) );
00349       s.write( (char*)(&rec.mPort) , sizeof( rec.mPort ) );
00350       s.write( (char*)(&rec.mFamily) , sizeof( rec.mFamily ) );
00351       s.write( (char*)(&rec.mTransport) , sizeof( rec.mTransport ) );
00352 
00353       s.flush();
00354    }
00355    
00356    return dbWriteRecord( AclTable, key, data );
00357 }
00358 
00359 
00360 void 
00361 AbstractDb::eraseAcl(  const AbstractDb::Key& key )
00362 {  
00363    dbEraseRecord (AclTable, key);
00364 }
00365 
00366 
00367 AbstractDb::AclRecord 
00368 AbstractDb::getAcl( const AbstractDb::Key& key) const
00369 { 
00370    AbstractDb::AclRecord rec;
00371    Data data;
00372    bool stat = dbReadRecord( AclTable, key, data );
00373    if ( !stat )
00374    {
00375       return rec;
00376    }
00377    if ( data.empty() )
00378    {
00379       return rec;
00380    }
00381 
00382    iDataStream s(data);
00383 
00384    short version;
00385    assert( sizeof(version) == 2 );
00386    s.read( (char*)(&version), sizeof(version) );
00387    
00388    if ( version == 1 )
00389    {
00390       decodeString(s, rec.mTlsPeerName);
00391       decodeString(s, rec.mAddress);
00392       s.read( (char*)(&rec.mMask), sizeof(rec.mMask) ); 
00393       s.read( (char*)(&rec.mPort), sizeof(rec.mPort) ); 
00394       s.read( (char*)(&rec.mFamily), sizeof(rec.mFamily) ); 
00395       s.read( (char*)(&rec.mTransport), sizeof(rec.mTransport) ); 
00396    }
00397    else
00398    {
00399       // unknown version 
00400       ErrLog( <<"Data in ACL database with unknown version " << version );
00401       ErrLog( <<"record size is " << data.size() );
00402    }
00403       
00404    return rec;
00405 }
00406 
00407 
00408 AbstractDb::AclRecordList 
00409 AbstractDb::getAllAcls()
00410 {
00411    AbstractDb::AclRecordList ret;
00412    
00413    AbstractDb::Key key = firstAclKey();
00414    while ( !key.empty() )
00415    {
00416       AbstractDb::AclRecord rec = getAcl(key);
00417       
00418       ret.push_back(rec);
00419             
00420       key = nextAclKey();
00421    }
00422    
00423    return ret;
00424 }
00425 
00426 
00427 AbstractDb::Key 
00428 AbstractDb::firstAclKey()
00429 { 
00430    return dbFirstKey(AclTable);
00431 }
00432 
00433 
00434 AbstractDb::Key 
00435 AbstractDb::nextAclKey()
00436 { 
00437    return dbNextKey(AclTable);
00438 }
00439 
00440 
00441 bool
00442 AbstractDb::addConfig( const AbstractDb::Key& key, 
00443                  const AbstractDb::ConfigRecord& rec )
00444 { 
00445    assert( !key.empty() );
00446    
00447    Data data;
00448    {
00449       oDataStream s(data);
00450       
00451       short version=1;
00452       assert( sizeof( version) == 2 );
00453       s.write( (char*)(&version) , sizeof(version) );
00454       
00455       encodeString( s, rec.mDomain );
00456       s.write( (char*)(&rec.mTlsPort) , sizeof( rec.mTlsPort ) );
00457       assert( sizeof(rec.mTlsPort) == 2 );
00458 
00459       s.flush();
00460    }
00461    
00462    return dbWriteRecord( ConfigTable, key, data );
00463 }
00464 
00465 
00466 void 
00467 AbstractDb::eraseConfig(  const AbstractDb::Key& key )
00468 {  
00469    dbEraseRecord (ConfigTable, key);
00470 }
00471 
00472 
00473 AbstractDb::ConfigRecord 
00474 AbstractDb::getConfig( const AbstractDb::Key& key) const
00475 { 
00476    AbstractDb::ConfigRecord rec;
00477    Data data;
00478    bool stat = dbReadRecord( ConfigTable, key, data );
00479    if ( !stat )
00480    {
00481       return rec;
00482    }
00483    if ( data.empty() )
00484    {
00485       return rec;
00486    }
00487 
00488    iDataStream s(data);
00489 
00490    short version;
00491    assert( sizeof(version) == 2 );
00492    s.read( (char*)(&version), sizeof(version) );
00493    
00494    if ( version == 1 )
00495    {
00496       decodeString(s, rec.mDomain);
00497 
00498       s.read( (char*)(&rec.mTlsPort), sizeof(rec.mTlsPort) ); 
00499       assert( sizeof( rec.mTlsPort) == 2 );
00500    }
00501    else
00502    {
00503       // unknown version 
00504       ErrLog( <<"Data in ACL database with unknown version " << version );
00505       ErrLog( <<"record size is " << data.size() );
00506    }
00507       
00508    return rec;
00509 }
00510 
00511 
00512 AbstractDb::ConfigRecordList 
00513 AbstractDb::getAllConfigs()
00514 {
00515    AbstractDb::ConfigRecordList ret;
00516    
00517    AbstractDb::Key key = firstConfigKey();
00518    while ( !key.empty() )
00519    {
00520       AbstractDb::ConfigRecord rec = getConfig(key);
00521       
00522       ret.push_back(rec);
00523             
00524       key = nextConfigKey();
00525    }
00526    
00527    return ret;
00528 }
00529 
00530 
00531 AbstractDb::Key 
00532 AbstractDb::firstConfigKey()
00533 { 
00534    return dbFirstKey(ConfigTable);
00535 }
00536 
00537 
00538 AbstractDb::Key 
00539 AbstractDb::nextConfigKey()
00540 { 
00541    return dbNextKey(ConfigTable);
00542 }
00543 
00544 
00545 bool
00546 AbstractDb::addStaticReg( const AbstractDb::Key& key, 
00547                           const AbstractDb::StaticRegRecord& rec )
00548 { 
00549    assert( !key.empty() );
00550    
00551    Data data;
00552    {
00553       oDataStream s(data);
00554       
00555       short version=1;
00556       assert( sizeof( version) == 2 );
00557       s.write( (char*)(&version) , sizeof(version) );
00558       
00559       encodeString( s, rec.mAor );
00560       encodeString( s, rec.mContact );
00561       encodeString( s, rec.mPath );
00562 
00563       s.flush();
00564    }
00565    
00566    return dbWriteRecord( StaticRegTable, key, data );
00567 }
00568 
00569 
00570 void 
00571 AbstractDb::eraseStaticReg(  const AbstractDb::Key& key )
00572 {  
00573    dbEraseRecord (StaticRegTable, key);
00574 }
00575 
00576 
00577 AbstractDb::StaticRegRecord 
00578 AbstractDb::getStaticReg( const AbstractDb::Key& key) const
00579 { 
00580    AbstractDb::StaticRegRecord rec;
00581    Data data;
00582    bool stat = dbReadRecord( StaticRegTable, key, data );
00583    if ( !stat )
00584    {
00585       return rec;
00586    }
00587    if ( data.empty() )
00588    {
00589       return rec;
00590    }
00591 
00592    iDataStream s(data);
00593 
00594    short version;
00595    assert( sizeof(version) == 2 );
00596    s.read( (char*)(&version), sizeof(version) );
00597    
00598    if ( version == 1 )
00599    {
00600       decodeString(s, rec.mAor);
00601       decodeString(s, rec.mContact);
00602       decodeString(s, rec.mPath);
00603    }
00604    else
00605    {
00606       // unknown version 
00607       ErrLog( <<"Data in StaticReg database with unknown version " << version );
00608       ErrLog( <<"record size is " << data.size() );
00609    }
00610       
00611    return rec;
00612 }
00613 
00614 
00615 AbstractDb::StaticRegRecordList 
00616 AbstractDb::getAllStaticRegs()
00617 {
00618    AbstractDb::StaticRegRecordList ret;
00619    
00620    AbstractDb::Key key = firstStaticRegKey();
00621    while ( !key.empty() )
00622    {
00623       AbstractDb::StaticRegRecord rec = getStaticReg(key);
00624       
00625       ret.push_back(rec);
00626             
00627       key = nextStaticRegKey();
00628    }
00629    
00630    return ret;
00631 }
00632 
00633 
00634 AbstractDb::Key 
00635 AbstractDb::firstStaticRegKey()
00636 { 
00637    return dbFirstKey(StaticRegTable);
00638 }
00639 
00640 
00641 AbstractDb::Key 
00642 AbstractDb::nextStaticRegKey()
00643 { 
00644    return dbNextKey(StaticRegTable);
00645 }
00646 
00647 
00648 void 
00649 AbstractDb::encodeFilter(const FilterRecord& rec, resip::Data& data)
00650 {
00651    oDataStream s(data);
00652 
00653    short version=1;
00654    assert(sizeof( version) == 2);
00655    s.write((char*)(&version) , sizeof(version));
00656       
00657    encodeString(s, rec.mCondition1Header);
00658    encodeString(s, rec.mCondition1Regex);
00659    encodeString(s, rec.mCondition2Header);
00660    encodeString(s, rec.mCondition2Regex);
00661    encodeString(s, rec.mMethod);
00662    encodeString(s, rec.mEvent);
00663    s.write((char*)(&rec.mAction), sizeof (rec.mAction));
00664    assert(sizeof(rec.mAction) == 2);
00665    encodeString(s, rec.mActionData);
00666    s.write((char*)(&rec.mOrder), sizeof(rec.mOrder));
00667    assert(sizeof(rec.mOrder) == 2);
00668 
00669    s.flush();
00670 }
00671 
00672 
00673 bool
00674 AbstractDb::addFilter(const AbstractDb::Key& key, 
00675                       const AbstractDb::FilterRecord& rec)
00676 { 
00677    assert( !key.empty() );
00678    
00679    Data data;
00680    encodeFilter(rec, data);
00681    return dbWriteRecord(FilterTable, key, data);
00682 }
00683 
00684 
00685 void 
00686 AbstractDb::eraseFilter(const AbstractDb::Key& key)
00687 {  
00688    dbEraseRecord(FilterTable, key);
00689 }
00690 
00691 
00692 AbstractDb::FilterRecord 
00693 AbstractDb::getFilter( const AbstractDb::Key& key) const
00694 { 
00695    AbstractDb::FilterRecord rec;
00696    Data data;
00697    bool stat = dbReadRecord(FilterTable, key, data);
00698    if (!stat)
00699    {
00700       return rec;
00701    }
00702    if (data.empty())
00703    {
00704       return rec;
00705    }
00706 
00707    iDataStream s(data);
00708 
00709    short version;
00710    assert(sizeof(version) == 2);
00711    s.read((char*)(&version), sizeof(version));
00712    
00713    if (version == 1)
00714    {
00715       decodeString(s, rec.mCondition1Header);
00716       decodeString(s, rec.mCondition1Regex);
00717       decodeString(s, rec.mCondition2Header);
00718       decodeString(s, rec.mCondition2Regex);
00719       decodeString(s, rec.mMethod);
00720       decodeString(s, rec.mEvent);
00721       s.read((char*)(&rec.mAction), sizeof(rec.mAction)); 
00722       assert(sizeof(rec.mAction) == 2);
00723       decodeString(s, rec.mActionData);
00724       s.read((char*)(&rec.mOrder), sizeof(rec.mOrder)); 
00725       assert(sizeof(rec.mOrder) == 2);
00726    }
00727    else
00728    {
00729       // unknown version 
00730       ErrLog( <<"Data in filter database with unknown version " << version );
00731       ErrLog( <<"record size is " << data.size() );
00732    }
00733       
00734    return rec;
00735 }
00736 
00737 
00738 AbstractDb::FilterRecordList 
00739 AbstractDb::getAllFilters()
00740 {
00741    AbstractDb::FilterRecordList ret;
00742    
00743    AbstractDb::Key key = firstFilterKey();
00744    while ( !key.empty() )
00745    {
00746       AbstractDb::FilterRecord rec = getFilter(key);
00747       
00748       ret.push_back(rec);
00749             
00750       key = nextFilterKey();
00751    }
00752    
00753    return ret;
00754 }
00755 
00756 
00757 AbstractDb::Key 
00758 AbstractDb::firstFilterKey()
00759 { 
00760    return dbFirstKey(FilterTable);
00761 }
00762 
00763 
00764 AbstractDb::Key 
00765 AbstractDb::nextFilterKey()
00766 { 
00767    return dbNextKey(FilterTable);
00768 }
00769 
00770 bool
00771 AbstractDb::addToSilo(const Key& key, const SiloRecord& rec)
00772 {
00773    assert( !key.empty() );
00774    
00775    Data data;
00776    {
00777       oDataStream s(data);
00778 
00779       short version=1;
00780       assert(sizeof( version) == 2);
00781       s.write((char*)(&version) , sizeof(version));
00782 
00783       encodeString(s, rec.mDestUri);
00784       encodeString(s, rec.mSourceUri);
00785       s.write((char*)(&rec.mOriginalSentTime), sizeof (rec.mOriginalSentTime));
00786       assert(sizeof(rec.mOriginalSentTime) == 8);
00787       encodeString(s, rec.mTid);
00788       encodeString(s, rec.mMimeType);
00789       encodeString(s, rec.mMessageBody);
00790 
00791       s.flush();
00792    }
00793    return dbWriteRecord(SiloTable, key, data);
00794 }
00795 
00796 void
00797 AbstractDb::decodeSiloRecord(Data& data, SiloRecord& rec)
00798 {
00799    iDataStream s(data);
00800 
00801    short version;
00802    assert(sizeof(version) == 2);
00803    s.read((char*)(&version), sizeof(version));
00804    
00805    if (version == 1)
00806    {
00807       decodeString(s, rec.mDestUri);
00808       decodeString(s, rec.mSourceUri);
00809       s.read((char*)(&rec.mOriginalSentTime), sizeof(rec.mOriginalSentTime)); 
00810       assert(sizeof(rec.mOriginalSentTime) == 8);
00811       decodeString(s, rec.mTid);
00812       decodeString(s, rec.mMimeType);
00813       decodeString(s, rec.mMessageBody);
00814    }
00815    else
00816    {
00817       // unknown version 
00818       ErrLog( <<"Data in silo database with unknown version " << version );
00819       ErrLog( <<"record size is " << data.size() );
00820    }
00821 }
00822 
00823 bool
00824 AbstractDb::getSiloRecords(const Key& skey, AbstractDb::SiloRecordList& recordList)
00825 {
00826    AbstractDb::SiloRecord rec;
00827 
00828    Data data;
00829    bool moreRecords = dbFirstRecord(SiloTable, skey, data, false /* forUpdate? */);
00830    if(moreRecords)
00831    {
00832       // Decode and store data
00833       decodeSiloRecord(data,rec);
00834       recordList.push_back(rec);
00835       while((moreRecords = dbNextRecord(SiloTable, skey, data, false /* forUpdate? */)))
00836       {
00837          // Decode and store data
00838          decodeSiloRecord(data,rec);
00839          recordList.push_back(rec);
00840       }
00841    }
00842 
00843    return true;
00844 }
00845 
00846 void 
00847 AbstractDb::eraseSiloRecord(const Key& key)
00848 {
00849    dbEraseRecord(SiloTable, key);
00850 }
00851 
00852 void 
00853 AbstractDb::cleanupExpiredSiloRecords(UInt64 now, unsigned long expirationTime)
00854 {
00855    AbstractDb::Key key = dbFirstKey(SiloTable);  // Iterate on primary key
00856    // Iterate through all silo records - retrieve Original send time embedded into the 
00857    // primary key and see if the record has expired.
00858    Data originalSendTimeData;
00859    UInt64 originalSendTime;
00860    while(!key.empty())
00861    {
00862       ParseBuffer pb(key);
00863       const char* anchor = pb.position();
00864       pb.skipToChar(':');
00865       pb.data(originalSendTimeData, anchor);
00866       originalSendTime = originalSendTimeData.convertUInt64();
00867       if((unsigned long)(now - originalSendTime) > expirationTime)
00868       {
00869          eraseSiloRecord(key);
00870       }
00871       key = dbNextKey(SiloTable);
00872    }
00873 }
00874 
00875 /* ====================================================================
00876  * The Vovida Software License, Version 1.0 
00877  * 
00878  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00879  * 
00880  * Redistribution and use in source and binary forms, with or without
00881  * modification, are permitted provided that the following conditions
00882  * are met:
00883  * 
00884  * 1. Redistributions of source code must retain the above copyright
00885  *    notice, this list of conditions and the following disclaimer.
00886  * 
00887  * 2. Redistributions in binary form must reproduce the above copyright
00888  *    notice, this list of conditions and the following disclaimer in
00889  *    the documentation and/or other materials provided with the
00890  *    distribution.
00891  * 
00892  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00893  *    and "Vovida Open Communication Application Library (VOCAL)" must
00894  *    not be used to endorse or promote products derived from this
00895  *    software without prior written permission. For written
00896  *    permission, please contact vocal@vovida.org.
00897  *
00898  * 4. Products derived from this software may not be called "VOCAL", nor
00899  *    may "VOCAL" appear in their name, without prior written
00900  *    permission of Vovida Networks, Inc.
00901  * 
00902  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00903  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00904  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00905  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00906  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00907  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00908  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00909  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00910  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00911  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00912  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00913  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00914  * DAMAGE.
00915  * 
00916  * ====================================================================
00917  */