• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 12351442937

16 Dec 2024 11:13AM UTC coverage: 64.773% (+0.02%) from 64.751%
12351442937

Pull #14617

github

web-flow
Merge a5962f66f into 2c5c5b828
Pull Request #14617: rec: dedup records

37546 of 88848 branches covered (42.26%)

Branch coverage included in aggregate %.

77 of 77 new or added lines in 8 files covered. (100.0%)

42 existing lines in 12 files now uncovered.

125960 of 163583 relevant lines covered (77.0%)

4425415.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.62
/pdns/misc.hh
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of version 2 of the GNU General Public License as
7
 * published by the Free Software Foundation.
8
 *
9
 * In addition, for the avoidance of any doubt, permission is granted to
10
 * link this program with OpenSSL and to (re)distribute the binaries
11
 * produced as the result of such linking.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 */
22
#pragma once
23
#include <cinttypes>
24
#include <cstring>
25
#include <cstdio>
26
#include <regex.h>
27
#include <climits>
28
#include <type_traits>
29

30
#include <boost/algorithm/string.hpp>
31

32
#include "dns.hh"
33
#include <atomic>
34
#include <sys/time.h>
35
#include <sys/types.h>
36
#include <sys/socket.h>
37
#include <ctime>
38
#include <syslog.h>
39
#include <stdexcept>
40
#include <string>
41
#include <cctype>
42
#include <vector>
43

44
#include "namespaces.hh"
45

46
class DNSName;
47

48
// Do not change to "using TSIGHashEnum ..." until you know CodeQL does not choke on it
49
typedef enum
50
{
51
  TSIG_MD5,
52
  TSIG_SHA1,
53
  TSIG_SHA224,
54
  TSIG_SHA256,
55
  TSIG_SHA384,
56
  TSIG_SHA512,
57
  TSIG_GSS,
58
} TSIGHashEnum;
59

60
namespace pdns
61
{
62
/**
63
 * \brief Retrieves the errno-based error message in a reentrant way.
64
 *
65
 * This internally handles the portability issues around using
66
 * `strerror_r` and returns a `std::string` that owns the error
67
 * message's contents.
68
 *
69
 * \param[in] errnum The errno value.
70
 *
71
 * \return The `std::string` error message.
72
 */
73
auto getMessageFromErrno(int errnum) -> std::string;
74

75
#if defined(HAVE_LIBCRYPTO)
76
namespace OpenSSL
77
{
78
  /**
79
   * \brief Throws a `std::runtime_error` with the current OpenSSL error.
80
   *
81
   * \param[in] errorMessage The message to attach in addition to the OpenSSL error.
82
   */
83
  [[nodiscard]] auto error(const std::string& errorMessage) -> std::runtime_error;
84

85
  /**
86
   * \brief Throws a `std::runtime_error` with a name and the current OpenSSL error.
87
   *
88
   * \param[in] componentName The name of the component to mark the error message with.
89
   * \param[in] errorMessage The message to attach in addition to the OpenSSL error.
90
   */
91
  [[nodiscard]] auto error(const std::string& componentName, const std::string& errorMessage) -> std::runtime_error;
92
}
93
#endif // HAVE_LIBCRYPTO
94
}
95

96
string nowTime();
97
string unquotify(const string &item);
98
string humanDuration(time_t passed);
99
bool stripDomainSuffix(string *qname, const string &domain);
100
void stripLine(string &line);
101
std::optional<string> getHostname();
102
std::string getCarbonHostName();
103
string urlEncode(const string &text);
104
int waitForData(int fileDesc, int seconds, int useconds = 0);
105
int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd);
106
int waitForMultiData(const set<int>& fds, const int seconds, const int useconds, int* fd);
107
int waitForRWData(int fileDesc, bool waitForRead, int seconds, int useconds, bool* error = nullptr, bool* disconnected = nullptr);
108
bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum);
109
DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum);
110

111
int logFacilityToLOG(unsigned int facility);
112

113
template<typename Container>
114
void
115
stringtok (Container &container, string const &in,
116
           const char * const delimiters = " \t\n")
117
{
1,328,769✔
118
  const string::size_type len = in.length();
1,328,769✔
119
  string::size_type i = 0;
1,328,769✔
120

121
  while (i<len) {
3,947,284✔
122
    // eat leading whitespace
123
    i = in.find_first_not_of (delimiters, i);
3,911,027✔
124
    if (i == string::npos)
3,911,027!
125
      return;   // nothing left but white space
2✔
126

127
    // find the end of the token
128
    string::size_type j = in.find_first_of (delimiters, i);
3,911,025✔
129

130
    // push token
131
    if (j == string::npos) {
3,911,025✔
132
      container.push_back (in.substr(i));
1,292,510✔
133
      return;
1,292,510✔
134
    } else
1,292,510✔
135
      container.push_back (in.substr(i, j-i));
2,618,515✔
136

137
    // set up for next loop
138
    i = j + 1;
2,618,515✔
139
  }
2,618,515✔
140
}
1,328,769✔
141

142
template<typename T> bool rfc1982LessThan(T a, T b)
143
{
178✔
144
  static_assert(std::is_unsigned_v<T>, "rfc1982LessThan only works for unsigned types");
178✔
145
  return std::make_signed_t<T>(a - b) < 0;
178✔
146
}
178✔
147

148
// fills container with ranges, so {posbegin,posend}
149
template <typename Container>
150
void
151
vstringtok (Container &container, string const &in,
152
           const char * const delimiters = " \t\n")
153
{
4,416,187✔
154
  const string::size_type len = in.length();
4,416,187✔
155
  string::size_type i = 0;
4,416,187✔
156

157
  while (i<len) {
18,722,814!
158
    // eat leading whitespace
159
    i = in.find_first_not_of (delimiters, i);
18,715,706✔
160
    if (i == string::npos)
18,715,706!
161
      return;   // nothing left but white space
×
162

163
    // find the end of the token
164
    string::size_type j = in.find_first_of (delimiters, i);
18,715,706✔
165

166
    // push token
167
    if (j == string::npos) {
18,715,706✔
168
      container.emplace_back(i, len);
4,409,079✔
169
      return;
4,409,079✔
170
    } else
4,409,079✔
171
      container.emplace_back(i, j);
14,306,627✔
172

173
    // set up for next loop
174
    i = j + 1;
14,306,627✔
175
  }
14,306,627✔
176
}
4,416,187✔
177

178
size_t writen2(int fd, const void *buf, size_t count);
179
inline size_t writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
76✔
180
size_t readn2(int fileDesc, void* buffer, size_t len);
181
size_t readn2WithTimeout(int fd, void* buffer, size_t len, const struct timeval& idleTimeout, const struct timeval& totalTimeout={0,0}, bool allowIncomplete=false);
182
size_t writen2WithTimeout(int fd, const void * buffer, size_t len, const struct timeval& timeout);
183

184
void toLowerInPlace(string& str);
185
const string toLower(const string &upper);
186
const string toLowerCanonic(const string &upper);
187
bool IpToU32(const string &str, uint32_t *ip);
188
string U32ToIP(uint32_t);
189

190
inline string stringerror(int err = errno)
191
{
4,573✔
192
  return pdns::getMessageFromErrno(err);
4,573✔
193
}
4,573✔
194

195
string bitFlip(const string &str);
196

197
void dropPrivs(int uid, int gid);
198
void cleanSlashes(string &str);
199

200
#if defined(_POSIX_THREAD_CPUTIME) && defined(CLOCK_THREAD_CPUTIME_ID)
201
/** CPUTime measurements */
202
class CPUTime
203
{
204
public:
205
  void start()
206
  {
×
207
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &d_start);
×
208
  }
×
209
  uint64_t ndiff()
210
  {
×
211
    struct timespec now;
×
212
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
×
213
    return 1000000000ULL*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec);
×
214
  }
×
215
private:
216
  struct timespec d_start;
217
};
218
#endif
219

220
/** The DTime class can be used for timing statistics with microsecond resolution.
221
On 32 bits systems this means that 2147 seconds is the longest time that can be measured. */
222
class DTime
223
{
224
public:
225
  //!< Does not set the timer for you! Saves lots of gettimeofday() calls
226
  DTime() = default;
2,304,930✔
227
  DTime(const DTime &dt) = default;
228
  DTime & operator=(const DTime &dt) = default;
229
  inline time_t time() const;
230
  inline void set();  //!< Reset the timer
231
  inline int udiff(bool reset = true); //!< Return the number of microseconds since the timer was last set.
232

233
  int udiffNoReset() //!< Return the number of microseconds since the timer was last set.
234
  {
207,311✔
235
    return udiff(false);
207,311✔
236
  }
207,311✔
237
  void setTimeval(const struct timeval& tv)
238
  {
96,990✔
239
    d_set=tv;
96,990✔
240
  }
96,990✔
241
  struct timeval getTimeval() const
242
  {
18,935✔
243
    return d_set;
18,935✔
244
  }
18,935✔
245
private:
246
struct timeval d_set{0, 0};
247
};
248

249
inline time_t DTime::time() const
250
{
×
251
  return d_set.tv_sec;
×
252
}
×
253

254
inline void DTime::set()
255
{
13,803✔
256
  gettimeofday(&d_set, nullptr);
13,803✔
257
}
13,803✔
258

259
inline int DTime::udiff(bool reset)
260
{
489,563✔
261
  struct timeval now;
489,563✔
262
  gettimeofday(&now, nullptr);
489,563✔
263

264
  int ret=1000000*(now.tv_sec-d_set.tv_sec)+(now.tv_usec-d_set.tv_usec);
489,563✔
265

266
  if (reset) {
489,563✔
267
    d_set = now;
282,250✔
268
  }
282,250✔
269

270
  return ret;
489,563✔
271
}
489,563✔
272

273
inline void toLowerInPlace(string& str)
274
{
7,743,556✔
275
  const size_t length = str.length();
7,743,556✔
276
  char c;
7,743,556✔
277
  for (size_t i = 0; i < length; ++i) {
150,321,618✔
278
    c = dns_tolower(str[i]);
142,578,062✔
279
    if (c != str[i]) {
142,578,062✔
280
      str[i] = c;
971,249✔
281
    }
971,249✔
282
  }
142,578,062✔
283
}
7,743,556✔
284

285
inline const string toLower(const string &upper)
286
{
2,620,223✔
287
  string reply(upper);
2,620,223✔
288

289
  toLowerInPlace(reply);
2,620,223✔
290

291
  return reply;
2,620,223✔
292
}
2,620,223✔
293

294
inline const string toLowerCanonic(const string &upper)
295
{
213✔
296
  string reply(upper);
213✔
297
  if(!upper.empty()) {
213!
298
    unsigned int i, limit= ( unsigned int ) reply.length();
213✔
299
    unsigned char c;
213✔
300
    for(i = 0; i < limit ; i++) {
9,941✔
301
      c = dns_tolower(upper[i]);
9,728✔
302
      if(c != upper[i])
9,728!
303
        reply[i] = c;
×
304
    }
9,728✔
305
    if(upper[i-1]=='.')
213!
306
      reply.resize(i-1);
213✔
307
  }
213✔
308

309
  return reply;
213✔
310
}
213✔
311

312

313

314
// Make s uppercase:
315
inline string toUpper( const string& s )
316
{
6,751,697✔
317
        string r(s);
6,751,697✔
318
        for( unsigned int i = 0; i < s.length(); i++ ) {
24,451,600✔
319
          r[i] = dns_toupper(r[i]);
17,699,903✔
320
        }
17,699,903✔
321
        return r;
6,751,697✔
322
}
6,751,697✔
323

324
inline double getTime()
325
{
×
326
  struct timeval now;
×
327
  gettimeofday(&now,0);
×
328

×
329
  return now.tv_sec+now.tv_usec/1000000.0;
×
330
}
×
331

332
[[noreturn]] inline void unixDie(const string &why)
UNCOV
333
{
×
UNCOV
334
  throw runtime_error(why + ": " + stringerror(errno));
×
UNCOV
335
}
×
336

337
string makeHexDump(const string& str);
338
//! Convert the hexstring in to a byte string
339
string makeBytesFromHex(const string &in);
340

341
void normalizeTV(struct timeval& tv);
342
struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs);
343
struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs);
344

345
inline float makeFloat(const struct timeval& tv)
346
{
51,268✔
347
  return tv.tv_sec + tv.tv_usec/1000000.0f;
51,268✔
348
}
51,268✔
349
inline uint64_t uSec(const struct timeval& tv)
350
{
23,486✔
351
  return tv.tv_sec * 1000000 + tv.tv_usec;
23,486✔
352
}
23,486✔
353

354
inline bool operator<(const struct timeval& lhs, const struct timeval& rhs)
355
{
492,540✔
356
  return std::tie(lhs.tv_sec, lhs.tv_usec) < std::tie(rhs.tv_sec, rhs.tv_usec);
492,540✔
357
}
492,540✔
358
inline bool operator<=(const struct timeval& lhs, const struct timeval& rhs)
359
{
8,350✔
360
  return std::tie(lhs.tv_sec, lhs.tv_usec) <= std::tie(rhs.tv_sec, rhs.tv_usec);
8,350✔
361
}
8,350✔
362

363
inline bool operator<(const struct timespec& lhs, const struct timespec& rhs)
364
{
1,121,419✔
365
  return std::tie(lhs.tv_sec, lhs.tv_nsec) < std::tie(rhs.tv_sec, rhs.tv_nsec);
1,121,419✔
366
}
1,121,419✔
367

368

369
inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b)  __attribute__((pure));
370
inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b)
371
{
20,774✔
372
  const unsigned char *aPtr = (const unsigned char*)a.c_str(), *bPtr = (const unsigned char*)b.c_str();
20,774✔
373
  const unsigned char *aEptr = aPtr + a.length(), *bEptr = bPtr + b.length();
20,774✔
374
  while(aPtr != aEptr && bPtr != bEptr) {
78,375✔
375
    if ((*aPtr != *bPtr) && (dns_tolower(*aPtr) - dns_tolower(*bPtr)))
71,363✔
376
      return (dns_tolower(*aPtr) - dns_tolower(*bPtr)) < 0;
13,762✔
377
    aPtr++;
57,601✔
378
    bPtr++;
57,601✔
379
  }
57,601✔
380
  if(aPtr == aEptr && bPtr == bEptr) // strings are equal (in length)
7,012✔
381
    return false;
6,269✔
382
  return aPtr == aEptr; // true if first string was shorter
743✔
383
}
7,012✔
384

385
inline bool pdns_iequals(const std::string& a, const std::string& b) __attribute__((pure));
386
inline bool pdns_iequals(const std::string& a, const std::string& b)
387
{
13,935,122✔
388
  if (a.length() != b.length())
13,935,122✔
389
    return false;
9,359,282✔
390

391
  const char *aPtr = a.c_str(), *bPtr = b.c_str();
4,575,840✔
392
  const char *aEptr = aPtr + a.length();
4,575,840✔
393
  while(aPtr != aEptr) {
15,015,260✔
394
    if((*aPtr != *bPtr) && (dns_tolower(*aPtr) != dns_tolower(*bPtr)))
10,564,093✔
395
      return false;
124,673✔
396
    aPtr++;
10,439,420✔
397
    bPtr++;
10,439,420✔
398
  }
10,439,420✔
399
  return true;
4,451,167✔
400
}
4,575,840✔
401

402
inline bool pdns_iequals_ch(const char a, const char b) __attribute__((pure));
403
inline bool pdns_iequals_ch(const char a, const char b)
404
{
1,443,291✔
405
  if ((a != b) && (dns_tolower(a) != dns_tolower(b)))
1,443,291✔
406
    return false;
1,422,501✔
407

408
  return true;
20,790✔
409
}
1,443,291✔
410

411

412
typedef unsigned long AtomicCounterInner;
413
typedef std::atomic<AtomicCounterInner> AtomicCounter ;
414

415
// FIXME400 this should probably go?
416
struct CIStringCompare
417
{
418
  bool operator()(const string& a, const string& b) const
419
  {
20,606✔
420
    return pdns_ilexicographical_compare(a, b);
20,606✔
421
  }
20,606✔
422
};
423

424
struct CIStringComparePOSIX
425
{
426
   bool operator() (const std::string& lhs, const std::string& rhs) const
427
   {
16,696✔
428
      const std::locale &loc = std::locale("POSIX");
16,696✔
429
      auto lhsIter = lhs.begin();
16,696✔
430
      auto rhsIter = rhs.begin();
16,696✔
431
      while (lhsIter != lhs.end()) {
537,251!
432
        if (rhsIter == rhs.end() || std::tolower(*rhsIter,loc) < std::tolower(*lhsIter,loc)) {
537,251!
433
          return false;
6,489✔
434
        }
6,489✔
435
        if (std::tolower(*lhsIter,loc) < std::tolower(*rhsIter,loc)) {
530,762✔
436
          return true;
10,207✔
437
        }
10,207✔
438
        ++lhsIter;++rhsIter;
520,555✔
439
      }
520,555✔
440
      return rhsIter != rhs.end();
×
441
   }
16,696✔
442
};
443

444
struct CIStringPairCompare
445
{
446
  bool operator()(const pair<string, uint16_t>& a, const pair<string, uint16_t>& b) const
447
  {
93✔
448
    if(pdns_ilexicographical_compare(a.first, b.first))
93✔
449
        return true;
45✔
450
    if(pdns_ilexicographical_compare(b.first, a.first))
48✔
451
        return false;
9✔
452
    return a.second < b.second;
39✔
453
  }
48✔
454
};
455

456
inline size_t pdns_ci_find(const string& haystack, const string& needle)
457
{
81,016✔
458
  string::const_iterator it = std::search(haystack.begin(), haystack.end(),
81,016✔
459
    needle.begin(), needle.end(), pdns_iequals_ch);
81,016✔
460
  if (it == haystack.end()) {
81,016✔
461
    // not found
462
    return string::npos;
81,013✔
463
  } else {
81,013✔
464
    return it - haystack.begin();
3✔
465
  }
3✔
466
}
81,016✔
467

468
pair<string, string> splitField(const string& inp, char sepa);
469

470
inline bool isCanonical(const string& qname)
471
{
4,418,350✔
472
  if(qname.empty())
4,418,350✔
473
    return false;
10✔
474
  return qname[qname.size()-1]=='.';
4,418,340✔
475
}
4,418,350✔
476

477
inline DNSName toCanonic(const DNSName& zone, const string& qname)
478
{
37,082✔
479
  if(qname.size()==1 && qname[0]=='@')
37,082!
480
    return zone;
×
481
  if(isCanonical(qname))
37,082✔
482
    return DNSName(qname);
27,028✔
483
  return DNSName(qname) += zone;
10,054✔
484
}
37,082✔
485

486
string stripDot(const string& dom);
487

488
int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret);
489
int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret);
490
int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret);
491
bool stringfgets(FILE* fp, std::string& line);
492

493
template<typename Index>
494
std::pair<typename Index::iterator,bool>
495
replacing_insert(Index& i,const typename Index::value_type& x)
496
{
2,817✔
497
  std::pair<typename Index::iterator,bool> res=i.insert(x);
2,817✔
498
  if(!res.second)res.second=i.replace(res.first,x);
2,817✔
499
  return res;
2,817✔
500
}
2,817✔
501

502
/** very small regex wrapper */
503
class Regex
504
{
505
public:
506
  /** constructor that accepts the expression to regex */
507
  Regex(const string &expr);
508

509
  ~Regex()
510
  {
20✔
511
    regfree(&d_preg);
20✔
512
  }
20✔
513
  /** call this to find out if 'line' matches your expression */
514
  bool match(const string &line) const
515
  {
3,547✔
516
    return regexec(&d_preg,line.c_str(),0,0,0)==0;
3,547✔
517
  }
3,547✔
518
  bool match(const DNSName& name) const
519
  {
×
520
    return match(name.toStringNoDot());
×
521
  }
×
522

523
private:
524
  regex_t d_preg;
525
};
526

527
class SimpleMatch
528
{
529
public:
530
  SimpleMatch(const string &mask, bool caseFold = false): d_mask(mask), d_fold(caseFold)
531
  {
96✔
532
  }
96✔
533

534
  bool match(string::const_iterator mi, string::const_iterator mend, string::const_iterator vi, string::const_iterator vend) const
535
  {
13,308✔
536
    for(;;++mi) {
21,163✔
537
      if (mi == mend) {
21,163✔
538
        return vi == vend;
30✔
539
      } else if (*mi == '?') {
21,133✔
540
        if (vi == vend) return false;
12✔
541
        ++vi;
9✔
542
      } else if (*mi == '*') {
21,121✔
543
        while(mi != mend && *mi == '*') ++mi;
1,158✔
544
        if (mi == mend) return true;
579✔
545
        while(vi != vend) {
12,696✔
546
          if (match(mi,mend,vi,vend)) return true;
12,156✔
547
          ++vi;
12,141✔
548
        }
12,141✔
549
        return false;
540✔
550
      } else {
20,542✔
551
        if ((mi == mend && vi != vend)||
20,542!
552
            (mi != mend && vi == vend)) return false;
20,542!
553
        if (d_fold) {
20,536✔
554
          if (dns_tolower(*mi) != dns_tolower(*vi)) return false;
20,446✔
555
        } else {
20,536✔
556
          if (*mi != *vi) return false;
90✔
557
        }
90✔
558
        ++vi;
7,846✔
559
      }
7,846✔
560
    }
21,163✔
561
  }
13,308✔
562

563
  bool match(const string& value) const {
1,152✔
564
    return match(d_mask.begin(), d_mask.end(), value.begin(), value.end());
1,152✔
565
  }
1,152✔
566

567
  bool match(const DNSName& name) const {
1,095✔
568
    return match(name.toStringNoDot());
1,095✔
569
  }
1,095✔
570

571
private:
572
  const string d_mask;
573
  const bool d_fold;
574
};
575

576
union ComboAddress;
577

578
// An aligned type to hold cmsgbufs. See https://man.openbsd.org/CMSG_DATA
579
typedef union { struct cmsghdr hdr; char buf[256]; } cmsgbuf_aligned;
580

581
/* itfIndex is an interface index, as returned by if_nametoindex(). 0 means default. */
582
void addCMsgSrcAddr(struct msghdr* msgh, cmsgbuf_aligned* cbuf, const ComboAddress* source, int itfIndex);
583

584
unsigned int getFilenumLimit(bool hardOrSoft=0);
585
void setFilenumLimit(unsigned int lim);
586
bool readFileIfThere(const char* fname, std::string* line);
587
bool setSocketTimestamps(int fd);
588

589
//! Sets the socket into blocking mode.
590
bool setBlocking( int sock );
591

592
//! Sets the socket into non-blocking mode.
593
bool setNonBlocking( int sock );
594
bool setTCPNoDelay(int sock);
595
bool setReuseAddr(int sock);
596
bool isNonBlocking(int sock);
597
bool setReceiveSocketErrors(int sock, int af);
598
int closesocket(int socket);
599
bool setCloseOnExec(int sock);
600

601
size_t getPipeBufferSize(int fd);
602
bool setPipeBufferSize(int fd, size_t size);
603

604
uint64_t udpErrorStats(const std::string& str);
605
uint64_t udp6ErrorStats(const std::string& str);
606
uint64_t tcpErrorStats(const std::string& str);
607
uint64_t getRealMemoryUsage(const std::string&);
608
uint64_t getSpecialMemoryUsage(const std::string&);
609
uint64_t getOpenFileDescriptors(const std::string&);
610
uint64_t getCPUTimeUser(const std::string&);
611
uint64_t getCPUTimeSystem(const std::string&);
612
uint64_t getCPUIOWait(const std::string&);
613
uint64_t getCPUSteal(const std::string&);
614
std::string getMACAddress(const ComboAddress& ca);
615
int getMACAddress(const ComboAddress& ca, char* dest, size_t len);
616

617
template<typename T>
618
const T& defTer(const T& a, const T& b)
619
{
9✔
620
  return a ? a : b;
9!
621
}
9✔
622

623
template<typename P, typename T>
624
T valueOrEmpty(const P val) {
92✔
625
  if (!val) return T{};
92!
626
  return T(val);
92✔
627
}
92✔
628

629

630
// I'm not very OCD, but I appreciate loglines like "processing 1 delta", "processing 2 deltas" :-)
631
template <typename Integer,
632
typename std::enable_if_t<std::is_integral_v<Integer>, bool> = true>
633
const char* addS(Integer siz, const char* singular = "", const char *plural = "s")
634
{
94✔
635
  if (siz == 1) {
94!
636
    return singular;
29✔
637
  }
29✔
638
  return plural;
65✔
639
}
94✔
640

641
template <typename C,
642
typename std::enable_if_t<std::is_class_v<C>, bool> = true>
643
const char* addS(const C& c, const char* singular = "", const char *plural = "s")
644
{
645
  return addS(c.size(), singular, plural);
646
}
647

648
template<typename C>
649
const typename C::value_type::second_type* rplookup(const C& c, const typename C::value_type::first_type& key)
650
{
4,626✔
651
  auto fnd = c.find(key);
4,626✔
652
  if(fnd == c.end())
4,626!
653
    return 0;
69✔
654
  return &fnd->second;
4,557✔
655
}
4,626✔
656

657
double DiffTime(const struct timespec& first, const struct timespec& second);
658
double DiffTime(const struct timeval& first, const struct timeval& second);
659
uid_t strToUID(const string &str);
660
gid_t strToGID(const string &str);
661

662
namespace pdns
663
{
664
/**
665
 * \brief Does a checked conversion from one integer type to another.
666
 *
667
 * \warning The source type `F` and target type `T` must have the same
668
 * signedness, otherwise a compilation error is thrown.
669
 *
670
 * \exception std::out_of_range Thrown if the source value does not fit
671
 * in the target type.
672
 *
673
 * \param[in] from The source value of type `F`.
674
 *
675
 * \return The target value of type `T`.
676
 */
677
template <typename T, typename F>
678
auto checked_conv(F from) -> T
679
{
6,300,195✔
680
  static_assert(std::numeric_limits<F>::is_integer, "checked_conv: The `F` type must be an integer");
6,300,195✔
681
  static_assert(std::numeric_limits<T>::is_integer, "checked_conv: The `T` type must be an integer");
6,300,195✔
682
  static_assert((std::numeric_limits<F>::is_signed && std::numeric_limits<T>::is_signed) || (!std::numeric_limits<F>::is_signed && !std::numeric_limits<T>::is_signed),
6,300,195✔
683
                "checked_conv: The `T` and `F` types must either both be signed or unsigned");
6,300,195✔
684

685
  constexpr auto tMin = std::numeric_limits<T>::min();
6,300,195✔
686
  if constexpr (std::numeric_limits<F>::min() != tMin) {
6,300,195✔
687
    if (from < tMin) {
2,793,335!
688
      string s = "checked_conv: source value " + std::to_string(from) + " is smaller than target's minimum possible value " + std::to_string(tMin);
1,645,928✔
689
      throw std::out_of_range(s);
1,645,928✔
690
    }
1,645,928✔
691
  }
2,793,335✔
692

693
  constexpr auto tMax = std::numeric_limits<T>::max();
2,793,335✔
694
  if constexpr (std::numeric_limits<F>::max() != tMax) {
6,300,195✔
695
    if (from > tMax) {
6,298,492!
696
      string s = "checked_conv: source value " + std::to_string(from) + " is larger than target's maximum possible value " + std::to_string(tMax);
28✔
697
      throw std::out_of_range(s);
28✔
698
    }
28✔
699
  }
6,298,492✔
700

701
  return static_cast<T>(from);
6,298,464✔
702
}
2,793,335✔
703

704
/**
705
 * \brief Performs a conversion from `std::string&` to integer.
706
 *
707
 * This function internally calls `std::stoll` and `std::stoull` to do
708
 * the conversion from `std::string&` and calls `pdns::checked_conv` to
709
 * do the checked conversion from `long long`/`unsigned long long` to
710
 * `T`.
711
 *
712
 * \warning The target type `T` must be an integer, otherwise a
713
 * compilation error is thrown.
714
 *
715
 * \exception std:stoll Throws what std::stoll throws.
716
 *
717
 * \exception std::stoull Throws what std::stoull throws.
718
 *
719
 * \exception pdns::checked_conv Throws what pdns::checked_conv throws.
720
 *
721
 * \param[in] str The input string to be converted.
722
 *
723
 * \param[in] idx Location to store the index at which processing
724
 * stopped. If the input `str` is empty, `*idx` shall be set to 0.
725
 *
726
 * \param[in] base The numerical base for conversion.
727
 *
728
 * \return `str` converted to integer `T`, or 0 if `str` is empty.
729
 */
730
template <typename T>
731
auto checked_stoi(const std::string& str, size_t* idx = nullptr, int base = 10) -> T
732
{
6,318,278✔
733
  static_assert(std::numeric_limits<T>::is_integer, "checked_stoi: The `T` type must be an integer");
6,318,278✔
734

735
  if (str.empty()) {
6,318,278!
736
    if (idx != nullptr) {
16,040!
737
      *idx = 0;
×
738
    }
×
739

740
    return 0; // compatibility
16,040✔
741
  }
16,040✔
742

743
  if constexpr (std::is_unsigned_v<T>) {
6,302,238✔
744
    return pdns::checked_conv<T>(std::stoull(str, idx, base));
2,793,847✔
745
  }
2,793,847✔
746
  else {
2,793,847✔
747
    return pdns::checked_conv<T>(std::stoll(str, idx, base));
2,793,847✔
748
  }
2,793,847✔
749
}
6,302,238✔
750

751
/**
752
 * \brief Performs a conversion from `std::string&` to integer.
753
 *
754
 * This function internally calls `pdns::checked_stoi` and stores its
755
 * result in `out`.
756
 *
757
 * \exception pdns::checked_stoi Throws what pdns::checked_stoi throws.
758
 *
759
 * \param[out] out `str` converted to integer `T`, or 0 if `str` is
760
 * empty.
761
 *
762
 * \param[in] str The input string to be converted.
763
 *
764
 * \param[in] idx Location to store the index at which processing
765
 * stopped. If the input `str` is empty, `*idx` shall be set to 0.
766
 *
767
 * \param[in] base The numerical base for conversion.
768
 *
769
 * \return `str` converted to integer `T`, or 0 if `str` is empty.
770
 */
771
template <typename T>
772
auto checked_stoi_into(T& out, const std::string& str, size_t* idx = nullptr, int base = 10)
773
{
2,663,646✔
774
  out = checked_stoi<T>(str, idx, base);
2,663,646✔
775
}
2,663,646✔
776
}
777

778
bool isSettingThreadCPUAffinitySupported();
779
int mapThreadToCPUList(pthread_t tid, const std::set<int>& cpus);
780

781
std::vector<ComboAddress> getResolvers(const std::string& resolvConfPath);
782

783
DNSName reverseNameFromIP(const ComboAddress& ip);
784

785
size_t parseRFC1035CharString(const std::string &in, std::string &val); // from ragel
786
size_t parseSVCBValueListFromParsedRFC1035CharString(const std::string &in, vector<std::string> &val); // from ragel
787
size_t parseSVCBValueList(const std::string &in, vector<std::string> &val);
788

789
std::string makeLuaString(const std::string& in);
790

791
bool constantTimeStringEquals(const std::string& a, const std::string& b);
792

793
// Used in NID and L64 records
794
struct NodeOrLocatorID { uint8_t content[8]; };
795

796
struct FDWrapper
797
{
798
  FDWrapper() = default;
172,271✔
799
  FDWrapper(int desc): d_fd(desc) {}
276,220✔
800
  FDWrapper(const FDWrapper&) = delete;
801
  FDWrapper& operator=(const FDWrapper& rhs) = delete;
802

803

804
  ~FDWrapper()
805
  {
1,096,471✔
806
    reset();
1,096,471✔
807
  }
1,096,471✔
808

809
  FDWrapper(FDWrapper&& rhs) noexcept : d_fd(rhs.d_fd)
810
  {
541,878✔
811
    rhs.d_fd = -1;
541,878✔
812
  }
541,878✔
813

814
  FDWrapper& operator=(FDWrapper&& rhs) noexcept
815
  {
194,322✔
816
    if (d_fd >= 0) {
194,322✔
817
      close(d_fd);
26✔
818
    }
26✔
819
    d_fd = rhs.d_fd;
194,322✔
820
    rhs.d_fd = -1;
194,322✔
821
    return *this;
194,322✔
822
  }
194,322✔
823

824
  [[nodiscard]] int getHandle() const
825
  {
59,160,592✔
826
    return d_fd;
59,160,592✔
827
  }
59,160,592✔
828

829
  operator int() const
830
  {
1,886✔
831
    return d_fd;
1,886✔
832
  }
1,886✔
833

834
  int reset()
835
  {
1,096,585✔
836
    int ret = 0;
1,096,585✔
837
    if (d_fd >= 0) {
1,096,585✔
838
      ret = close(d_fd);
5,097✔
839
    }
5,097✔
840
    d_fd = -1;
1,096,585✔
841
    return ret;
1,096,585✔
842
  }
1,096,585✔
843

844
private:
845
  int d_fd{-1};
846
};
847

848
namespace pdns
849
{
850
[[nodiscard]] std::optional<std::string> visit_directory(const std::string& directory, const std::function<bool(ino_t inodeNumber, const std::string_view& name)>& visitor);
851

852
struct FilePtrDeleter
853
{
854
  /* using a deleter instead of decltype(&fclose) has two big advantages:
855
     - the deleter is included in the type and does not have to be passed
856
       when creating a new object (easier to use, less memory usage, in theory
857
       better inlining)
858
     - we avoid the annoying "ignoring attributes on template argument ‘int (*)(FILE*)’"
859
       warning from the compiler, which is there because fclose is tagged as __nonnull((1))
860
  */
861
  void operator()(FILE* filePtr) const noexcept {
647✔
862
    fclose(filePtr);
647✔
863
  }
647✔
864
};
865

866
using UniqueFilePtr = std::unique_ptr<FILE, FilePtrDeleter>;
867

868
UniqueFilePtr openFileForWriting(const std::string& filePath, mode_t permissions, bool mustNotExist = true, bool appendIfExists = false);
869
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc