]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/misc.hh
limit compression pointers to 14 bits
[thirdparty/pdns.git] / pdns / misc.hh
CommitLineData
12c86877 1/*
12471842
PL
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 */
ea76bac0 22#pragma once
2a9094ef 23#include <errno.h>
61b26744 24#include <inttypes.h>
8b3cfcd3 25#include <cstring>
f9822705 26#include <cstdio>
3ee84c3f 27#include <regex.h>
58044407 28#include <limits.h>
88bf3279 29#include <type_traits>
ec6480f3 30#include <boost/algorithm/string.hpp>
f0db590d
BH
31#include <boost/multi_index_container.hpp>
32#include <boost/multi_index/ordered_index.hpp>
33#include <boost/tuple/tuple_comparison.hpp>
34#include <boost/multi_index/key_extractors.hpp>
35#include <boost/multi_index/sequenced_index.hpp>
d190894c 36
f0db590d 37using namespace ::boost::multi_index;
12c86877 38
e67e250f 39#include "dns.hh"
ac0995bb 40#include <atomic>
76473b92
KM
41#include <sys/time.h>
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <time.h>
45#include <syslog.h>
3de83124 46#include <deque>
a640a9d4 47#include <stdexcept>
12c86877
BH
48#include <string>
49#include <ctype.h>
e67e250f
BH
50#include <vector>
51
10f4eea8 52#include "namespaces.hh"
d72aaada
KM
53#include "dnsname.hh"
54
bcb5b94e 55typedef enum { TSIG_MD5, TSIG_SHA1, TSIG_SHA224, TSIG_SHA256, TSIG_SHA384, TSIG_SHA512, TSIG_GSS } TSIGHashEnum;
da15912b 56
cc3afe25 57string nowTime();
1d329048 58const string unquotify(const string &item);
12c86877 59string humanDuration(time_t passed);
f2c11a48 60bool stripDomainSuffix(string *qname, const string &domain);
12c86877
BH
61void stripLine(string &line);
62string getHostname();
63string urlEncode(const string &text);
a7d50153 64int waitForData(int fd, int seconds, int useconds=0);
f4ff5929 65int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd);
d529011f 66int waitForMultiData(const set<int>& fds, const int seconds, const int useconds, int* fd);
51959320 67int waitForRWData(int fd, bool waitForRead, int seconds, int useconds, bool* error=nullptr, bool* disconnected=nullptr);
092f210a
BH
68uint16_t getShort(const unsigned char *p);
69uint16_t getShort(const char *p);
70uint32_t getLong(const unsigned char *p);
71uint32_t getLong(const char *p);
21a3792f
KM
72bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum);
73DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum);
58044407 74
f8499e52 75int logFacilityToLOG(unsigned int facility);
bbce5bf0 76
12c86877
BH
77struct ServiceTuple
78{
79 string host;
092f210a 80 uint16_t port;
12c86877
BH
81};
82void parseService(const string &descr, ServiceTuple &st);
83
84template <typename Container>
85void
86stringtok (Container &container, string const &in,
87 const char * const delimiters = " \t\n")
88{
89 const string::size_type len = in.length();
90 string::size_type i = 0;
3ddb9247 91
12c86877
BH
92 while (i<len) {
93 // eat leading whitespace
94 i = in.find_first_not_of (delimiters, i);
95 if (i == string::npos)
96 return; // nothing left but white space
3ddb9247 97
12c86877
BH
98 // find the end of the token
99 string::size_type j = in.find_first_of (delimiters, i);
3ddb9247 100
12c86877
BH
101 // push token
102 if (j == string::npos) {
103 container.push_back (in.substr(i));
104 return;
105 } else
106 container.push_back (in.substr(i, j-i));
3ddb9247 107
12c86877
BH
108 // set up for next loop
109 i = j + 1;
110 }
111}
8c3149f2 112
f7a69a4c
RA
113template<typename T> bool rfc1982LessThan(T a, T b)
114{
115 return ((signed)(a - b)) < 0;
116}
117
0ab3fdc6 118// fills container with ranges, so {posbegin,posend}
8c3149f2
BH
119template <typename Container>
120void
121vstringtok (Container &container, string const &in,
122 const char * const delimiters = " \t\n")
123{
124 const string::size_type len = in.length();
125 string::size_type i = 0;
3ddb9247 126
8c3149f2
BH
127 while (i<len) {
128 // eat leading whitespace
129 i = in.find_first_not_of (delimiters, i);
130 if (i == string::npos)
131 return; // nothing left but white space
3ddb9247 132
8c3149f2
BH
133 // find the end of the token
134 string::size_type j = in.find_first_of (delimiters, i);
3ddb9247 135
8c3149f2
BH
136 // push token
137 if (j == string::npos) {
138 container.push_back (make_pair(i, len));
139 return;
140 } else
141 container.push_back (make_pair(i, j));
3ddb9247 142
8c3149f2
BH
143 // set up for next loop
144 i = j + 1;
145 }
146}
147
a683e8bd
RG
148size_t writen2(int fd, const void *buf, size_t count);
149inline size_t writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
150size_t readn2(int fd, void* buffer, size_t len);
9396d955 151size_t readn2WithTimeout(int fd, void* buffer, size_t len, int idleTimeout, int totalTimeout=0);
a683e8bd 152size_t writen2WithTimeout(int fd, const void * buffer, size_t len, int timeout);
040712e0 153
c3d9d009 154const string toLower(const string &upper);
b0d4fb45 155const string toLowerCanonic(const string &upper);
092f210a 156bool IpToU32(const string &str, uint32_t *ip);
5730f30c 157string U32ToIP(uint32_t);
12c86877 158string stringerror();
d3b4137e 159string netstringerror();
12c86877 160string itoa(int i);
22c9c86a 161string uitoa(unsigned int i);
d88babea 162string bitFlip(const string &str);
12c86877
BH
163
164void dropPrivs(int uid, int gid);
12c86877
BH
165void cleanSlashes(string &str);
166
c6d04bdc 167#if defined(_POSIX_THREAD_CPUTIME) && defined(CLOCK_THREAD_CPUTIME_ID)
df13e61d 168/** CPUTime measurements */
169class CPUTime
170{
171public:
172 void start()
173 {
174 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &d_start);
175 }
176 uint64_t ndiff()
177 {
178 struct timespec now;
179 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
180 return 1000000000ULL*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec);
181 }
182private:
183 struct timespec d_start;
184};
3ddb9247 185#endif
df13e61d 186
3ddb9247 187/** The DTime class can be used for timing statistics with microsecond resolution.
12c86877 188On 32 bits systems this means that 2147 seconds is the longest time that can be measured. */
3ddb9247 189class DTime
12c86877
BH
190{
191public:
eefd15f9 192 DTime(); //!< Does not set the timer for you! Saves lots of gettimeofday() calls
12c86877
BH
193 DTime(const DTime &dt);
194 time_t time();
195 inline void set(); //!< Reset the timer
196 inline int udiff(); //!< Return the number of microseconds since the timer was last set.
62c3a7b8 197 inline int udiffNoReset(); //!< Return the number of microseconds since the timer was last set.
88358c9b
BH
198 void setTimeval(const struct timeval& tv)
199 {
200 d_set=tv;
201 }
202 struct timeval getTimeval()
203 {
204 return d_set;
205 }
12c86877
BH
206private:
207 struct timeval d_set;
208};
85db02c5 209
12c86877
BH
210inline void DTime::set()
211{
15ad1a99 212 gettimeofday(&d_set,0);
12c86877
BH
213}
214
215inline int DTime::udiff()
62c3a7b8
BH
216{
217 int res=udiffNoReset();
15ad1a99 218 gettimeofday(&d_set,0);
62c3a7b8
BH
219 return res;
220}
221
222inline int DTime::udiffNoReset()
12c86877
BH
223{
224 struct timeval now;
12c86877 225
15ad1a99 226 gettimeofday(&now,0);
fe213470 227 int ret=1000000*(now.tv_sec-d_set.tv_sec)+(now.tv_usec-d_set.tv_usec);
fe213470 228 return ret;
12c86877
BH
229}
230
c3d9d009 231inline const string toLower(const string &upper)
12c86877
BH
232{
233 string reply(upper);
2b3eefc3 234 const size_t length = reply.length();
c536ca8d 235 char c;
2b3eefc3 236 for(unsigned int i = 0; i < length; ++i) {
e3cacd48
BH
237 c = dns_tolower(upper[i]);
238 if( c != upper[i])
c536ca8d
BH
239 reply[i] = c;
240 }
12c86877
BH
241 return reply;
242}
243
b0d4fb45
BH
244inline const string toLowerCanonic(const string &upper)
245{
246 string reply(upper);
247 if(!upper.empty()) {
705f31ae 248 unsigned int i, limit= ( unsigned int ) reply.length();
1352c9b6 249 unsigned char c;
c536ca8d 250 for(i = 0; i < limit ; i++) {
e3cacd48
BH
251 c = dns_tolower(upper[i]);
252 if(c != upper[i])
4957a608 253 reply[i] = c;
3ddb9247 254 }
e3cacd48 255 if(upper[i-1]=='.')
b0d4fb45
BH
256 reply.resize(i-1);
257 }
3ddb9247 258
b0d4fb45
BH
259 return reply;
260}
261
262
12c86877 263
52936200
BH
264// Make s uppercase:
265inline string toUpper( const string& s )
266{
4957a608
BH
267 string r(s);
268 for( unsigned int i = 0; i < s.length(); i++ ) {
315f45a0 269 r[i] = dns_toupper(r[i]);
4957a608
BH
270 }
271 return r;
52936200
BH
272}
273
a6d7640a
BH
274inline double getTime()
275{
276 struct timeval now;
15ad1a99 277 gettimeofday(&now,0);
3ddb9247 278
a6d7640a
BH
279 return now.tv_sec+now.tv_usec/1000000.0;
280}
281
a640a9d4
BH
282inline void unixDie(const string &why)
283{
284 throw runtime_error(why+": "+strerror(errno));
285}
286
2db9c30e 287string makeHexDump(const string& str);
4950b140 288struct DNSRecord;
c77eccee 289struct DNSZoneRecord;
4950b140 290void shuffle(vector<DNSRecord>& rrs);
d190894c 291void shuffle(vector<DNSZoneRecord>& rrs);
90ba52e0 292
e325f20c 293void orderAndShuffle(vector<DNSRecord>& rrs);
88358c9b
BH
294
295void normalizeTV(struct timeval& tv);
296const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs);
297const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs);
298inline float makeFloat(const struct timeval& tv)
299{
705f31ae 300 return tv.tv_sec + tv.tv_usec/1000000.0f;
88358c9b 301}
5b0ddd18 302
3ddb9247 303inline bool operator<(const struct timeval& lhs, const struct timeval& rhs)
5b0ddd18
BH
304{
305 return make_pair(lhs.tv_sec, lhs.tv_usec) < make_pair(rhs.tv_sec, rhs.tv_usec);
306}
307
80a216c9 308inline bool operator<(const struct timespec& lhs, const struct timespec& rhs)
309{
310 return tie(lhs.tv_sec, lhs.tv_nsec) < tie(rhs.tv_sec, rhs.tv_nsec);
311}
312
313
ec6480f3 314inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) __attribute__((pure));
8fb5b29a 315inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b)
7738a23f 316{
97a24230 317 const unsigned char *aPtr = (const unsigned char*)a.c_str(), *bPtr = (const unsigned char*)b.c_str();
7fd7a590 318 const unsigned char *aEptr = aPtr + a.length(), *bEptr = bPtr + b.length();
319 while(aPtr != aEptr && bPtr != bEptr) {
8fb5b29a
KM
320 if ((*aPtr != *bPtr) && (dns_tolower(*aPtr) - dns_tolower(*bPtr)))
321 return (dns_tolower(*aPtr) - dns_tolower(*bPtr)) < 0;
322 aPtr++;
323 bPtr++;
7738a23f 324 }
7fd7a590 325 if(aPtr == aEptr && bPtr == bEptr) // strings are equal (in length)
8fb5b29a 326 return false;
7fd7a590 327 return aPtr == aEptr; // true if first string was shorter
ec6480f3 328}
eff65ff8 329
ec6480f3 330inline bool pdns_iequals(const std::string& a, const std::string& b) __attribute__((pure));
8fb5b29a 331inline bool pdns_iequals(const std::string& a, const std::string& b)
ec6480f3 332{
8fb5b29a
KM
333 if (a.length() != b.length())
334 return false;
335
ec6480f3 336 const char *aPtr = a.c_str(), *bPtr = b.c_str();
b10795de 337 const char *aEptr = aPtr + a.length();
338 while(aPtr != aEptr) {
8fb5b29a
KM
339 if((*aPtr != *bPtr) && (dns_tolower(*aPtr) != dns_tolower(*bPtr)))
340 return false;
341 aPtr++;
342 bPtr++;
eff65ff8 343 }
8fb5b29a 344 return true;
ec6480f3
BH
345}
346
57cb86d8
CH
347inline bool pdns_iequals_ch(const char a, const char b) __attribute__((pure));
348inline bool pdns_iequals_ch(const char a, const char b)
349{
350 if ((a != b) && (dns_tolower(a) != dns_tolower(b)))
351 return false;
352
353 return true;
354}
355
1566533a 356
00c6f2b9
RG
357typedef unsigned long AtomicCounterInner;
358typedef std::atomic<AtomicCounterInner> AtomicCounter ;
1bc9e6bd 359
ac0995bb 360// FIXME400 this should probably go?
3ddb9247 361struct CIStringCompare: public std::binary_function<string, string, bool>
ec6480f3
BH
362{
363 bool operator()(const string& a, const string& b) const
eff65ff8 364 {
ec6480f3 365 return pdns_ilexicographical_compare(a, b);
eff65ff8 366 }
7738a23f 367};
eff65ff8 368
2aa1b703
AT
369struct CIStringComparePOSIX
370{
371 bool operator() (const std::string& lhs, const std::string& rhs)
372 {
373 std::string::const_iterator a,b;
374 const std::locale &loc = std::locale("POSIX");
375 a=lhs.begin();b=rhs.begin();
376 while(a!=lhs.end()) {
377 if (b==rhs.end() || std::tolower(*b,loc)<std::tolower(*a,loc)) return false;
378 else if (std::tolower(*a,loc)<std::tolower(*b,loc)) return true;
4b5da564 379 ++a;++b;
2aa1b703
AT
380 }
381 return (b!=rhs.end());
382 }
383};
384
3ddb9247 385struct CIStringPairCompare: public std::binary_function<pair<string, uint16_t>, pair<string,uint16_t>, bool>
21f0f88b
BH
386{
387 bool operator()(const pair<string, uint16_t>& a, const pair<string, uint16_t>& b) const
388 {
389 if(pdns_ilexicographical_compare(a.first, b.first))
390 return true;
391 if(pdns_ilexicographical_compare(b.first, a.first))
392 return false;
393 return a.second < b.second;
394 }
395};
396
57cb86d8
CH
397inline size_t pdns_ci_find(const string& haystack, const string& needle)
398{
399 string::const_iterator it = std::search(haystack.begin(), haystack.end(),
400 needle.begin(), needle.end(), pdns_iequals_ch);
401 if (it == haystack.end()) {
402 // not found
403 return string::npos;
404 } else {
405 return it - haystack.begin();
406 }
407}
21f0f88b 408
50c79a76 409pair<string, string> splitField(const string& inp, char sepa);
26cd1b3f 410
e720f311 411inline bool isCanonical(const string& qname)
26cd1b3f 412{
e720f311 413 if(qname.empty())
26cd1b3f 414 return false;
e720f311 415 return qname[qname.size()-1]=='.';
26cd1b3f
BH
416}
417
e720f311 418inline DNSName toCanonic(const DNSName& zone, const string& qname)
675fa24c 419{
e720f311 420 if(qname.size()==1 && qname[0]=='@')
8171ab83 421 return zone;
e720f311 422 if(isCanonical(qname))
8171ab83 423 return DNSName(qname);
e720f311 424 return DNSName(qname) += zone;
26cd1b3f 425}
da042e6e
BH
426
427string stripDot(const string& dom);
561434a6 428
f71bc087 429int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret);
76cb4593
CH
430int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret);
431int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret);
834942f1 432bool stringfgets(FILE* fp, std::string& line);
f0db590d
BH
433
434template<typename Index>
435std::pair<typename Index::iterator,bool>
436replacing_insert(Index& i,const typename Index::value_type& x)
437{
438 std::pair<typename Index::iterator,bool> res=i.insert(x);
439 if(!res.second)res.second=i.replace(res.first,x);
440 return res;
441}
442
3ee84c3f
BH
443/** very small regex wrapper */
444class Regex
445{
446public:
447 /** constructor that accepts the expression to regex */
448 Regex(const string &expr);
3ddb9247 449
3ee84c3f
BH
450 ~Regex()
451 {
452 regfree(&d_preg);
453 }
454 /** call this to find out if 'line' matches your expression */
6eecd4c2 455 bool match(const string &line) const
3ee84c3f
BH
456 {
457 return regexec(&d_preg,line.c_str(),0,0,0)==0;
458 }
6eecd4c2 459 bool match(const DNSName& name) const
60ee1829
AT
460 {
461 return match(name.toStringNoDot());
462 }
463
3ee84c3f
BH
464private:
465 regex_t d_preg;
466};
467
ac84f00c
AT
468class SimpleMatch
469{
470public:
8a70e507 471 SimpleMatch(const string &mask, bool caseFold = false): d_mask(mask), d_fold(caseFold)
ac84f00c 472 {
ac84f00c
AT
473 }
474
475 bool match(string::const_iterator mi, string::const_iterator mend, string::const_iterator vi, string::const_iterator vend)
476 {
4b5da564 477 for(;;++mi) {
ac84f00c
AT
478 if (mi == mend) {
479 return vi == vend;
480 } else if (*mi == '?') {
481 if (vi == vend) return false;
4b5da564 482 ++vi;
ac84f00c 483 } else if (*mi == '*') {
4b5da564 484 while(*mi == '*') ++mi;
ac84f00c
AT
485 if (mi == d_mask.end()) return true;
486 while(vi != vend) {
487 if (match(mi,mend,vi,vend)) return true;
4b5da564 488 ++vi;
ac84f00c
AT
489 }
490 return false;
491 } else {
492 if ((mi == mend && vi != vend)||
493 (mi != mend && vi == vend)) return false;
494 if (d_fold) {
495 if (dns_tolower(*mi) != dns_tolower(*vi)) return false;
496 } else {
497 if (*mi != *vi) return false;
498 }
4b5da564 499 ++vi;
ac84f00c
AT
500 }
501 }
502 }
503
504 bool match(const string& value) {
505 return match(d_mask.begin(), d_mask.end(), value.begin(), value.end());
506 }
507
508 bool match(const DNSName& name) {
509 return match(name.toStringNoDot());
510 }
511
512private:
513 string d_mask;
514 bool d_fold;
515};
516
65d8e171 517union ComboAddress;
7bec330a 518
00692909 519// An aligned type to hold cmsgbufs. See https://man.openbsd.org/CMSG_DATA
7bec330a
OM
520typedef union { struct cmsghdr hdr; char buf[256]; } cmsgbuf_aligned;
521
fbe2a2e0 522/* itfIndex is an interface index, as returned by if_nametoindex(). 0 means default. */
7bec330a 523void addCMsgSrcAddr(struct msghdr* msgh, cmsgbuf_aligned* cbuf, const ComboAddress* source, int itfIndex);
3a8a4d68 524
525unsigned int getFilenumLimit(bool hardOrSoft=0);
526void setFilenumLimit(unsigned int lim);
4e9a20e6 527bool readFileIfThere(const char* fname, std::string* line);
5c57a75a 528uint32_t burtle(const unsigned char* k, uint32_t length, uint32_t init);
915b0c39 529bool setSocketTimestamps(int fd);
15ad1a99 530
531//! Sets the socket into blocking mode.
532bool setBlocking( int sock );
533
534//! Sets the socket into non-blocking mode.
535bool setNonBlocking( int sock );
883a30a7 536bool setTCPNoDelay(int sock);
bf676f2f 537bool setReuseAddr(int sock);
18861f97 538bool isNonBlocking(int sock);
29bb743c 539bool setReceiveSocketErrors(int sock, int af);
3897b9e1 540int closesocket(int fd);
541bool setCloseOnExec(int sock);
74ad42dc 542
ee271fc4
RG
543size_t getPipeBufferSize(int fd);
544bool setPipeBufferSize(int fd, size_t size);
545
546uint64_t udpErrorStats(const std::string& str);
a1a787dc 547uint64_t getRealMemoryUsage(const std::string&);
330dcb5c 548uint64_t getSpecialMemoryUsage(const std::string&);
a9b6db56 549uint64_t getOpenFileDescriptors(const std::string&);
4f99f3d3
RG
550uint64_t getCPUTimeUser(const std::string&);
551uint64_t getCPUTimeSystem(const std::string&);
6907f014 552std::string getMACAddress(const ComboAddress& ca);
74ad42dc 553template<typename T, typename... Args>
554std::unique_ptr<T> make_unique(Args&&... args)
555{
556 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
557}
1c150f27 558
559
560template<typename T>
561const T& defTer(const T& a, const T& b)
562{
563 return a ? a : b;
564}
3555371a
AT
565
566template<typename P, typename T>
567T valueOrEmpty(const P val) {
568 if (!val) return T{};
569 return T(val);
570}
f5f96ff1 571
88bf3279 572
f5f96ff1 573// I'm not very OCD, but I appreciate loglines like "processing 1 delta", "processing 2 deltas" :-)
88bf3279 574template <typename Integer>
575const char* addS(Integer siz, typename std::enable_if<std::is_integral<Integer>::value>::type*P=0)
f5f96ff1 576{
f5f96ff1 577 if(!siz || siz > 1)
578 return "s";
579 else return "";
580}
88bf3279 581
582template<typename C>
583const char* addS(const C& c, typename std::enable_if<std::is_class<C>::value>::type*P=0)
584{
585 return addS(c.size());
586}
587
2ac8ae89 588template<typename C>
589const typename C::value_type::second_type* rplookup(const C& c, const typename C::value_type::first_type& key)
590{
591 auto fnd = c.find(key);
592 if(fnd == c.end())
593 return 0;
594 return &fnd->second;
595}
596
3fcaeeac 597double DiffTime(const struct timespec& first, const struct timespec& second);
598double DiffTime(const struct timeval& first, const struct timeval& second);
ffb07158 599uid_t strToUID(const string &str);
600gid_t strToGID(const string &str);
a5c4e4a6
AT
601
602unsigned int pdns_stou(const std::string& str, size_t * idx = 0, int base = 10);
60a1c204 603
8fd25133
RG
604bool isSettingThreadCPUAffinitySupported();
605int mapThreadToCPUList(pthread_t tid, const std::set<int>& cpus);
5d4e1ef8
RG
606
607std::vector<ComboAddress> getResolvers(const std::string& resolvConfPath);