2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
20 Christian Herdtweck, Intra2net AG 2015
23 #include "dns/dnscache.h"
26 #include <logfunc.hpp>
27 #include <filefunc.hxx> // I2n::file_exists
28 #include <boost/bind.hpp>
29 #include <boost/date_time/posix_time/posix_time.hpp>
30 #include <boost/asio/placeholders.hpp>
31 #include <boost/serialization/serialization.hpp>
32 #include <boost/serialization/map.hpp>
33 #include <boost/serialization/string.hpp>
34 #include <boost/serialization/vector.hpp>
35 #include <boost/archive/xml_oarchive.hpp>
36 #include <boost/archive/xml_iarchive.hpp>
39 using boost::posix_time::seconds;
40 using I2n::Logger::GlobalLogger;
44 int SaveTimerSeconds = 60;
49 DnsCache::DnsCache(const IoServiceItem &io_serv,
50 const std::string &cache_file)
53 , SaveTimer( *io_serv )
54 , CacheFile( cache_file )
57 // load cache from file
58 load_from_cachefile();
61 (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) );
62 SaveTimer.async_wait( bind( &DnsCache::schedule_save, this,
63 boost::asio::placeholders::error ) );
69 GlobalLogger.info() << "Dns Cache is being destructed";
71 // save one last time without re-scheduling the next save
79 void DnsCache::schedule_save(const boost::system::error_code &error)
81 // just in case: ensure SaveTimer is cancelled
82 SaveTimer.cancel(); // (will do nothing if already expired/cancelled)
84 if ( error == boost::asio::error::operation_aborted ) // cancelled
86 GlobalLogger.error() << "DnsCache: SaveTimer was cancelled "
87 << "--> no save and no re-schedule of saving!";
92 GlobalLogger.error() << "DnsCache: Received error " << error
93 << " in schedule_save "
94 << "--> no save now but re-schedule saving";
100 (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) );
101 SaveTimer.async_wait( bind( &DnsCache::schedule_save, this,
102 boost::asio::placeholders::error ) );
105 void DnsCache::save_to_cachefile()
109 GlobalLogger.info() << "DnsCache: skip saving because has not changed";
112 else if (CacheFile.empty())
114 GlobalLogger.warning()
115 << "DnsCache: skip saving because file name empty!";
121 std::ofstream ofs( CacheFile.c_str() );
122 boost::archive::xml_oarchive oa(ofs);
123 oa << boost::serialization::make_nvp("IpCache", IpCache);
124 oa << boost::serialization::make_nvp("CnameCache", CnameCache);
125 GlobalLogger.info() << "DnsCache: saved to cache file " << CacheFile;
129 catch (std::exception &exc)
131 GlobalLogger.warning() << "Saving failed: " << exc.what();
136 void DnsCache::load_from_cachefile()
138 if (CacheFile.empty())
140 GlobalLogger.warning()
141 << "DnsCache: cannot load because cache file name is empty!";
144 else if ( !I2n::file_exists(CacheFile) )
146 GlobalLogger.warning() << "DnsCache: cannot load because cache file "
147 << CacheFile << " does not exist!";
152 HostAddressVec cache;
154 std::ifstream ifs( CacheFile.c_str() );
155 boost::archive::xml_iarchive ia(ifs);
157 ia >> boost::serialization::make_nvp("IpCache", cache);
158 ia >> boost::serialization::make_nvp("CnameCache", cache);
159 GlobalLogger.info() << "DnsCache: loaded from file " << CacheFile;
161 catch (boost::archive::archive_exception &exc)
163 GlobalLogger.warning() << "DnsCache: archive exception loading from "
164 << CacheFile << ": " << exc.what();
166 catch (std::exception &exc)
168 GlobalLogger.warning() << "DnsCache: exception while loading from "
169 << CacheFile << ": " << exc.what();
173 void DnsCache::update(const std::string &hostname,
174 const HostAddressVec &new_data)
176 GlobalLogger.info() << "DnsCache: update IPs for " << hostname
177 << " to " << new_data.size() << "-list";
178 IpCache[hostname] = new_data;
183 void DnsCache::update(const std::string &hostname,
184 const std::string &cname)
186 GlobalLogger.info() << "DnsCache: update CNAME for " << hostname
188 CnameCache[hostname] = cname;
193 void DnsCache::update_ttl(const std::string &hostname,
194 const uint32_t new_ttl)
196 GlobalLogger.info() << "DnsCache: ensure TTL for IPs for " << hostname
197 << " is below " << new_ttl;
198 HostAddressVec ips = IpCache[hostname];
199 uint32_t current_ttl;
200 TimeToLive current_ttl;
201 BOOST_FOREACH( HostAddress &addr, ips )
203 current_ttl = addr.get_ttl();
204 if (current_ttl.get_value() > new_ttl)
206 current_ttl.set_value(new_ttl);
207 addr.set_ttl(current_ttl);
211 IpCache[hostname] = ip;
215 HostAddressVec& DnsCache::get_ips(const std::string &hostname)
217 GlobalLogger.info() << "DnsCache: request IPs for " << hostname
218 << " --> " << IpCache[hostname].size() << "-list";
219 return IpCache[hostname];
222 std::string& DnsCache::get_cname(const std::string &hostname)
224 GlobalLogger.info() << "DnsCache: request CNAME for " << hostname
225 << " --> " << CnameCache[hostname];
226 return CnameCache[hostname];
231 // (created using vim -- the world's best text editor)