]>
Commit | Line | Data |
---|---|---|
00a19ff7 BH |
1 | #ifndef PDNS_SYNCRES_HH |
2 | #define PDNS_SYNCRES_HH | |
3 | #include <string> | |
4 | #include "dns.hh" | |
5 | #include "qtype.hh" | |
6 | #include <vector> | |
7 | #include <set> | |
8 | #include <map> | |
eefd15f9 BH |
9 | #include <cmath> |
10 | #include <iostream> | |
11 | #include <utility> | |
c836dc19 | 12 | #include "misc.hh" |
00a19ff7 | 13 | #include "lwres.hh" |
d6d5dea7 | 14 | #include <boost/utility.hpp> |
1d5b3ce6 | 15 | #include "sstuff.hh" |
9fdf67d5 | 16 | #include "recursor_cache.hh" |
1d5b3ce6 BH |
17 | #include <boost/tuple/tuple.hpp> |
18 | #include <boost/tuple/tuple_comparison.hpp> | |
19 | #include "mtasker.hh" | |
eefd15f9 | 20 | |
00a19ff7 | 21 | /* external functions, opaque to us */ |
eefd15f9 | 22 | |
bdf40704 | 23 | void primeHints(void); |
00a19ff7 | 24 | |
38e22b5a BH |
25 | struct NegCacheEntry |
26 | { | |
27 | string name; | |
28 | time_t ttd; | |
29 | }; | |
00a19ff7 | 30 | |
49f076e8 BH |
31 | |
32 | template<class Thing> class Throttle | |
33 | { | |
34 | public: | |
35 | Throttle() | |
36 | { | |
37 | d_limit=3; | |
38 | d_ttl=60; | |
39 | d_last_clean=time(0); | |
40 | } | |
87da00e7 | 41 | bool shouldThrottle(time_t now, const Thing& t) |
49f076e8 | 42 | { |
49f076e8 BH |
43 | if(now > d_last_clean + 60 ) { |
44 | d_last_clean=now; | |
45 | for(typename cont_t::iterator i=d_cont.begin();i!=d_cont.end();) | |
46 | if( i->second.ttd > now) { | |
47 | d_cont.erase(i++); | |
48 | } | |
49 | else | |
50 | ++i; | |
51 | } | |
52 | ||
49f076e8 BH |
53 | typename cont_t::iterator i=d_cont.find(t); |
54 | if(i==d_cont.end()) | |
55 | return false; | |
014c60c3 | 56 | if(now > i->second.ttd || i->second.count-- < 0) { |
49f076e8 | 57 | d_cont.erase(i); |
49f076e8 | 58 | } |
014c60c3 BH |
59 | |
60 | return true; // still listed, still blocked | |
49f076e8 | 61 | } |
87da00e7 | 62 | void throttle(time_t now, const Thing& t, unsigned int ttl=0, unsigned int tries=0) |
49f076e8 BH |
63 | { |
64 | typename cont_t::iterator i=d_cont.find(t); | |
87da00e7 | 65 | entry e={ now+(ttl ? ttl : d_ttl), tries ? tries : d_limit}; |
49f076e8 | 66 | |
c214232f | 67 | if(i==d_cont.end()) { |
49f076e8 | 68 | d_cont[t]=e; |
c214232f BH |
69 | } |
70 | else if(i->second.ttd > e.ttd || (i->second.count) < e.count) | |
71 | d_cont[t]=e; | |
8a5602d4 BH |
72 | } |
73 | ||
74 | unsigned int size() | |
75 | { | |
76 | return d_cont.size(); | |
49f076e8 BH |
77 | } |
78 | private: | |
79 | int d_limit; | |
80 | int d_ttl; | |
81 | time_t d_last_clean; | |
82 | struct entry | |
83 | { | |
84 | time_t ttd; | |
85 | int count; | |
86 | }; | |
87 | typedef map<Thing,entry> cont_t; | |
88 | cont_t d_cont; | |
89 | }; | |
90 | ||
91 | ||
eefd15f9 | 92 | /** Class that implements a decaying EWMA. |
36c5ee42 | 93 | This class keeps an exponentially weighted moving average which, additionally, decays over time. |
eefd15f9 BH |
94 | The decaying is only done on get. |
95 | */ | |
96 | class DecayingEwma | |
97 | { | |
98 | public: | |
d6d5dea7 BH |
99 | DecayingEwma() : d_last(getTime()) , d_lastget(d_last), d_val(0.0) { |
100 | ||
36c5ee42 | 101 | } |
d6d5dea7 BH |
102 | |
103 | DecayingEwma(const DecayingEwma& orig) : d_last(orig.d_last), d_lastget(orig.d_lastget), d_val(orig.d_val) | |
eefd15f9 | 104 | { |
d6d5dea7 BH |
105 | |
106 | } | |
107 | ||
108 | void submit(int val, struct timeval*tv = 0) | |
109 | { | |
9fdf67d5 | 110 | float now; |
d6d5dea7 BH |
111 | if(tv) |
112 | now=tv->tv_sec + tv->tv_usec/1000000.0; | |
113 | else | |
114 | now=getTime(); | |
115 | ||
9fdf67d5 | 116 | float diff=d_last-now; |
36c5ee42 | 117 | d_last=now; |
9fdf67d5 | 118 | float factor=exp(diff)/2.0; // might be '0.5', or 0.0001 |
eefd15f9 BH |
119 | d_val=(1-factor)*val+ factor*d_val; |
120 | } | |
d6d5dea7 | 121 | |
9fdf67d5 | 122 | float get(struct timeval*tv = 0) |
eefd15f9 | 123 | { |
9fdf67d5 | 124 | float now; |
d6d5dea7 BH |
125 | if(tv) |
126 | now=tv->tv_sec + tv->tv_usec/1000000.0; | |
127 | else | |
128 | now=getTime(); | |
129 | ||
9fdf67d5 | 130 | float diff=d_lastget-now; |
36c5ee42 | 131 | d_lastget=now; |
9fdf67d5 | 132 | float factor=exp(diff/60.0); // is 1.0 or less |
eefd15f9 BH |
133 | return d_val*=factor; |
134 | } | |
135 | ||
9fdf67d5 BH |
136 | bool stale(time_t limit) |
137 | { | |
138 | return limit > d_lastget; | |
139 | } | |
140 | ||
eefd15f9 | 141 | private: |
d6d5dea7 | 142 | DecayingEwma& operator=(const DecayingEwma&); |
9fdf67d5 BH |
143 | float d_last; |
144 | float d_lastget; | |
145 | float d_val; | |
eefd15f9 BH |
146 | }; |
147 | ||
148 | ||
7b35aa49 | 149 | class SyncRes |
00a19ff7 BH |
150 | { |
151 | public: | |
d6d5dea7 | 152 | SyncRes() : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_cacheonly(false), d_nocache(false) { gettimeofday(&d_now, 0); } |
00a19ff7 | 153 | int beginResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret); |
c836dc19 BH |
154 | void setId(int id) |
155 | { | |
9fdf67d5 BH |
156 | if(s_log) |
157 | d_prefix="["+itoa(id)+"] "; | |
c836dc19 BH |
158 | } |
159 | static void setLog(bool log) | |
160 | { | |
161 | s_log=log; | |
162 | } | |
163 | void setCacheOnly(bool state=true) | |
164 | { | |
165 | d_cacheonly=state; | |
166 | } | |
167 | void setNoCache(bool state=true) | |
168 | { | |
169 | d_nocache=state; | |
170 | } | |
171 | static unsigned int s_queries; | |
7becf07f | 172 | static unsigned int s_outgoingtimeouts; |
3de83124 | 173 | static unsigned int s_throttledqueries; |
c836dc19 | 174 | static unsigned int s_outqueries; |
5c633640 | 175 | static unsigned int s_tcpoutqueries; |
525b8a7c | 176 | static unsigned int s_nodelegated; |
c836dc19 | 177 | unsigned int d_outqueries; |
5c633640 | 178 | unsigned int d_tcpoutqueries; |
3de83124 | 179 | unsigned int d_throttledqueries; |
d77df2e1 | 180 | unsigned int d_timeouts; |
9fdf67d5 BH |
181 | typedef map<string,NegCacheEntry> negcache_t; |
182 | static negcache_t s_negcache; | |
183 | ||
184 | typedef map<string,DecayingEwma> nsspeeds_t; | |
185 | static nsspeeds_t s_nsSpeeds; | |
186 | ||
1d5b3ce6 BH |
187 | typedef Throttle<string> throttle_t; |
188 | static throttle_t s_throttle; | |
00a19ff7 BH |
189 | private: |
190 | struct GetBestNSAnswer; | |
191 | int doResolveAt(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, | |
192 | int depth, set<GetBestNSAnswer>&beenthere); | |
193 | int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere); | |
194 | bool doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res); | |
195 | bool doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res); | |
196 | void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int depth, set<GetBestNSAnswer>& beenthere); | |
197 | void addCruft(const string &qname, vector<DNSResourceRecord>& ret); | |
198 | string getBestNSNamesFromCache(const string &qname,set<string>& nsset, int depth, set<GetBestNSAnswer>&beenthere); | |
199 | void addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth); | |
200 | ||
d8d0bb8f | 201 | inline vector<string> shuffle(set<string> &nameservers, const string &prefix); |
00a19ff7 | 202 | bool moreSpecificThan(const string& a, const string &b); |
bfea0d0b | 203 | vector<string> getAs(const string &qname, int depth, set<GetBestNSAnswer>& beenthere); |
c75a6a9e | 204 | |
36c5ee42 BH |
205 | SyncRes(const SyncRes&); |
206 | SyncRes& operator=(const SyncRes&); | |
00a19ff7 | 207 | private: |
c836dc19 BH |
208 | string d_prefix; |
209 | static bool s_log; | |
210 | bool d_cacheonly; | |
211 | bool d_nocache; | |
7b35aa49 | 212 | LWRes d_lwr; |
d6d5dea7 | 213 | struct timeval d_now; |
c75a6a9e | 214 | |
00a19ff7 BH |
215 | struct GetBestNSAnswer |
216 | { | |
217 | string qname; | |
218 | set<DNSResourceRecord> bestns; | |
219 | bool operator<(const GetBestNSAnswer &b) const | |
220 | { | |
221 | if(qname<b.qname) | |
222 | return true; | |
223 | if(qname==b.qname) | |
224 | return bestns<b.bestns; | |
225 | return false; | |
226 | } | |
227 | }; | |
228 | ||
229 | }; | |
5c633640 BH |
230 | class Socket; |
231 | int asendtcp(const string& data, Socket* sock); | |
232 | int arecvtcp(string& data, int len, Socket* sock); | |
1d5b3ce6 BH |
233 | |
234 | ||
235 | struct PacketID | |
236 | { | |
237 | PacketID() : sock(0), inNeeded(0), outPos(0) | |
238 | {} | |
239 | ||
240 | uint16_t id; // wait for a specific id/remote pair | |
241 | struct sockaddr_in remote; // this is the remote | |
242 | ||
243 | Socket* sock; // or wait for an event on a TCP fd | |
244 | int inNeeded; // if this is set, we'll read until inNeeded bytes are read | |
245 | string inMSG; // they'll go here | |
246 | ||
247 | string outMSG; // the outgoing message that needs to be sent | |
248 | string::size_type outPos; // how far we are along in the outMSG | |
249 | ||
250 | bool operator<(const PacketID& b) const | |
251 | { | |
252 | int ourSock= sock ? sock->getHandle() : 0; | |
253 | int bSock = b.sock ? b.sock->getHandle() : 0; | |
254 | return | |
255 | tie(id, remote.sin_addr.s_addr, remote.sin_port, ourSock) < | |
256 | tie(b.id, b.remote.sin_addr.s_addr, b.remote.sin_port, bSock); | |
257 | } | |
258 | }; | |
259 | ||
260 | extern MemRecursorCache RC; | |
261 | extern uint64_t qcounter; | |
262 | extern MTasker<PacketID,string>* MT; | |
263 | ||
264 | struct RecursorStats | |
265 | { | |
266 | uint64_t servFails; | |
267 | uint64_t nxDomains; | |
268 | uint64_t noErrors; | |
269 | }; | |
270 | ||
271 | extern RecursorStats g_stats; | |
00a19ff7 | 272 | #endif |