]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/misc.cc
Include config.h only in .cc files
[thirdparty/pdns.git] / pdns / misc.cc
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 - 2014 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 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <sys/param.h>
27 #include <sys/socket.h>
28 #include <netdb.h>
29 #include <sys/time.h>
30 #include <time.h>
31 #include <sys/resource.h>
32 #include <netinet/in.h>
33 #include <sys/un.h>
34 #include <unistd.h>
35 #include "misc.hh"
36 #include <vector>
37 #include <sstream>
38 #include <errno.h>
39 #include <cstring>
40 #include <iostream>
41 #include <algorithm>
42 #include <boost/optional.hpp>
43 #include <poll.h>
44 #include <iomanip>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include "pdnsexception.hh"
49 #include <sys/types.h>
50 #include "utility.hh"
51 #include <boost/algorithm/string.hpp>
52 #include "logger.hh"
53 #include "iputils.hh"
54
55 bool g_singleThreaded;
56
57 int writen2(int fd, const void *buf, size_t count)
58 {
59 const char *ptr = (char*)buf;
60 const char *eptr = ptr + count;
61
62 int res;
63 while(ptr != eptr) {
64 res = ::write(fd, ptr, eptr - ptr);
65 if(res < 0) {
66 if (errno == EAGAIN)
67 throw std::runtime_error("used writen2 on non-blocking socket, got EAGAIN");
68 else
69 unixDie("failed in writen2");
70 }
71 else if (res == 0)
72 throw std::runtime_error("could not write all bytes, got eof in writen2");
73
74 ptr += res;
75 }
76
77 return count;
78 }
79
80 int readn2(int fd, void* buffer, unsigned int len)
81 {
82 unsigned int pos=0;
83 int res;
84 for(;;) {
85 res = read(fd, (char*)buffer + pos, len - pos);
86 if(res == 0)
87 throw runtime_error("EOF while writing message");
88 if(res < 0) {
89 if (errno == EAGAIN)
90 throw std::runtime_error("used writen2 on non-blocking socket, got EAGAIN");
91 else
92 unixDie("failed in writen2");
93 }
94
95 pos+=res;
96 if(pos == len)
97 break;
98 }
99 return len;
100 }
101
102
103 string nowTime()
104 {
105 time_t now=time(0);
106 string t=ctime(&now);
107 boost::trim_right(t);
108 return t;
109 }
110
111 uint16_t getShort(const unsigned char *p)
112 {
113 return p[0] * 256 + p[1];
114 }
115
116
117 uint16_t getShort(const char *p)
118 {
119 return getShort((const unsigned char *)p);
120 }
121
122 uint32_t getLong(const unsigned char* p)
123 {
124 return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
125 }
126
127 uint32_t getLong(const char* p)
128 {
129 return getLong((unsigned char *)p);
130 }
131
132
133
134 /** strips a domain suffix from a domain, returns true if it stripped */
135 bool stripDomainSuffix(string *qname, const string &domain)
136 {
137 if(!endsOn(*qname, domain))
138 return false;
139
140 if(toLower(*qname)==toLower(domain))
141 *qname="@";
142 else {
143 if((*qname)[qname->size()-domain.size()-1]!='.')
144 return false;
145
146 qname->resize(qname->size()-domain.size()-1);
147 }
148 return true;
149 }
150
151 /** Chops off the start of a domain, so goes from 'www.ds9a.nl' to 'ds9a.nl' to 'nl' to ''. Return zero on the empty string */
152 bool chopOff(string &domain)
153 {
154 if(domain.empty())
155 return false;
156
157 string::size_type fdot=domain.find('.');
158
159 if(fdot==string::npos)
160 domain="";
161 else {
162 string::size_type remain = domain.length() - (fdot + 1);
163 char tmp[remain];
164 memcpy(tmp, domain.c_str()+fdot+1, remain);
165 domain.assign(tmp, remain); // don't dare to do this w/o tmp holder :-)
166 }
167 return true;
168 }
169
170 /** Chops off the start of a domain, so goes from 'www.ds9a.nl.' to 'ds9a.nl.' to 'nl.' to '.' Return zero on the empty string */
171 bool chopOffDotted(string &domain)
172 {
173 if(domain.empty() || (domain.size()==1 && domain[0]=='.'))
174 return false;
175
176 string::size_type fdot=domain.find('.');
177 if(fdot == string::npos)
178 return false;
179
180 if(fdot==domain.size()-1)
181 domain=".";
182 else {
183 string::size_type remain = domain.length() - (fdot + 1);
184 char tmp[remain];
185 memcpy(tmp, domain.c_str()+fdot+1, remain);
186 domain.assign(tmp, remain);
187 }
188 return true;
189 }
190
191
192 bool ciEqual(const string& a, const string& b)
193 {
194 if(a.size()!=b.size())
195 return false;
196
197 string::size_type pos=0, epos=a.size();
198 for(;pos < epos; ++pos)
199 if(dns_tolower(a[pos])!=dns_tolower(b[pos]))
200 return false;
201 return true;
202 }
203
204 /** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
205 bool endsOn(const string &domain, const string &suffix)
206 {
207 if( suffix.empty() || ciEqual(domain, suffix) )
208 return true;
209
210 if(domain.size()<=suffix.size())
211 return false;
212
213 string::size_type dpos=domain.size()-suffix.size()-1, spos=0;
214
215 if(domain[dpos++]!='.')
216 return false;
217
218 for(; dpos < domain.size(); ++dpos, ++spos)
219 if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos]))
220 return false;
221
222 return true;
223 }
224
225 /** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
226 bool dottedEndsOn(const string &domain, const string &suffix)
227 {
228 if( suffix=="." || ciEqual(domain, suffix) )
229 return true;
230
231 if(domain.size()<=suffix.size())
232 return false;
233
234 string::size_type dpos=domain.size()-suffix.size()-1, spos=0;
235
236 if(domain[dpos++]!='.')
237 return false;
238
239 for(; dpos < domain.size(); ++dpos, ++spos)
240 if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos]))
241 return false;
242
243 return true;
244 }
245
246 static void parseService4(const string &descr, ServiceTuple &st)
247 {
248 vector<string>parts;
249 stringtok(parts,descr,":");
250 if(parts.empty())
251 throw PDNSException("Unable to parse '"+descr+"' as a service");
252 st.host=parts[0];
253 if(parts.size()>1)
254 st.port=atoi(parts[1].c_str());
255 }
256
257 static void parseService6(const string &descr, ServiceTuple &st)
258 {
259 string::size_type pos=descr.find(']');
260 if(pos == string::npos)
261 throw PDNSException("Unable to parse '"+descr+"' as an IPv6 service");
262
263 st.host=descr.substr(1, pos-1);
264 if(pos + 2 < descr.length())
265 st.port=atoi(descr.c_str() + pos +2);
266 }
267
268
269 void parseService(const string &descr, ServiceTuple &st)
270 {
271 if(descr.empty())
272 throw PDNSException("Unable to parse '"+descr+"' as a service");
273
274 vector<string> parts;
275 stringtok(parts, descr, ":");
276
277 if(descr[0]=='[') {
278 parseService6(descr, st);
279 }
280 else if(descr[0]==':' || parts.size() > 2 || descr.find("::") != string::npos) {
281 st.host=descr;
282 }
283 else {
284 parseService4(descr, st);
285 }
286 }
287
288 // returns -1 in case if error, 0 if no data is available, 1 if there is. In the first two cases, errno is set
289 int waitForData(int fd, int seconds, int useconds)
290 {
291 return waitForRWData(fd, true, seconds, useconds);
292 }
293
294 int waitForRWData(int fd, bool waitForRead, int seconds, int useconds)
295 {
296 int ret;
297
298 struct pollfd pfd;
299 memset(&pfd, 0, sizeof(pfd));
300 pfd.fd = fd;
301
302 if(waitForRead)
303 pfd.events=POLLIN;
304 else
305 pfd.events=POLLOUT;
306
307 ret = poll(&pfd, 1, seconds * 1000 + useconds/1000);
308 if ( ret == -1 )
309 errno = ETIMEDOUT; // ???
310
311 return ret;
312 }
313
314 // returns -1 in case of error, 0 if no data is available, 1 if there is. In the first two cases, errno is set
315 int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int*fd)
316 {
317 int ret;
318
319 struct pollfd pfds[2];
320 memset(&pfds[0], 0, 2*sizeof(struct pollfd));
321 pfds[0].fd = fd1;
322 pfds[1].fd = fd2;
323
324 pfds[0].events= pfds[1].events = POLLIN;
325
326 int nsocks = 1 + (fd2 >= 0); // fd2 can optionally be -1
327
328 if(seconds >= 0)
329 ret = poll(pfds, nsocks, seconds * 1000 + useconds/1000);
330 else
331 ret = poll(pfds, nsocks, -1);
332 if(!ret || ret < 0)
333 return ret;
334
335 if((pfds[0].revents & POLLIN) && !(pfds[1].revents & POLLIN))
336 *fd = pfds[0].fd;
337 else if((pfds[1].revents & POLLIN) && !(pfds[0].revents & POLLIN))
338 *fd = pfds[1].fd;
339 else if(ret == 2) {
340 *fd = pfds[random()%2].fd;
341 }
342 else
343 *fd = -1; // should never happen
344
345 return 1;
346 }
347
348
349 string humanDuration(time_t passed)
350 {
351 ostringstream ret;
352 if(passed<60)
353 ret<<passed<<" seconds";
354 else if(passed<3600)
355 ret<<std::setprecision(2)<<passed/60.0<<" minutes";
356 else if(passed<86400)
357 ret<<std::setprecision(3)<<passed/3600.0<<" hours";
358 else if(passed<(86400*30.41))
359 ret<<std::setprecision(3)<<passed/86400.0<<" days";
360 else
361 ret<<std::setprecision(3)<<passed/(86400*30.41)<<" months";
362
363 return ret.str();
364 }
365
366 DTime::DTime()
367 {
368 // set(); // saves lots of gettimeofday calls
369 }
370
371 DTime::DTime(const DTime &dt)
372 {
373 d_set=dt.d_set;
374 }
375
376 time_t DTime::time()
377 {
378 return d_set.tv_sec;
379 }
380
381 const string unquotify(const string &item)
382 {
383 if(item.size()<2)
384 return item;
385
386 string::size_type bpos=0, epos=item.size();
387
388 if(item[0]=='"')
389 bpos=1;
390
391 if(item[epos-1]=='"')
392 epos-=1;
393
394 return item.substr(bpos,epos-bpos);
395 }
396
397 void stripLine(string &line)
398 {
399 string::size_type pos=line.find_first_of("\r\n");
400 if(pos!=string::npos) {
401 line.resize(pos);
402 }
403 }
404
405 string urlEncode(const string &text)
406 {
407 string ret;
408 for(string::const_iterator i=text.begin();i!=text.end();++i)
409 if(*i==' ')ret.append("%20");
410 else ret.append(1,*i);
411 return ret;
412 }
413
414 string getHostname()
415 {
416 #ifndef MAXHOSTNAMELEN
417 #define MAXHOSTNAMELEN 255
418 #endif
419
420 char tmp[MAXHOSTNAMELEN];
421 if(gethostname(tmp, MAXHOSTNAMELEN))
422 return "UNKNOWN";
423
424 return tmp;
425 }
426
427 string itoa(int i)
428 {
429 ostringstream o;
430 o<<i;
431 return o.str();
432 }
433
434 string uitoa(unsigned int i) // MSVC 6 doesn't grok overloading (un)signed
435 {
436 ostringstream o;
437 o<<i;
438 return o.str();
439 }
440
441 string bitFlip(const string &str)
442 {
443 string::size_type pos=0, epos=str.size();
444 string ret;
445 ret.reserve(epos);
446 for(;pos < epos; ++pos)
447 ret.append(1, ~str[pos]);
448 return ret;
449 }
450
451 string stringerror()
452 {
453 return strerror(errno);
454 }
455
456 string netstringerror()
457 {
458 return stringerror();
459 }
460
461 void cleanSlashes(string &str)
462 {
463 string::const_iterator i;
464 string out;
465 for(i=str.begin();i!=str.end();++i) {
466 if(*i=='/' && i!=str.begin() && *(i-1)=='/')
467 continue;
468 out.append(1,*i);
469 }
470 str=out;
471 }
472
473
474 bool IpToU32(const string &str, uint32_t *ip)
475 {
476 if(str.empty()) {
477 *ip=0;
478 return true;
479 }
480
481 struct in_addr inp;
482 if(Utility::inet_aton(str.c_str(), &inp)) {
483 *ip=inp.s_addr;
484 return true;
485 }
486 return false;
487 }
488
489 string U32ToIP(uint32_t val)
490 {
491 char tmp[17];
492 snprintf(tmp, sizeof(tmp)-1, "%u.%u.%u.%u",
493 (val >> 24)&0xff,
494 (val >> 16)&0xff,
495 (val >> 8)&0xff,
496 (val )&0xff);
497 return tmp;
498 }
499
500
501 string makeHexDump(const string& str)
502 {
503 char tmp[5];
504 string ret;
505 ret.reserve((int)(str.size()*2.2));
506
507 for(string::size_type n=0;n<str.size();++n) {
508 sprintf(tmp,"%02x ", (unsigned char)str[n]);
509 ret+=tmp;
510 }
511 return ret;
512 }
513
514 // shuffle, maintaining some semblance of order
515 void shuffle(vector<DNSResourceRecord>& rrs)
516 {
517 vector<DNSResourceRecord>::iterator first, second;
518 for(first=rrs.begin();first!=rrs.end();++first)
519 if(first->d_place==DNSResourceRecord::ANSWER && first->qtype.getCode() != QType::CNAME) // CNAME must come first
520 break;
521 for(second=first;second!=rrs.end();++second)
522 if(second->d_place!=DNSResourceRecord::ANSWER)
523 break;
524
525 if(second-first>1)
526 random_shuffle(first,second);
527
528 // now shuffle the additional records
529 for(first=second;first!=rrs.end();++first)
530 if(first->d_place==DNSResourceRecord::ADDITIONAL && first->qtype.getCode() != QType::CNAME) // CNAME must come first
531 break;
532 for(second=first;second!=rrs.end();++second)
533 if(second->d_place!=DNSResourceRecord::ADDITIONAL)
534 break;
535
536 if(second-first>1)
537 random_shuffle(first,second);
538
539 // we don't shuffle the rest
540 }
541
542 static bool comparePlace(DNSResourceRecord a, DNSResourceRecord b)
543 {
544 return (a.d_place < b.d_place);
545 }
546
547 // make sure rrs is sorted in d_place order to avoid surprises later
548 // then shuffle the parts that desire shuffling
549 void orderAndShuffle(vector<DNSResourceRecord>& rrs)
550 {
551 std::stable_sort(rrs.begin(), rrs.end(), comparePlace);
552 shuffle(rrs);
553 }
554
555 void normalizeTV(struct timeval& tv)
556 {
557 if(tv.tv_usec > 1000000) {
558 ++tv.tv_sec;
559 tv.tv_usec-=1000000;
560 }
561 else if(tv.tv_usec < 0) {
562 --tv.tv_sec;
563 tv.tv_usec+=1000000;
564 }
565 }
566
567 const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs)
568 {
569 struct timeval ret;
570 ret.tv_sec=lhs.tv_sec + rhs.tv_sec;
571 ret.tv_usec=lhs.tv_usec + rhs.tv_usec;
572 normalizeTV(ret);
573 return ret;
574 }
575
576 const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs)
577 {
578 struct timeval ret;
579 ret.tv_sec=lhs.tv_sec - rhs.tv_sec;
580 ret.tv_usec=lhs.tv_usec - rhs.tv_usec;
581 normalizeTV(ret);
582 return ret;
583 }
584
585 pair<string, string> splitField(const string& inp, char sepa)
586 {
587 pair<string, string> ret;
588 string::size_type cpos=inp.find(sepa);
589 if(cpos==string::npos)
590 ret.first=inp;
591 else {
592 ret.first=inp.substr(0, cpos);
593 ret.second=inp.substr(cpos+1);
594 }
595 return ret;
596 }
597
598 int logFacilityToLOG(unsigned int facility)
599 {
600 switch(facility) {
601 case 0:
602 return LOG_LOCAL0;
603 case 1:
604 return(LOG_LOCAL1);
605 case 2:
606 return(LOG_LOCAL2);
607 case 3:
608 return(LOG_LOCAL3);
609 case 4:
610 return(LOG_LOCAL4);
611 case 5:
612 return(LOG_LOCAL5);
613 case 6:
614 return(LOG_LOCAL6);
615 case 7:
616 return(LOG_LOCAL7);
617 default:
618 return -1;
619 }
620 }
621
622 string stripDot(const string& dom)
623 {
624 if(dom.empty())
625 return dom;
626
627 if(dom[dom.size()-1]!='.')
628 return dom;
629
630 return dom.substr(0,dom.size()-1);
631 }
632
633
634 string labelReverse(const std::string& qname)
635 {
636 if(qname.empty())
637 return qname;
638
639 bool dotName = qname.find('.') != string::npos;
640
641 vector<string> labels;
642 stringtok(labels, qname, ". ");
643 if(labels.size()==1)
644 return qname;
645
646 string ret; // vv const_reverse_iter http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729
647 for(vector<string>::reverse_iterator iter = labels.rbegin(); iter != labels.rend(); ++iter) {
648 if(iter != labels.rbegin())
649 ret.append(1, dotName ? ' ' : '.');
650 ret+=*iter;
651 }
652 return ret;
653 }
654
655 // do NOT feed trailing dots!
656 // www.powerdns.com, powerdns.com -> www
657 string makeRelative(const std::string& fqdn, const std::string& zone)
658 {
659 if(zone.empty())
660 return fqdn;
661 if(fqdn != zone)
662 return fqdn.substr(0, fqdn.size() - zone.length() - 1); // strip domain name
663 return "";
664 }
665
666 string dotConcat(const std::string& a, const std::string &b)
667 {
668 if(a.empty() || b.empty())
669 return a+b;
670 else
671 return a+"."+b;
672 }
673
674 int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret)
675 {
676 if(addr.empty())
677 return -1;
678 string ourAddr(addr);
679 int port = -1;
680 if(addr[0]=='[') { // [::]:53 style address
681 string::size_type pos = addr.find(']');
682 if(pos == string::npos || pos + 2 > addr.size() || addr[pos+1]!=':')
683 return -1;
684 ourAddr.assign(addr.c_str() + 1, pos-1);
685 port = atoi(addr.c_str()+pos+2);
686 }
687 ret->sin6_scope_id=0;
688 ret->sin6_family=AF_INET6;
689
690 if(inet_pton(AF_INET6, ourAddr.c_str(), (void*)&ret->sin6_addr) != 1) {
691 struct addrinfo* res;
692 struct addrinfo hints;
693 memset(&hints, 0, sizeof(hints));
694
695 hints.ai_family = AF_INET6;
696 hints.ai_flags = AI_NUMERICHOST;
697
698 int error;
699 if((error=getaddrinfo(ourAddr.c_str(), 0, &hints, &res))) { // this is correct
700 return -1;
701 }
702
703 memcpy(ret, res->ai_addr, res->ai_addrlen);
704 freeaddrinfo(res);
705 }
706
707 if(port >= 0)
708 ret->sin6_port = htons(port);
709
710 return 0;
711 }
712
713 int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret)
714 {
715 if(str.empty()) {
716 return -1;
717 }
718 struct in_addr inp;
719
720 string::size_type pos = str.find(':');
721 if(pos == string::npos) { // no port specified, not touching the port
722 if(Utility::inet_aton(str.c_str(), &inp)) {
723 ret->sin_addr.s_addr=inp.s_addr;
724 return 0;
725 }
726 return -1;
727 }
728 if(!*(str.c_str() + pos + 1)) // trailing :
729 return -1;
730
731 char *eptr = (char*)str.c_str() + str.size();
732 int port = strtol(str.c_str() + pos + 1, &eptr, 10);
733 if(*eptr)
734 return -1;
735
736 ret->sin_port = htons(port);
737 if(Utility::inet_aton(str.substr(0, pos).c_str(), &inp)) {
738 ret->sin_addr.s_addr=inp.s_addr;
739 return 0;
740 }
741 return -1;
742 }
743
744 int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret)
745 {
746 if (path.empty())
747 return -1;
748
749 memset(ret, 0, sizeof(struct sockaddr_un));
750 ret->sun_family = AF_UNIX;
751 if (path.length() >= sizeof(ret->sun_path))
752 return -1;
753
754 path.copy(ret->sun_path, sizeof(ret->sun_path), 0);
755 return 0;
756 }
757
758 //! read a line of text from a FILE* to a std::string, returns false on 'no data'
759 bool stringfgets(FILE* fp, std::string& line)
760 {
761 char buffer[1024];
762 line.clear();
763
764 do {
765 if(!fgets(buffer, sizeof(buffer), fp))
766 return !line.empty();
767
768 line.append(buffer);
769 } while(!strchr(buffer, '\n'));
770 return true;
771 }
772
773 bool readFileIfThere(const char* fname, std::string* line)
774 {
775 line->clear();
776 FILE* fp = fopen(fname, "r");
777 if(!fp)
778 return false;
779 stringfgets(fp, *line);
780 fclose(fp);
781 return true;
782 }
783
784 Regex::Regex(const string &expr)
785 {
786 if(regcomp(&d_preg, expr.c_str(), REG_ICASE|REG_NOSUB|REG_EXTENDED))
787 throw PDNSException("Regular expression did not compile");
788 }
789
790 void addCMsgSrcAddr(struct msghdr* msgh, void* cmsgbuf, const ComboAddress* source)
791 {
792 struct cmsghdr *cmsg = NULL;
793
794 if(source->sin4.sin_family == AF_INET6) {
795 struct in6_pktinfo *pkt;
796
797 msgh->msg_control = cmsgbuf;
798 msgh->msg_controllen = CMSG_SPACE(sizeof(*pkt));
799
800 cmsg = CMSG_FIRSTHDR(msgh);
801 cmsg->cmsg_level = IPPROTO_IPV6;
802 cmsg->cmsg_type = IPV6_PKTINFO;
803 cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
804
805 pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg);
806 memset(pkt, 0, sizeof(*pkt));
807 pkt->ipi6_addr = source->sin6.sin6_addr;
808 msgh->msg_controllen = cmsg->cmsg_len; // makes valgrind happy and is slightly better style
809 }
810 else {
811 #ifdef IP_PKTINFO
812 struct in_pktinfo *pkt;
813
814 msgh->msg_control = cmsgbuf;
815 msgh->msg_controllen = CMSG_SPACE(sizeof(*pkt));
816
817 cmsg = CMSG_FIRSTHDR(msgh);
818 cmsg->cmsg_level = IPPROTO_IP;
819 cmsg->cmsg_type = IP_PKTINFO;
820 cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
821
822 pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
823 memset(pkt, 0, sizeof(*pkt));
824 pkt->ipi_spec_dst = source->sin4.sin_addr;
825 msgh->msg_controllen = cmsg->cmsg_len;
826 #endif
827 #ifdef IP_SENDSRCADDR
828 struct in_addr *in;
829
830 msgh->msg_control = cmsgbuf;
831 msgh->msg_controllen = CMSG_SPACE(sizeof(*in));
832
833 cmsg = CMSG_FIRSTHDR(msgh);
834 cmsg->cmsg_level = IPPROTO_IP;
835 cmsg->cmsg_type = IP_SENDSRCADDR;
836 cmsg->cmsg_len = CMSG_LEN(sizeof(*in));
837
838 in = (struct in_addr *) CMSG_DATA(cmsg);
839 *in = source->sin4.sin_addr;
840 msgh->msg_controllen = cmsg->cmsg_len;
841 #endif
842 }
843 }
844
845 unsigned int getFilenumLimit(bool hardOrSoft)
846 {
847 struct rlimit rlim;
848 if(getrlimit(RLIMIT_NOFILE, &rlim) < 0)
849 unixDie("Requesting number of available file descriptors");
850 return hardOrSoft ? rlim.rlim_max : rlim.rlim_cur;
851 }
852
853 void setFilenumLimit(unsigned int lim)
854 {
855 struct rlimit rlim;
856
857 if(getrlimit(RLIMIT_NOFILE, &rlim) < 0)
858 unixDie("Requesting number of available file descriptors");
859 rlim.rlim_cur=lim;
860 if(setrlimit(RLIMIT_NOFILE, &rlim) < 0)
861 unixDie("Setting number of available file descriptors");
862 }
863
864 #define burtlemix(a,b,c) \
865 { \
866 a -= b; a -= c; a ^= (c>>13); \
867 b -= c; b -= a; b ^= (a<<8); \
868 c -= a; c -= b; c ^= (b>>13); \
869 a -= b; a -= c; a ^= (c>>12); \
870 b -= c; b -= a; b ^= (a<<16); \
871 c -= a; c -= b; c ^= (b>>5); \
872 a -= b; a -= c; a ^= (c>>3); \
873 b -= c; b -= a; b ^= (a<<10); \
874 c -= a; c -= b; c ^= (b>>15); \
875 }
876
877 uint32_t burtle(const unsigned char* k, uint32_t length, uint32_t initval)
878 {
879 uint32_t a,b,c,len;
880
881 /* Set up the internal state */
882 len = length;
883 a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
884 c = initval; /* the previous hash value */
885
886 /*---------------------------------------- handle most of the key */
887 while (len >= 12) {
888 a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24));
889 b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24));
890 c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24));
891 burtlemix(a,b,c);
892 k += 12; len -= 12;
893 }
894
895 /*------------------------------------- handle the last 11 bytes */
896 c += length;
897 switch(len) { /* all the case statements fall through */
898 case 11: c+=((uint32_t)k[10]<<24);
899 case 10: c+=((uint32_t)k[9]<<16);
900 case 9 : c+=((uint32_t)k[8]<<8);
901 /* the first byte of c is reserved for the length */
902 case 8 : b+=((uint32_t)k[7]<<24);
903 case 7 : b+=((uint32_t)k[6]<<16);
904 case 6 : b+=((uint32_t)k[5]<<8);
905 case 5 : b+=k[4];
906 case 4 : a+=((uint32_t)k[3]<<24);
907 case 3 : a+=((uint32_t)k[2]<<16);
908 case 2 : a+=((uint32_t)k[1]<<8);
909 case 1 : a+=k[0];
910 /* case 0: nothing left to add */
911 }
912 burtlemix(a,b,c);
913 /*-------------------------------------------- report the result */
914 return c;
915 }
916
917 void setSocketTimestamps(int fd)
918 {
919 #ifdef SO_TIMESTAMP
920 int on=1;
921 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, (char*)&on, sizeof(on)) < 0 )
922 L<<Logger::Error<<"Unable to enable timestamp reporting for socket"<<endl;
923 #endif
924 }
925
926 uint32_t pdns_strtoui(const char *nptr, char **endptr, int base)
927 {
928 #if ULONG_MAX == 4294967295
929 return strtoul(nptr, endptr, base);
930 #else
931 unsigned long val = strtoul(nptr, endptr, base);
932 if (val > UINT_MAX) {
933 errno = ERANGE;
934 return UINT_MAX;
935 }
936
937 return val;
938 #endif
939 }