1 #ifndef PDNS_SYNCRES_HH
2 #define PDNS_SYNCRES_HH
14 #include <boost/utility.hpp>
16 #include "recursor_cache.hh"
17 #include <boost/tuple/tuple.hpp>
18 #include <boost/optional.hpp>
19 #include <boost/tuple/tuple_comparison.hpp>
23 void primeHints(void);
34 template<class Thing> class Throttle
43 bool shouldThrottle(time_t now, const Thing& t)
45 if(now > d_last_clean + 300 ) {
47 for(typename cont_t::iterator i=d_cont.begin();i!=d_cont.end();) {
48 if( i->second.ttd < now) {
56 typename cont_t::iterator i=d_cont.find(t);
59 if(now > i->second.ttd || i->second.count-- < 0) {
63 return true; // still listed, still blocked
65 void throttle(time_t now, const Thing& t, unsigned int ttl=0, unsigned int tries=0)
67 typename cont_t::iterator i=d_cont.find(t);
68 entry e={ now+(ttl ? ttl : d_ttl), tries ? tries : d_limit};
73 else if(i->second.ttd > e.ttd || (i->second.count) < e.count)
79 return (unsigned int)d_cont.size();
90 typedef map<Thing,entry> cont_t;
95 /** Class that implements a decaying EWMA.
96 This class keeps an exponentially weighted moving average which, additionally, decays over time.
97 The decaying is only done on get.
102 DecayingEwma() : d_val(0.0)
105 d_last.tv_sec = d_last.tv_usec = 0;
109 DecayingEwma(const DecayingEwma& orig) : d_last(orig.d_last), d_lastget(orig.d_lastget), d_val(orig.d_val), d_needinit(orig.d_needinit)
113 struct timeval getOrMakeTime(struct timeval* tv)
119 Utility::gettimeofday(&ret, 0);
124 void submit(int val, struct timeval* tv)
126 struct timeval now=getOrMakeTime(tv);
133 float diff= makeFloat(d_last - now);
136 double factor=exp(diff)/2.0; // might be '0.5', or 0.0001
137 d_val=(float)((1-factor)*val+ (float)factor*d_val);
140 double get(struct timeval* tv)
142 struct timeval now=getOrMakeTime(tv);
143 float diff=makeFloat(d_lastget-now);
145 float factor=exp(diff/60.0f); // is 1.0 or less
146 return d_val*=factor;
149 bool stale(time_t limit) const
151 return limit > d_lastget.tv_sec;
155 struct timeval d_last; // stores time
156 struct timeval d_lastget; // stores time
165 PulseRate() : d_val(0.0)
167 Utility::gettimeofday(&d_last, 0);
170 PulseRate(const PulseRate& orig) : d_last(orig.d_last), d_val(orig.d_val)
174 void pulse(const struct timeval& now)
176 // cout<<"about to submit: "<< 1000.0*makeFloat(now - d_last)<<"\n";
177 submit((int)(1000.0*(makeFloat(now-d_last))), now);
180 optional<float> get(struct timeval& now, unsigned int limit) const
183 float diff=makeFloat(now - d_last);
189 bool stale(time_t limit) const
191 return limit > d_last.tv_sec;
195 void submit(int val, const struct timeval& now)
197 float diff= makeFloat(d_last - now);
200 double factor=exp(diff/2.0)/2.0; // might be '0.5', or 0.0001
201 d_val=(float)((1-factor)*val+ (float)factor*d_val);
204 PulseRate& operator=(const PulseRate&);
205 struct timeval d_last; // stores time
213 explicit SyncRes(const struct timeval& now) : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
215 d_cacheonly(false), d_nocache(false), d_doEDNS0(false) { }
216 int beginResolve(const string &qname, const QType &qtype, uint16_t qclass, vector<DNSResourceRecord>&ret);
220 d_prefix="["+itoa(id)+"] ";
222 static void setLog(bool log)
226 void setCacheOnly(bool state=true)
230 void setNoCache(bool state=true)
235 void setDoEDNS0(bool state=true)
240 static unsigned int s_queries;
241 static unsigned int s_outgoingtimeouts;
242 static unsigned int s_throttledqueries;
243 static unsigned int s_outqueries;
244 static unsigned int s_tcpoutqueries;
245 static unsigned int s_nodelegated;
246 static unsigned int s_unreachables;
247 static bool s_doIPv6;
248 unsigned int d_outqueries;
249 unsigned int d_tcpoutqueries;
250 unsigned int d_throttledqueries;
251 unsigned int d_timeouts;
252 unsigned int d_unreachables;
254 // typedef map<string,NegCacheEntry> negcache_t;
256 typedef multi_index_container <
262 member<NegCacheEntry, string, &NegCacheEntry::d_name>,
263 member<NegCacheEntry, QType, &NegCacheEntry::d_qtype>
265 composite_key_compare<CIStringCompare, std::less<QType> >
268 member<NegCacheEntry, uint32_t, &NegCacheEntry::d_ttd>
272 static negcache_t s_negcache;
274 //! This represents a number of decaying Ewmas, used to store performance per namerserver-name.
275 /** Modelled to work mostly like the underlying DecayingEwma. After you've called get,
276 d_best is filled out with the best address for this collection */
277 struct DecayingEwmaCollection
279 void submit(const ComboAddress& remote, int usecs, struct timeval* now)
281 collection_t::iterator pos;
282 for(pos=d_collection.begin(); pos != d_collection.end(); ++pos)
283 if(pos->first==remote)
285 if(pos!=d_collection.end()) {
286 pos->second.submit(usecs, now);
290 de.submit(usecs, now);
291 d_collection.push_back(make_pair(remote, de));
295 double get(struct timeval* now)
297 if(d_collection.empty())
299 double ret=numeric_limits<double>::max();
301 for(collection_t::iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos) {
302 if((tmp=pos->second.get(now)) < ret) {
311 bool stale(time_t limit) const
313 for(collection_t::const_iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos)
314 if(!pos->second.stale(limit))
319 typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
320 collection_t d_collection;
324 typedef map<string, DecayingEwmaCollection , CIStringCompare> nsspeeds_t;
325 static nsspeeds_t s_nsSpeeds;
330 typedef multi_index_container <
334 composite_key< DNSResourceRecord,
335 member<DNSResourceRecord, string, &DNSResourceRecord::qname>,
336 member<DNSResourceRecord, QType, &DNSResourceRecord::qtype>
338 composite_key_compare<CIStringCompare, std::less<QType> >
346 typedef map<string, AuthDomain, CIStringCompare> domainmap_t;
347 static domainmap_t s_domainmap;
349 typedef Throttle<tuple<ComboAddress,string,uint16_t> > throttle_t;
350 static throttle_t s_throttle;
351 struct timeval d_now;
352 static unsigned int s_maxnegttl;
353 static string s_serverID;
355 struct GetBestNSAnswer;
356 int doResolveAt(set<string, CIStringCompare> nameservers, string auth, bool flawedNSSet, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret,
357 int depth, set<GetBestNSAnswer>&beenthere);
358 int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere);
359 bool doOOBResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res);
360 domainmap_t::const_iterator getBestAuthZone(string* qname);
361 bool doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res);
362 bool doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res);
363 void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, bool* flawedNSSet, int depth, set<GetBestNSAnswer>& beenthere);
364 void addCruft(const string &qname, vector<DNSResourceRecord>& ret);
365 string getBestNSNamesFromCache(const string &qname,set<string, CIStringCompare>& nsset, bool* flawedNSSet, int depth, set<GetBestNSAnswer>&beenthere);
366 void addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth);
368 inline vector<string> shuffleInSpeedOrder(set<string, CIStringCompare> &nameservers, const string &prefix);
369 bool moreSpecificThan(const string& a, const string &b);
370 vector<ComboAddress> getAs(const string &qname, int depth, set<GetBestNSAnswer>& beenthere);
372 SyncRes(const SyncRes&);
373 SyncRes& operator=(const SyncRes&);
383 struct GetBestNSAnswer
386 set<DNSResourceRecord> bestns;
387 bool operator<(const GetBestNSAnswer &b) const
392 return bestns<b.bestns;
399 /* external functions, opaque to us */
400 int asendtcp(const string& data, Socket* sock);
401 int arecvtcp(string& data, int len, Socket* sock);
406 PacketID() : id(0), type(0), sock(0), inNeeded(0), outPos(0), nearMisses(0), fd(-1)
408 memset(&remote, 0, sizeof(remote));
411 uint16_t id; // wait for a specific id/remote pair
412 ComboAddress remote; // this is the remote
413 string domain; // this is the question
414 uint16_t type; // and this is its type
416 Socket* sock; // or wait for an event on a TCP fd
417 int inNeeded; // if this is set, we'll read until inNeeded bytes are read
418 string inMSG; // they'll go here
420 string outMSG; // the outgoing message that needs to be sent
421 string::size_type outPos; // how far we are along in the outMSG
423 mutable uint32_t nearMisses; // number of near misses - host correct, id wrong
424 typedef set<uint16_t > chain_t;
425 mutable chain_t chain;
428 bool operator<(const PacketID& b) const
430 int ourSock= sock ? sock->getHandle() : 0;
431 int bSock = b.sock ? b.sock->getHandle() : 0;
432 if( tie(remote, ourSock, type) < tie(b.remote, bSock, b.type))
434 if( tie(remote, ourSock, type) > tie(b.remote, bSock, b.type))
437 int cmp=Utility::strcasecmp(domain.c_str(), b.domain.c_str());
443 return tie(fd, id) < tie(b.fd, b.id);
447 struct PacketIDBirthdayCompare: public binary_function<PacketID, PacketID, bool>
449 bool operator()(const PacketID& a, const PacketID& b) const
451 int ourSock= a.sock ? a.sock->getHandle() : 0;
452 int bSock = b.sock ? b.sock->getHandle() : 0;
453 if( tie(a.remote, ourSock, a.type) < tie(b.remote, bSock, b.type))
455 if( tie(a.remote, ourSock, a.type) > tie(b.remote, bSock, b.type))
458 int cmp=Utility::strcasecmp(a.domain.c_str(), b.domain.c_str());
462 extern MemRecursorCache RC;
463 typedef MTasker<PacketID,string> MT_t;
472 uint64_t answers0_1, answers1_10, answers10_100, answers100_1000, answersSlow;
473 uint64_t avgLatencyUsec;
475 uint64_t tcpqcounter;
476 uint64_t unauthorizedUDP;
477 uint64_t unauthorizedTCP;
478 uint64_t tcpClientOverflow;
479 uint64_t clientParseError;
480 uint64_t serverParseError;
481 uint64_t unexpectedCount;
483 uint64_t resourceLimits;
484 uint64_t ipv6queries;
485 uint64_t chainResends;
486 uint64_t nsSetInvalidations;
488 uint64_t noShuntCNAME, noShuntExpired, noShuntSize, noShuntNoMatch, noShuntWrongType, noShuntWrongQuestion;
491 typedef vector<ComboAddress> remotes_t;
494 void addRemote(const ComboAddress& remote)
499 remotes[(d_remotepos++) % remotes.size()]=remote;
503 extern RecursorStats g_stats;
506 template<typename Index>
507 std::pair<typename Index::iterator,bool>
508 replacing_insert(Index& i,const typename Index::value_type& x)
510 std::pair<typename Index::iterator,bool> res=i.insert(x);
511 if(!res.second)res.second=i.replace(res.first,x);
516 std::string reloadAuthAndForwards();