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

PowerDNS / pdns / 19937114032

04 Dec 2025 05:00PM UTC coverage: 73.093% (-0.04%) from 73.131%
19937114032

Pull #16598

github

web-flow
Merge bdc1eb026 into a67907d2f
Pull Request #16598: Codeql remove unused variables

38530 of 63422 branches covered (60.75%)

Branch coverage included in aggregate %.

128087 of 164529 relevant lines covered (77.85%)

6073228.55 hits per line

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

85.03
/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 <string_view>
42
#include <cctype>
43
#include <utility>
44
#include <vector>
45

46
#include "namespaces.hh"
47

48
class DNSName;
49
#if defined(PDNS_AUTH)
50
class ZoneName;
51
#else
52
using ZoneName = DNSName;
53
#endif
54

55
// Do not change to "using TSIGHashEnum ..." until you know CodeQL does not choke on it
56
typedef enum
57
{
58
  TSIG_MD5,
59
  TSIG_SHA1,
60
  TSIG_SHA224,
61
  TSIG_SHA256,
62
  TSIG_SHA384,
63
  TSIG_SHA512,
64
  TSIG_GSS,
65
} TSIGHashEnum;
66

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

82
#if defined(HAVE_LIBCRYPTO)
83
namespace OpenSSL
84
{
85
  /**
86
   * \brief Throws a `std::runtime_error` with the current OpenSSL error.
87
   *
88
   * \param[in] errorMessage The message to attach in addition to the OpenSSL error.
89
   */
90
  [[nodiscard]] auto error(const std::string& errorMessage) -> std::runtime_error;
91

92
  /**
93
   * \brief Throws a `std::runtime_error` with a name and the current OpenSSL error.
94
   *
95
   * \param[in] componentName The name of the component to mark the error message with.
96
   * \param[in] errorMessage The message to attach in addition to the OpenSSL error.
97
   */
98
  [[nodiscard]] auto error(const std::string& componentName, const std::string& errorMessage) -> std::runtime_error;
99
}
100
#endif // HAVE_LIBCRYPTO
101
}
102

103
string nowTime();
104
string unquotify(const string &item);
105
string humanDuration(time_t passed);
106
void stripLine(string &line);
107
std::optional<string> getHostname();
108
std::string getCarbonHostName();
109
string urlEncode(const string &text);
110
int waitForData(int fileDesc, int seconds, int mseconds = 0);
111
int waitForData(int fileDesc, struct timeval timeout);
112
int waitForMultiData(const set<int>& fds, const int seconds, const int mseconds, int* fd);
113
int waitForRWData(int fileDesc, bool waitForRead, int seconds, int mseconds, bool* error = nullptr, bool* disconnected = nullptr);
114
int waitForRWData(int fileDesc, bool waitForRead, struct timeval timeout, bool* error = nullptr, bool* disconnected = nullptr);
115
bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum);
116
DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum);
117

118
int logFacilityToLOG(unsigned int facility);
119
std::optional<int> logFacilityFromString(std::string facilityStr);
120

121
template<typename Container>
122
void
123
stringtok (Container &container, string const &in,
124
           const char * const delimiters = " \t\n")
125
{
168,844✔
126
  const string::size_type len = in.length();
168,844✔
127
  string::size_type i = 0;
168,844✔
128

129
  while (i<len) {
703,783✔
130
    // eat leading whitespace
131
    i = in.find_first_not_of (delimiters, i);
635,483✔
132
    if (i == string::npos)
635,483!
133
      return;   // nothing left but white space
2✔
134

135
    // find the end of the token
136
    string::size_type j = in.find_first_of (delimiters, i);
635,481✔
137

138
    // push token
139
    if (j == string::npos) {
635,481✔
140
      container.push_back (in.substr(i));
100,542✔
141
      return;
100,542✔
142
    } else
100,542✔
143
      container.push_back (in.substr(i, j-i));
534,939✔
144

145
    // set up for next loop
146
    i = j + 1;
534,939✔
147
  }
534,939✔
148
}
168,844✔
149

150
template<typename T> bool rfc1982LessThan(T lhs, T rhs)
151
{
234✔
152
  static_assert(std::is_unsigned_v<T>, "rfc1982LessThan only works for unsigned types");
234✔
153
  return static_cast<std::make_signed_t<T>>(lhs - rhs) < 0;
234✔
154
}
234✔
155

156
template<typename T> bool rfc1982LessThanOrEqual(T lhs, T rhs)
157
{
29,839✔
158
  static_assert(std::is_unsigned_v<T>, "rfc1982LessThanOrEqual only works for unsigned types");
29,839✔
159
  return static_cast<std::make_signed_t<T>>(lhs - rhs) <= 0;
29,839✔
160
}
29,839✔
161

162
// fills container with ranges, so {posbegin,posend}
163
template <typename Container>
164
void
165
vstringtok (Container &container, string const &in,
166
           const char * const delimiters = " \t\n")
167
{
4,318,804✔
168
  const string::size_type len = in.length();
4,318,804✔
169
  string::size_type i = 0;
4,318,804✔
170

171
  while (i<len) {
18,342,385✔
172
    // eat leading whitespace
173
    i = in.find_first_not_of (delimiters, i);
18,334,999✔
174
    if (i == string::npos)
18,334,999!
175
      return;   // nothing left but white space
×
176

177
    // find the end of the token
178
    string::size_type j = in.find_first_of (delimiters, i);
18,334,999✔
179

180
    // push token
181
    if (j == string::npos) {
18,334,999✔
182
      container.emplace_back(i, len);
4,311,418✔
183
      return;
4,311,418✔
184
    } else
4,311,418✔
185
      container.emplace_back(i, j);
14,023,581✔
186

187
    // set up for next loop
188
    i = j + 1;
14,023,581✔
189
  }
14,023,581✔
190
}
4,318,804✔
191

192
size_t writen2(int fd, const void *buf, size_t count);
193
inline size_t writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
88✔
194
size_t readn2(int fileDesc, void* buffer, size_t len);
195
size_t readn2WithTimeout(int fd, void* buffer, size_t len, const struct timeval& idleTimeout, const struct timeval& totalTimeout={0,0}, bool allowIncomplete=false);
196
size_t writen2WithTimeout(int fd, const void * buffer, size_t len, const struct timeval& timeout);
197

198
void toLowerInPlace(string& str);
199
const string toLower(const string &upper);
200
const string toLowerCanonic(const string &upper);
201
bool IpToU32(const string &str, uint32_t *ip);
202
string U32ToIP(uint32_t);
203

204
inline string stringerror(int err = errno)
205
{
1,592✔
206
  return pdns::getMessageFromErrno(err);
1,592✔
207
}
1,592✔
208

209
void dropPrivs(int uid, int gid);
210
void cleanSlashes(string &str);
211

212
#if defined(_POSIX_THREAD_CPUTIME) && defined(CLOCK_THREAD_CPUTIME_ID)
213
/** CPUTime measurements */
214
class CPUTime
215
{
216
public:
217
  void start()
218
  {
×
219
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &d_start);
×
220
  }
×
221
  uint64_t ndiff()
222
  {
×
223
    struct timespec now;
×
224
    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
×
225
    return 1000000000ULL*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec);
×
226
  }
×
227
private:
228
  struct timespec d_start;
229
};
230
#endif
231

232
/** The DTime class can be used for timing statistics with microsecond resolution.
233
On 32 bits systems this means that 2147 seconds is the longest time that can be measured. */
234
class DTime
235
{
236
public:
237
  //!< Does not set the timer for you! Saves lots of gettimeofday() calls
238
  DTime() = default;
2,445,758✔
239
  DTime(const DTime &dt) = default;
240
  DTime & operator=(const DTime &dt) = default;
241
  inline time_t time() const;
242
  inline void set();  //!< Reset the timer
243
  inline int udiff(bool reset = true); //!< Return the number of microseconds since the timer was last set.
244

245
  int udiffNoReset() //!< Return the number of microseconds since the timer was last set.
246
  {
257,547✔
247
    return udiff(false);
257,547✔
248
  }
257,547✔
249
  void setTimeval(const struct timeval& tv)
250
  {
126,477✔
251
    d_set=tv;
126,477✔
252
  }
126,477✔
253
  struct timeval getTimeval() const
254
  {
21,467✔
255
    return d_set;
21,467✔
256
  }
21,467✔
257
private:
258
struct timeval d_set{0, 0};
259
};
260

261
inline time_t DTime::time() const
262
{
×
263
  return d_set.tv_sec;
×
264
}
×
265

266
inline void DTime::set()
267
{
15,301✔
268
  gettimeofday(&d_set, nullptr);
15,301✔
269
}
15,301✔
270

271
inline int DTime::udiff(bool reset)
272
{
638,130✔
273
  struct timeval now;
638,130✔
274
  gettimeofday(&now, nullptr);
638,130✔
275

276
  int ret=1000000*(now.tv_sec-d_set.tv_sec)+(now.tv_usec-d_set.tv_usec);
638,130✔
277

278
  if (reset) {
638,131✔
279
    d_set = now;
371,525✔
280
  }
371,525✔
281

282
  return ret;
638,130✔
283
}
638,130✔
284

285
inline void toLowerInPlace(string& str)
286
{
8,527,950✔
287
  const size_t length = str.length();
8,527,950✔
288
  char c;
8,527,950✔
289
  for (size_t i = 0; i < length; ++i) {
162,853,710✔
290
    c = dns_tolower(str[i]);
154,325,760✔
291
    if (c != str[i]) {
154,325,760✔
292
      str[i] = c;
994,364✔
293
    }
994,364✔
294
  }
154,325,760✔
295
}
8,527,950✔
296

297
inline const string toLower(const string &upper)
298
{
2,941,408✔
299
  string reply(upper);
2,941,408✔
300

301
  toLowerInPlace(reply);
2,941,408✔
302

303
  return reply;
2,941,408✔
304
}
2,941,408✔
305

306
inline const string toLowerCanonic(const string &upper)
307
{
218✔
308
  string reply(upper);
218✔
309
  if (!reply.empty()) {
218!
310
    const auto length = reply.length();
218✔
311
    if (reply[length - 1] == '.') {
218!
312
      reply.resize(length - 1);
218✔
313
    }
218✔
314
    toLowerInPlace(reply);
218✔
315
  }
218✔
316
  return reply;
218✔
317
}
218✔
318

319
// Make s uppercase:
320
inline string toUpper( const string& s )
321
{
6,732,830✔
322
  string r(s);
6,732,830✔
323
  for (size_t i = 0; i < s.length(); ++i) {
24,612,258✔
324
    r[i] = dns_toupper(r[i]);
17,879,428✔
325
  }
17,879,428✔
326
  return r;
6,732,830✔
327
}
6,732,830✔
328

329
inline double getTime()
330
{
×
331
  struct timeval now;
×
332
  gettimeofday(&now,0);
×
333

×
334
  return now.tv_sec+now.tv_usec/1000000.0;
×
335
}
×
336

337
[[noreturn]] inline void unixDie(const string &why)
338
{
×
339
  throw runtime_error(why + ": " + stringerror(errno));
×
340
}
×
341

342
string makeHexDump(const string& str, const string& sep = " ");
343
//! Convert the hexstring to a byte string
344
string makeBytesFromHex(const string &in);
345

346
void normalizeTV(struct timeval& tv);
347
struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs);
348
struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs);
349

350
inline float makeFloat(const struct timeval& tv)
351
{
60,356✔
352
  return tv.tv_sec + tv.tv_usec/1000000.0f;
60,356✔
353
}
60,356✔
354
inline uint64_t uSec(const struct timeval& tv)
355
{
32,206✔
356
  return tv.tv_sec * 1000000 + tv.tv_usec;
32,206✔
357
}
32,206✔
358

359
inline bool operator<(const struct timeval& lhs, const struct timeval& rhs)
360
{
597,825✔
361
  return std::tie(lhs.tv_sec, lhs.tv_usec) < std::tie(rhs.tv_sec, rhs.tv_usec);
597,825✔
362
}
597,825✔
363
inline bool operator<=(const struct timeval& lhs, const struct timeval& rhs)
364
{
4,247✔
365
  return std::tie(lhs.tv_sec, lhs.tv_usec) <= std::tie(rhs.tv_sec, rhs.tv_usec);
4,247✔
366
}
4,247✔
367

368
inline bool operator<(const struct timespec& lhs, const struct timespec& rhs)
369
{
380,845✔
370
  return std::tie(lhs.tv_sec, lhs.tv_nsec) < std::tie(rhs.tv_sec, rhs.tv_nsec);
380,845✔
371
}
380,845✔
372

373

374
inline int pdns_ilexicographical_compare_three_way(std::string_view a, std::string_view b)  __attribute__((pure));
375
inline int pdns_ilexicographical_compare_three_way(std::string_view a, std::string_view b)
376
{
143,843,135✔
377
  const unsigned char *aPtr = (const unsigned char*)a.data(), *bPtr = (const unsigned char*)b.data();
143,843,135✔
378
  const unsigned char *aEptr = aPtr + a.length(), *bEptr = bPtr + b.length();
143,843,135✔
379
  while(aPtr != aEptr && bPtr != bEptr) {
731,841,134✔
380
    if (*aPtr != *bPtr) {
710,510,264✔
381
      if (int rc = dns_tolower(*aPtr) - dns_tolower(*bPtr); rc != 0) {
122,517,587✔
382
        return rc;
122,512,265✔
383
      }
122,512,265✔
384
    }
122,509,718✔
385
    aPtr++;
587,997,999✔
386
    bPtr++;
587,997,999✔
387
  }
587,997,999✔
388
  // At this point, one of the strings has been completely processed.
389
  // Either both have the same length, and they are equal, or one of them
390
  // is larger, and compares as higher.
391
  if (aPtr == aEptr) {
21,353,301✔
392
    if (bPtr != bEptr) {
18,436,375✔
393
      return -1; // a < b
142,171✔
394
    }
142,171✔
395
  }
18,436,375✔
396
  else {
2,150,400,573✔
397
    return 1; // a > b
2,150,400,573✔
398
  }
2,150,400,573✔
399
  return 0; // a == b
18,294,204✔
400
}
21,330,870✔
401

402
inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b)  __attribute__((pure));
403
inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b)
404
{
20,603✔
405
  return pdns_ilexicographical_compare_three_way(a, b) < 0;
20,603✔
406
}
20,603✔
407

408
inline bool pdns_iequals(const std::string& a, const std::string& b) __attribute__((pure));
409
inline bool pdns_iequals(const std::string& a, const std::string& b)
410
{
13,793,929✔
411
  if (a.length() != b.length())
13,793,929✔
412
    return false;
9,289,809✔
413

414
  return pdns_ilexicographical_compare_three_way(a, b) == 0;
4,504,120✔
415
}
13,793,929✔
416

417
inline bool pdns_iequals_ch(const char a, const char b) __attribute__((pure));
418
inline bool pdns_iequals_ch(const char a, const char b)
419
{
×
420
  if ((a != b) && (dns_tolower(a) != dns_tolower(b)))
×
421
    return false;
×
422

423
  return true;
×
424
}
×
425

426

427
typedef unsigned long AtomicCounterInner;
428
typedef std::atomic<AtomicCounterInner> AtomicCounter ;
429

430
// FIXME400 this should probably go?
431
struct CIStringCompare
432
{
433
  bool operator()(const string& a, const string& b) const
434
  {
20,435✔
435
    return pdns_ilexicographical_compare(a, b);
20,435✔
436
  }
20,435✔
437
};
438

439
struct CIStringComparePOSIX
440
{
441
   bool operator() (const std::string& lhs, const std::string& rhs) const
442
   {
16,609✔
443
      const std::locale &loc = std::locale("POSIX");
16,609✔
444
      auto lhsIter = lhs.begin();
16,609✔
445
      auto rhsIter = rhs.begin();
16,609✔
446
      while (lhsIter != lhs.end()) {
536,383!
447
        if (rhsIter == rhs.end() || std::tolower(*rhsIter,loc) < std::tolower(*lhsIter,loc)) {
536,383!
448
          return false;
6,595✔
449
        }
6,595✔
450
        if (std::tolower(*lhsIter,loc) < std::tolower(*rhsIter,loc)) {
529,788✔
451
          return true;
10,014✔
452
        }
10,014✔
453
        ++lhsIter;++rhsIter;
519,774✔
454
      }
519,774✔
455
      return rhsIter != rhs.end();
×
456
   }
16,609✔
457
};
458

459
struct CIStringPairCompare
460
{
461
  bool operator()(const pair<string, uint16_t>& a, const pair<string, uint16_t>& b) const
462
  {
93✔
463
    if(pdns_ilexicographical_compare(a.first, b.first))
93✔
464
        return true;
45✔
465
    if(pdns_ilexicographical_compare(b.first, a.first))
48✔
466
        return false;
9✔
467
    return a.second < b.second;
39✔
468
  }
48✔
469
};
470

471
inline size_t pdns_ci_find(const string& haystack, const string& needle)
472
{
×
473
  string::const_iterator it = std::search(haystack.begin(), haystack.end(),
×
474
    needle.begin(), needle.end(), pdns_iequals_ch);
×
475
  if (it == haystack.end()) {
×
476
    // not found
477
    return string::npos;
×
478
  } else {
×
479
    return it - haystack.begin();
×
480
  }
×
481
}
×
482

483
pair<string, string> splitField(const string& inp, char sepa);
484

485
inline bool isCanonical(std::string_view qname)
486
{
4,321,198✔
487
  return boost::ends_with(qname, ".");
4,321,198✔
488
}
4,321,198✔
489

490
inline DNSName toCanonic(const ZoneName& zone, const string& qname)
491
{
37,893✔
492
  if(qname.size()==1 && qname[0]=='@')
37,893!
493
    return DNSName(zone);
×
494
  if(isCanonical(qname))
37,893✔
495
    return DNSName(qname);
27,762✔
496
  return DNSName(qname) += DNSName(zone);
10,131✔
497
}
37,893✔
498

499
string stripDot(const string& dom);
500

501
int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret);
502
int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret);
503
int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret);
504
bool stringfgets(FILE* fp, std::string& line);
505

506
template<typename Index>
507
std::pair<typename Index::iterator,bool>
508
replacing_insert(Index& i,const typename Index::value_type& x)
509
{
2,815✔
510
  std::pair<typename Index::iterator,bool> res=i.insert(x);
2,815✔
511
  if(!res.second)res.second=i.replace(res.first,x);
2,815✔
512
  return res;
2,815✔
513
}
2,815✔
514

515
/** very small regex wrapper */
516
class Regex
517
{
518
public:
519
  /** constructor that accepts the expression to regex */
520
  Regex(const string &expr);
521
  Regex(const Regex&) = delete;
522
  Regex& operator=(const Regex&) = delete;
523
  Regex(Regex&& rhs) = default;
23✔
524
  Regex& operator=(Regex&& rhs) = default;
525
  ~Regex() = default;
240✔
526
  /** call this to find out if 'line' matches your expression */
527
  bool match(const string &line) const;
528
  bool match(const DNSName& name) const;
529

530
private:
531
  struct Deleter
532
  {
533
    void operator()(regex_t* ptr) const noexcept {
217✔
534
      regfree(ptr);
217✔
535
      delete ptr;
217✔
536
    }
217✔
537
  };
538

539
  std::unique_ptr<regex_t, Deleter> d_preg;
540
};
541

542
class SimpleMatch
543
{
544
public:
545
  SimpleMatch(string mask, bool caseFold = false) :
546
    d_mask(std::move(mask)), d_fold(caseFold)
547
  {
112✔
548
  }
112✔
549

550
  bool match(string::const_iterator mi, string::const_iterator mend, string::const_iterator vi, string::const_iterator vend) const
551
  {
2,320,346✔
552
    for(;;++mi) {
2,391,604✔
553
      if (mi == mend) {
2,391,604✔
554
        return vi == vend;
38✔
555
      } else if (*mi == '?') {
2,391,566✔
556
        if (vi == vend) return false;
12✔
557
        ++vi;
9✔
558
      } else if (*mi == '*') {
2,391,554✔
559
        while(mi != mend && *mi == '*') ++mi;
246,240✔
560
        if (mi == mend) return true;
123,120✔
561
        while(vi != vend) {
2,238,023✔
562
          if (match(mi,mend,vi,vend)) return true;
2,114,970✔
563
          ++vi;
2,114,941✔
564
        }
2,114,941✔
565
        return false;
123,053✔
566
      } else {
2,268,434✔
567
        if ((mi == mend && vi != vend)||
2,268,434!
568
            (mi != mend && vi == vend)) return false;
2,268,434!
569
        if (d_fold) {
2,266,136✔
570
          if (dns_tolower(*mi) != dns_tolower(*vi)) return false;
2,266,046✔
571
        } else {
2,266,136✔
572
          if (*mi != *vi) return false;
90✔
573
        }
90✔
574
        ++vi;
71,249✔
575
      }
71,249✔
576
    }
2,391,604✔
577
  }
2,320,346✔
578

579
  bool match(const string& value) const {
205,376✔
580
    return match(d_mask.begin(), d_mask.end(), value.begin(), value.end());
205,376✔
581
  }
205,376✔
582

583
  bool match(const DNSName& name) const {
101,968✔
584
    return match(name.toStringNoDot());
101,968✔
585
  }
101,968✔
586

587
#if defined(PDNS_AUTH) // [
588
  bool match(const ZoneName& name) const {
1,400✔
589
    return match(name.toStringNoDot());
1,400✔
590
  }
1,400✔
591
#endif // ]
592

593
private:
594
  const string d_mask;
595
  const bool d_fold;
596
};
597

598
union ComboAddress;
599

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

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

606
unsigned int getFilenumLimit(bool hardOrSoft=0);
607
void setFilenumLimit(unsigned int lim);
608
bool readFileIfThere(const char* fname, std::string* line);
609
bool setSocketTimestamps(int fd);
610

611
//! Sets the socket into blocking mode.
612
bool setBlocking( int sock );
613

614
void setDscp(int sock, unsigned short family, uint8_t dscp);
615

616
//! Sets the socket into non-blocking mode.
617
bool setNonBlocking( int sock );
618
bool setTCPNoDelay(int sock);
619
bool setReuseAddr(int sock);
620
bool isNonBlocking(int sock);
621
bool setReceiveSocketErrors(int sock, int af);
622
int closesocket(int socket);
623
bool setCloseOnExec(int sock);
624

625
size_t getPipeBufferSize(int fd);
626
bool setPipeBufferSize(int fd, size_t size);
627

628
uint64_t udpErrorStats(const std::string& str);
629
uint64_t udp6ErrorStats(const std::string& str);
630
uint64_t tcpErrorStats(const std::string& str);
631
uint64_t getRealMemoryUsage(const std::string&);
632
uint64_t getSpecialMemoryUsage(const std::string&);
633
uint64_t getOpenFileDescriptors(const std::string&);
634
uint64_t getCPUTimeUser(const std::string&);
635
uint64_t getCPUTimeSystem(const std::string&);
636
uint64_t getCPUIOWait(const std::string&);
637
uint64_t getCPUSteal(const std::string&);
638
std::string getMACAddress(const ComboAddress& ca);
639
int getMACAddress(const ComboAddress& ca, char* dest, size_t len);
640

641
template<typename T>
642
const T& defTer(const T& a, const T& b)
643
{
9✔
644
  return a ? a : b;
9!
645
}
9✔
646

647
template<typename P, typename T>
648
T valueOrEmpty(const P val) {
92✔
649
  if (!val) return T{};
92!
650
  return T(val);
92✔
651
}
92✔
652

653

654
// I'm not very OCD, but I appreciate loglines like "processing 1 delta", "processing 2 deltas" :-)
655
template <typename Integer,
656
typename std::enable_if_t<std::is_integral_v<Integer>, bool> = true>
657
const char* addS(Integer siz, const char* singular = "", const char *plural = "s")
658
{
100✔
659
  if (siz == 1) {
100!
660
    return singular;
34✔
661
  }
34✔
662
  return plural;
66✔
663
}
100✔
664

665
template <typename C,
666
typename std::enable_if_t<std::is_class_v<C>, bool> = true>
667
const char* addS(const C& c, const char* singular = "", const char *plural = "s")
668
{
669
  return addS(c.size(), singular, plural);
670
}
671

672
template<typename C>
673
const typename C::value_type::second_type* rplookup(const C& c, const typename C::value_type::first_type& key)
674
{
5,491✔
675
  auto fnd = c.find(key);
5,491✔
676
  if(fnd == c.end())
5,491!
677
    return 0;
68✔
678
  return &fnd->second;
5,423✔
679
}
5,491✔
680

681
double DiffTime(const struct timespec& first, const struct timespec& second);
682
double DiffTime(const struct timeval& first, const struct timeval& second);
683
uid_t strToUID(const string &str);
684
gid_t strToGID(const string &str);
685

686
namespace pdns
687
{
688
/**
689
 * \brief Does a checked conversion from one integer type to another.
690
 *
691
 * \warning The source type `F` and target type `T` must have the same
692
 * signedness, otherwise a compilation error is thrown.
693
 *
694
 * \exception std::out_of_range Thrown if the source value does not fit
695
 * in the target type.
696
 *
697
 * \param[in] from The source value of type `F`.
698
 *
699
 * \return The target value of type `T`.
700
 */
701
template <typename T, typename F>
702
auto checked_conv(F from) -> T
703
{
5,745,650✔
704
  static_assert(std::numeric_limits<F>::is_integer, "checked_conv: The `F` type must be an integer");
5,745,650✔
705
  static_assert(std::numeric_limits<T>::is_integer, "checked_conv: The `T` type must be an integer");
5,745,650✔
706
  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),
5,745,650✔
707
                "checked_conv: The `T` and `F` types must either both be signed or unsigned");
5,745,650✔
708

709
  constexpr auto tMin = std::numeric_limits<T>::min();
5,745,650✔
710
  if constexpr (std::numeric_limits<F>::min() != tMin) {
5,399,563✔
711
    if (from < tMin) {
1,751,630!
712
      string s = "checked_conv: source value " + std::to_string(from) + " is smaller than target's minimum possible value " + std::to_string(tMin);
529,470✔
713
      throw std::out_of_range(s);
529,470✔
714
    }
529,470✔
715
  }
1,751,630✔
716

717
  constexpr auto tMax = std::numeric_limits<T>::max();
2,097,717✔
718
  if constexpr (std::numeric_limits<F>::max() != tMax) {
5,745,650✔
719
    if (from > tMax) {
5,744,366✔
720
      string s = "checked_conv: source value " + std::to_string(from) + " is larger than target's maximum possible value " + std::to_string(tMax);
30✔
721
      throw std::out_of_range(s);
30✔
722
    }
30✔
723
  }
5,744,366✔
724

725
  return static_cast<T>(from);
5,744,334✔
726
}
2,120,878✔
727

728
/**
729
 * \brief Performs a conversion from `std::string&` to integer.
730
 *
731
 * This function internally calls `std::stoll` and `std::stoull` to do
732
 * the conversion from `std::string&` and calls `pdns::checked_conv` to
733
 * do the checked conversion from `long long`/`unsigned long long` to
734
 * `T`.
735
 *
736
 * \warning The target type `T` must be an integer, otherwise a
737
 * compilation error is thrown.
738
 *
739
 * \exception std:stoll Throws what std::stoll throws.
740
 *
741
 * \exception std::stoull Throws what std::stoull throws.
742
 *
743
 * \exception pdns::checked_conv Throws what pdns::checked_conv throws.
744
 *
745
 * \param[in] str The input string to be converted.
746
 *
747
 * \param[in] idx Location to store the index at which processing
748
 * stopped. If the input `str` is empty, `*idx` shall be set to 0.
749
 *
750
 * \param[in] base The numerical base for conversion.
751
 *
752
 * \return `str` converted to integer `T`, or 0 if `str` is empty.
753
 */
754
template <typename T>
755
auto checked_stoi(const std::string& str, size_t* idx = nullptr, int base = 10) -> T
756
{
5,763,669✔
757
  static_assert(std::numeric_limits<T>::is_integer, "checked_stoi: The `T` type must be an integer");
5,763,669✔
758

759
  if (str.empty()) {
5,763,669!
760
    if (idx != nullptr) {
17,166!
761
      *idx = 0;
×
762
    }
×
763

764
    return 0; // compatibility
17,166✔
765
  }
17,166✔
766

767
  if constexpr (std::is_unsigned_v<T>) {
5,746,503✔
768
    return pdns::checked_conv<T>(std::stoull(str, idx, base));
2,121,851✔
769
  }
1,752,081✔
770
  else {
1,752,087✔
771
    return pdns::checked_conv<T>(std::stoll(str, idx, base));
1,752,087✔
772
  }
1,752,087✔
773
}
5,746,503✔
774

775
/**
776
 * \brief Performs a conversion from `std::string&` to integer.
777
 *
778
 * This function internally calls `pdns::checked_stoi` and stores its
779
 * result in `out`.
780
 *
781
 * \exception pdns::checked_stoi Throws what pdns::checked_stoi throws.
782
 *
783
 * \param[out] out `str` converted to integer `T`, or 0 if `str` is
784
 * empty.
785
 *
786
 * \param[in] str The input string to be converted.
787
 *
788
 * \param[in] idx Location to store the index at which processing
789
 * stopped. If the input `str` is empty, `*idx` shall be set to 0.
790
 *
791
 * \param[in] base The numerical base for conversion.
792
 *
793
 * \return `str` converted to integer `T`, or 0 if `str` is empty.
794
 */
795
template <typename T>
796
auto checked_stoi_into(T& out, const std::string& str, size_t* idx = nullptr, int base = 10)
797
{
2,811,266✔
798
  out = checked_stoi<T>(str, idx, base);
2,811,266✔
799
}
2,811,266✔
800
}
801

802
bool isSettingThreadCPUAffinitySupported();
803
int mapThreadToCPUList(pthread_t tid, const std::set<int>& cpus);
804

805
std::vector<ComboAddress> getResolvers(const std::string& resolvConfPath);
806

807
DNSName reverseNameFromIP(const ComboAddress& ip);
808

809
size_t parseRFC1035CharString(std::string_view in, std::string &val); // from ragel
810
size_t parseSVCBValueListFromParsedRFC1035CharString(const std::string &in, vector<std::string> &val); // from ragel
811
size_t parseSVCBValueList(const std::string &in, vector<std::string> &val);
812

813
std::string makeLuaString(const std::string& in);
814

815
bool constantTimeStringEquals(const std::string& a, const std::string& b);
816

817
// Used in NID and L64 records
818
struct NodeOrLocatorID { uint8_t content[8]; };
819

820
struct FDWrapper
821
{
822
  FDWrapper() = default;
23,374✔
823
  FDWrapper(int desc): d_fd(desc) {}
30,166✔
824
  FDWrapper(const FDWrapper&) = delete;
825
  FDWrapper& operator=(const FDWrapper& rhs) = delete;
826

827

828
  ~FDWrapper()
829
  {
93,008✔
830
    reset();
93,008✔
831
  }
93,008✔
832

833
  FDWrapper(FDWrapper&& rhs) noexcept : d_fd(rhs.d_fd)
75,818✔
834
  {
79,712✔
835
    rhs.d_fd = -1;
79,712✔
836
  }
79,712✔
837

838
  FDWrapper& operator=(FDWrapper&& rhs) noexcept
839
  {
23,692✔
840
    if (d_fd >= 0) {
23,692✔
841
      close(d_fd);
8✔
842
    }
8✔
843
    d_fd = rhs.d_fd;
23,692✔
844
    rhs.d_fd = -1;
23,692✔
845
    return *this;
23,692✔
846
  }
23,692✔
847

848
  [[nodiscard]] int getHandle() const
849
  {
9,749,790✔
850
    return d_fd;
9,749,790✔
851
  }
9,749,790✔
852

853
  operator int() const
854
  {
8,863✔
855
    return d_fd;
8,863✔
856
  }
8,863✔
857

858
  int reset()
859
  {
93,031✔
860
    int ret = 0;
93,031✔
861
    if (d_fd >= 0) { // NOLINT(clang-analyzer-core.UndefinedBinaryOperatorResult): obvious false positive
93,031✔
862
      ret = close(d_fd);
1,200✔
863
    }
1,200✔
864
    d_fd = -1;
93,031✔
865
    return ret;
93,031✔
866
  }
93,031✔
867

868
  int release()
869
  {
574✔
870
    auto ret = d_fd;
574✔
871
    d_fd = -1;
574✔
872
    return ret;
574✔
873
  }
574✔
874

875
private:
876
  int d_fd{-1};
877
};
878

879
namespace pdns
880
{
881
[[nodiscard]] std::optional<std::string> visit_directory(const std::string& directory, const std::function<bool(ino_t inodeNumber, const std::string_view& name)>& visitor);
882

883
struct FilePtrDeleter
884
{
885
  /* using a deleter instead of decltype(&fclose) has two big advantages:
886
     - the deleter is included in the type and does not have to be passed
887
       when creating a new object (easier to use, less memory usage, in theory
888
       better inlining)
889
     - we avoid the annoying "ignoring attributes on template argument ‘int (*)(FILE*)’"
890
       warning from the compiler, which is there because fclose is tagged as __nonnull((1))
891
  */
892
  void operator()(FILE* filePtr) const noexcept {
604✔
893
    fclose(filePtr);
604✔
894
  }
604✔
895
};
896

897
using UniqueFilePtr = std::unique_ptr<FILE, FilePtrDeleter>;
898

899
UniqueFilePtr openFileForWriting(const std::string& filePath, mode_t permissions, bool mustNotExist = true, bool appendIfExists = false);
900
}
901

902
using timebuf_t = std::array<char, 64>;
903
const char* timestamp(time_t arg, timebuf_t& buf);
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