]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/misc.hh
6824417794edf9a673fa3a9ea60bbefd63790115
[thirdparty/pdns.git] / pdns / misc.hh
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002-2012 PowerDNS.COM BV
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 #ifndef MISC_HH
19 #define MISC_HH
20 #include <inttypes.h>
21 #include <cstring>
22 #include <cstdio>
23 #include <regex.h>
24 #include <boost/algorithm/string.hpp>
25 #include <boost/multi_index_container.hpp>
26 #include <boost/multi_index/ordered_index.hpp>
27 #include <boost/tuple/tuple_comparison.hpp>
28 #include <boost/multi_index/key_extractors.hpp>
29 #include <boost/multi_index/sequenced_index.hpp>
30 using namespace ::boost::multi_index;
31 #if 0
32 #include <iostream>
33 using std::cout;
34 using std::endl;
35
36 struct TSCTimer
37 {
38 TSCTimer()
39 {
40 RDTSC(d_tsc1);
41 }
42 ~TSCTimer()
43 {
44 uint64_t tsc2;
45 RDTSC(tsc2);
46 cout<<"Timer: "<< (tsc2 - d_tsc1)/3000.0 << endl;
47 }
48 uint64_t d_tsc1;
49 };
50 #endif
51
52 #include "utility.hh"
53 #include "dns.hh"
54 #include <sys/time.h>
55 #include <sys/types.h>
56 #include <sys/socket.h>
57 #include <time.h>
58 #include <syslog.h>
59 #include <deque>
60 #include <stdexcept>
61 #include <string>
62 #include <ctype.h>
63 #include <vector>
64
65 #include "namespaces.hh"
66 bool chopOff(string &domain);
67 bool chopOffDotted(string &domain);
68
69 bool endsOn(const string &domain, const string &suffix);
70 bool dottedEndsOn(const string &domain, const string &suffix);
71 string nowTime();
72 const string unquotify(const string &item);
73 string humanDuration(time_t passed);
74 bool stripDomainSuffix(string *qname, const string &domain);
75 void stripLine(string &line);
76 string getHostname();
77 string urlEncode(const string &text);
78 int waitForData(int fd, int seconds, int useconds=0);
79 int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd);
80 int waitForRWData(int fd, bool waitForRead, int seconds, int useconds);
81 uint16_t getShort(const unsigned char *p);
82 uint16_t getShort(const char *p);
83 uint32_t getLong(const unsigned char *p);
84 uint32_t getLong(const char *p);
85 int logFacilityToLOG(unsigned int facility);
86
87 struct ServiceTuple
88 {
89 string host;
90 uint16_t port;
91 };
92 void parseService(const string &descr, ServiceTuple &st);
93
94 template <typename Container>
95 void
96 stringtok (Container &container, string const &in,
97 const char * const delimiters = " \t\n")
98 {
99 const string::size_type len = in.length();
100 string::size_type i = 0;
101
102 while (i<len) {
103 // eat leading whitespace
104 i = in.find_first_not_of (delimiters, i);
105 if (i == string::npos)
106 return; // nothing left but white space
107
108 // find the end of the token
109 string::size_type j = in.find_first_of (delimiters, i);
110
111 // push token
112 if (j == string::npos) {
113 container.push_back (in.substr(i));
114 return;
115 } else
116 container.push_back (in.substr(i, j-i));
117
118 // set up for next loop
119 i = j + 1;
120 }
121 }
122
123 template<typename T> bool rfc1982LessThan(T a, T b)
124 {
125 return ((signed)(a - b)) < 0;
126 }
127
128 // fills container with ranges, so {posbegin,posend}
129 template <typename Container>
130 void
131 vstringtok (Container &container, string const &in,
132 const char * const delimiters = " \t\n")
133 {
134 const string::size_type len = in.length();
135 string::size_type i = 0;
136
137 while (i<len) {
138 // eat leading whitespace
139 i = in.find_first_not_of (delimiters, i);
140 if (i == string::npos)
141 return; // nothing left but white space
142
143 // find the end of the token
144 string::size_type j = in.find_first_of (delimiters, i);
145
146 // push token
147 if (j == string::npos) {
148 container.push_back (make_pair(i, len));
149 return;
150 } else
151 container.push_back (make_pair(i, j));
152
153 // set up for next loop
154 i = j + 1;
155 }
156 }
157
158 int writen2(int fd, const void *buf, size_t count);
159 inline int writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
160 int readn2(int fd, void* buffer, unsigned int len);
161
162 const string toLower(const string &upper);
163 const string toLowerCanonic(const string &upper);
164 bool IpToU32(const string &str, uint32_t *ip);
165 string U32ToIP(uint32_t);
166 string stringerror();
167 string netstringerror();
168 string itoa(int i);
169 string uitoa(unsigned int i);
170
171 void dropPrivs(int uid, int gid);
172 int makeGidNumeric(const string &group);
173 int makeUidNumeric(const string &user);
174 void cleanSlashes(string &str);
175
176 /** The DTime class can be used for timing statistics with microsecond resolution.
177 On 32 bits systems this means that 2147 seconds is the longest time that can be measured. */
178 class DTime
179 {
180 public:
181 DTime(); //!< Does not set the timer for you! Saves lots of gettimeofday() calls
182 DTime(const DTime &dt);
183 time_t time();
184 inline void set(); //!< Reset the timer
185 inline int udiff(); //!< Return the number of microseconds since the timer was last set.
186 inline int udiffNoReset(); //!< Return the number of microseconds since the timer was last set.
187 void setTimeval(const struct timeval& tv)
188 {
189 d_set=tv;
190 }
191 struct timeval getTimeval()
192 {
193 return d_set;
194 }
195 private:
196 struct timeval d_set;
197 };
198
199 inline void DTime::set()
200 {
201 Utility::gettimeofday(&d_set,0);
202 }
203
204 inline int DTime::udiff()
205 {
206 int res=udiffNoReset();
207 Utility::gettimeofday(&d_set,0);
208 return res;
209 }
210
211 inline int DTime::udiffNoReset()
212 {
213 struct timeval now;
214
215 Utility::gettimeofday(&now,0);
216 int ret=1000000*(now.tv_sec-d_set.tv_sec)+(now.tv_usec-d_set.tv_usec);
217 return ret;
218 }
219
220
221 inline bool dns_isspace(char c)
222 {
223 return c==' ' || c=='\t' || c=='\r' || c=='\n';
224 }
225
226 inline char dns_tolower(char c)
227 {
228 if(c>='A' && c<='Z')
229 c+='a'-'A';
230 return c;
231 }
232
233 inline const string toLower(const string &upper)
234 {
235 string reply(upper);
236 char c;
237 for(unsigned int i = 0; i < reply.length(); i++) {
238 c = dns_tolower(upper[i]);
239 if( c != upper[i])
240 reply[i] = c;
241 }
242 return reply;
243 }
244
245 inline const string toLowerCanonic(const string &upper)
246 {
247 string reply(upper);
248 if(!upper.empty()) {
249 unsigned int i, limit= ( unsigned int ) reply.length();
250 char c;
251 for(i = 0; i < limit ; i++) {
252 c = dns_tolower(upper[i]);
253 if(c != upper[i])
254 reply[i] = c;
255 }
256 if(upper[i-1]=='.')
257 reply.resize(i-1);
258 }
259
260 return reply;
261 }
262
263
264
265 // Make s uppercase:
266 inline string toUpper( const string& s )
267 {
268 string r(s);
269 for( unsigned int i = 0; i < s.length(); i++ ) {
270 r[i] = toupper( r[i] );
271 }
272 return r;
273 }
274
275 inline double getTime()
276 {
277 struct timeval now;
278 Utility::gettimeofday(&now,0);
279
280 return now.tv_sec+now.tv_usec/1000000.0;
281 }
282
283 inline void unixDie(const string &why)
284 {
285 throw runtime_error(why+": "+strerror(errno));
286 }
287
288 string makeHexDump(const string& str);
289 void shuffle(vector<DNSResourceRecord>& rrs);
290 void orderAndShuffle(vector<DNSResourceRecord>& rrs);
291
292 void normalizeTV(struct timeval& tv);
293 const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs);
294 const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs);
295 inline float makeFloat(const struct timeval& tv)
296 {
297 return tv.tv_sec + tv.tv_usec/1000000.0f;
298 }
299
300 inline bool operator<(const struct timeval& lhs, const struct timeval& rhs)
301 {
302 return make_pair(lhs.tv_sec, lhs.tv_usec) < make_pair(rhs.tv_sec, rhs.tv_usec);
303 }
304
305 inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) __attribute__((pure));
306 inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b)
307 {
308 const unsigned char *aPtr = (const unsigned char*)a.c_str(), *bPtr = (const unsigned char*)b.c_str();
309
310 while(*aPtr && *bPtr) {
311 if ((*aPtr != *bPtr) && (dns_tolower(*aPtr) - dns_tolower(*bPtr)))
312 return (dns_tolower(*aPtr) - dns_tolower(*bPtr)) < 0;
313 aPtr++;
314 bPtr++;
315 }
316 if(!*aPtr && !*bPtr) // strings are equal (in length)
317 return false;
318 return !*aPtr; // true if first string was shorter
319 }
320
321 inline bool pdns_iequals(const std::string& a, const std::string& b) __attribute__((pure));
322 inline bool pdns_iequals(const std::string& a, const std::string& b)
323 {
324 if (a.length() != b.length())
325 return false;
326
327 const char *aPtr = a.c_str(), *bPtr = b.c_str();
328 while(*aPtr) {
329 if((*aPtr != *bPtr) && (dns_tolower(*aPtr) != dns_tolower(*bPtr)))
330 return false;
331 aPtr++;
332 bPtr++;
333 }
334 return true;
335 }
336
337 // lifted from boost, with thanks
338 class AtomicCounter
339 {
340 public:
341
342 explicit AtomicCounter( unsigned int v = 0) : value_( v ) {}
343
344 unsigned int operator++()
345 {
346 return atomic_exchange_and_add( &value_, +1 ) + 1;
347 }
348
349 unsigned int operator++(int)
350 {
351 return atomic_exchange_and_add( &value_, +1 );
352 }
353
354 unsigned int operator--()
355 {
356 return atomic_exchange_and_add( &value_, -1 ) - 1;
357 }
358
359 operator unsigned int() const
360 {
361 return atomic_exchange_and_add( &value_, 0);
362 }
363
364 AtomicCounter(AtomicCounter const &rhs) : value_(rhs)
365 {
366 }
367
368 private:
369 mutable unsigned int value_;
370
371 // the below is necessary because __sync_fetch_and_add is not universally available on i386.. I 3> RHEL5.
372 #if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
373 static int atomic_exchange_and_add( unsigned int * pw, int dv )
374 {
375 // int r = *pw;
376 // *pw += dv;
377 // return r;
378
379 int r;
380
381 __asm__ __volatile__
382 (
383 "lock\n\t"
384 "xadd %1, %0":
385 "+m"( *pw ), "=r"( r ): // outputs (%0, %1)
386 "1"( dv ): // inputs (%2 == %1)
387 "memory", "cc" // clobbers
388 );
389
390 return r;
391 }
392 #else
393 static int atomic_exchange_and_add( unsigned int * pw, int dv )
394 {
395 return __sync_fetch_and_add(pw, dv);
396 }
397 #endif
398 };
399
400
401 struct CIStringCompare: public std::binary_function<string, string, bool>
402 {
403 bool operator()(const string& a, const string& b) const
404 {
405 return pdns_ilexicographical_compare(a, b);
406 }
407 };
408
409 struct CIStringComparePOSIX
410 {
411 bool operator() (const std::string& lhs, const std::string& rhs)
412 {
413 std::string::const_iterator a,b;
414 const std::locale &loc = std::locale("POSIX");
415 a=lhs.begin();b=rhs.begin();
416 while(a!=lhs.end()) {
417 if (b==rhs.end() || std::tolower(*b,loc)<std::tolower(*a,loc)) return false;
418 else if (std::tolower(*a,loc)<std::tolower(*b,loc)) return true;
419 a++;b++;
420 }
421 return (b!=rhs.end());
422 }
423 };
424
425 struct CIStringPairCompare: public std::binary_function<pair<string, uint16_t>, pair<string,uint16_t>, bool>
426 {
427 bool operator()(const pair<string, uint16_t>& a, const pair<string, uint16_t>& b) const
428 {
429 if(pdns_ilexicographical_compare(a.first, b.first))
430 return true;
431 if(pdns_ilexicographical_compare(b.first, a.first))
432 return false;
433 return a.second < b.second;
434 }
435 };
436
437
438 pair<string, string> splitField(const string& inp, char sepa);
439
440 inline bool isCanonical(const string& dom)
441 {
442 if(dom.empty())
443 return false;
444 return dom[dom.size()-1]=='.';
445 }
446
447 inline string toCanonic(const string& zone, const string& domain)
448 {
449 if(domain.length()==1 && domain[0]=='@')
450 return zone;
451
452 if(isCanonical(domain))
453 return domain;
454 string ret=domain;
455 ret.append(1,'.');
456 if(!zone.empty() && zone[0]!='.')
457 ret.append(zone);
458 return ret;
459 }
460
461 inline void setSocketReusable(int fd)
462 {
463 int tmp=1;
464 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, static_cast<unsigned>(sizeof tmp));
465 }
466
467 string stripDot(const string& dom);
468 void seedRandom(const string& source);
469 string makeRelative(const std::string& fqdn, const std::string& zone);
470 string labelReverse(const std::string& qname);
471 std::string dotConcat(const std::string& a, const std::string &b);
472 int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret);
473 int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret);
474 int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret);
475 bool stringfgets(FILE* fp, std::string& line);
476
477 template<typename Index>
478 std::pair<typename Index::iterator,bool>
479 replacing_insert(Index& i,const typename Index::value_type& x)
480 {
481 std::pair<typename Index::iterator,bool> res=i.insert(x);
482 if(!res.second)res.second=i.replace(res.first,x);
483 return res;
484 }
485
486 /** very small regex wrapper */
487 class Regex
488 {
489 public:
490 /** constructor that accepts the expression to regex */
491 Regex(const string &expr);
492
493 ~Regex()
494 {
495 regfree(&d_preg);
496 }
497 /** call this to find out if 'line' matches your expression */
498 bool match(const string &line)
499 {
500 return regexec(&d_preg,line.c_str(),0,0,0)==0;
501 }
502
503 private:
504 regex_t d_preg;
505 };
506
507 #endif