root/trunk/pdns/pdns/misc.cc @ 872

Revision 872, 11.1 KB (checked in by ahu, 7 years ago)

generalise number -> localX code for use in pdns_recursor

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1/*
2    PowerDNS Versatile Database Driven Nameserver
3    Copyright (C) 2002 - 2006  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
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18*/
19
20#ifndef WIN32
21#include <sys/param.h>
22#include <netdb.h>
23#include <sys/time.h>
24#include <time.h>
25#include <netinet/in.h>
26#include <unistd.h>
27#endif // WIN32
28
29#include "misc.hh"
30#include <vector>
31#include <sstream>
32#include <errno.h>
33#include <cstring>
34#include <iostream>
35#include <algorithm>
36#include <boost/optional.hpp>
37
38#include <iomanip>
39#include <string.h>
40#include <stdlib.h>
41#include <stdio.h>
42#include "ahuexception.hh"
43#include <sys/types.h>
44
45
46#include "utility.hh"
47
48string nowTime()
49{
50  time_t now=time(0);
51  string t=ctime(&now);
52  chomp(t,"\n");
53  return t;
54}
55
56uint16_t getShort(const unsigned char *p)
57{
58  return p[0] * 256 + p[1];
59}
60
61
62uint16_t getShort(const char *p)
63{
64  return getShort((const unsigned char *)p);
65}
66
67uint32_t getLong(const unsigned char* p)
68{
69  return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
70}
71
72uint32_t getLong(const char* p)
73{
74  return getLong((unsigned char *)p);
75}
76
77
78
79/** strips a domain suffix from a domain, returns true if it stripped */
80bool stripDomainSuffix(string *qname, const string &domain)
81{
82  if(!endsOn(*qname, domain))
83    return false;
84
85  if(toLower(*qname)==toLower(domain))
86    *qname="@";
87  else {
88    if((*qname)[qname->size()-domain.size()-1]!='.')
89      return false;
90
91    qname->resize(qname->size()-domain.size()-1);
92  }
93  return true;
94}
95
96/** 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 */
97bool chopOff(string &domain)
98{
99  if(domain.empty())
100    return false;
101
102  string::size_type fdot=domain.find('.');
103
104  if(fdot==string::npos) 
105    domain="";
106  else 
107    domain=domain.substr(fdot+1);
108  return true;
109}
110
111/** 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 */
112bool chopOffDotted(string &domain)
113{
114  if(domain.empty() || (domain.size()==1 && domain[0]=='.'))
115    return false;
116
117  string::size_type fdot=domain.find('.');
118
119  if(fdot==domain.size()-1) 
120    domain=".";
121  else 
122    domain=domain.substr(fdot+1);
123  return true;
124}
125
126
127bool ciEqual(const string& a, const string& b)
128{
129  if(a.size()!=b.size())
130    return false;
131
132  string::size_type pos=0, epos=a.size();
133  for(;pos < epos; ++pos)
134    if(dns_tolower(a[pos])!=dns_tolower(b[pos]))
135      return false;
136  return true;
137}
138
139/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
140bool endsOn(const string &domain, const string &suffix) 
141{
142  if( suffix.empty() || ciEqual(domain, suffix) )
143    return true;
144
145  if(domain.size()<=suffix.size())
146    return false;
147 
148  string::size_type dpos=domain.size()-suffix.size()-1, spos=0;
149
150  if(domain[dpos++]!='.')
151    return false;
152
153  for(; dpos < domain.size(); ++dpos, ++spos)
154    if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos]))
155      return false;
156
157  return true;
158}
159
160/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
161bool dottedEndsOn(const string &domain, const string &suffix) 
162{
163  if( suffix=="." || ciEqual(domain, suffix) )
164    return true;
165
166  if(domain.size()<=suffix.size())
167    return false;
168 
169  string::size_type dpos=domain.size()-suffix.size()-1, spos=0;
170
171  if(domain[dpos++]!='.')
172    return false;
173
174  for(; dpos < domain.size(); ++dpos, ++spos)
175    if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos]))
176      return false;
177
178  return true;
179}
180
181
182int sendData(const char *buffer, int replen, int outsock)
183{
184  uint16_t nlen=htons(replen);
185  Utility::iovec iov[2];
186  iov[0].iov_base=(char*)&nlen;
187  iov[0].iov_len=2;
188  iov[1].iov_base=(char*)buffer;
189  iov[1].iov_len=replen;
190  int ret=Utility::writev(outsock,iov,2);
191
192  if(ret<0) {
193    return -1;
194  }
195  if(ret!=replen+2) {
196    return -1;
197  }
198  return 0;
199}
200
201static void parseService4(const string &descr, ServiceTuple &st)
202{
203  vector<string>parts;
204  stringtok(parts,descr,":");
205  if(parts.empty())
206    throw AhuException("Unable to parse '"+descr+"' as a service");
207  st.host=parts[0];
208  if(parts.size()>1)
209    st.port=atoi(parts[1].c_str());
210}
211
212static void parseService6(const string &descr, ServiceTuple &st)
213{
214  string::size_type pos=descr.find(']');
215  if(pos == string::npos)
216    throw AhuException("Unable to parse '"+descr+"' as an IPv6 service");
217
218  st.host=descr.substr(1, pos-1);
219  if(pos + 2 < descr.length())
220    st.port=atoi(descr.c_str() + pos +2);
221}
222
223
224void parseService(const string &descr, ServiceTuple &st)
225{
226  if(descr.empty())
227    throw AhuException("Unable to parse '"+descr+"' as a service");
228
229  vector<string> parts;
230  stringtok(parts, descr, ":");
231
232  if(descr[0]=='[') {
233    parseService6(descr, st);
234  }
235  else if(descr[0]==':' || parts.size() > 2 || descr.find("::") != string::npos) {
236    st.host=descr;
237  }
238  else {
239    parseService4(descr, st);
240  }
241}
242
243int waitForData(int fd, int seconds, int useconds)
244{
245  struct timeval tv;
246  int ret;
247
248  tv.tv_sec   = seconds;
249  tv.tv_usec  = useconds;
250
251  fd_set readfds;
252  FD_ZERO( &readfds );
253  FD_SET( fd, &readfds );
254
255  ret = select( fd + 1, &readfds, NULL, NULL, &tv );
256  if ( ret == -1 )
257    errno = ETIMEDOUT;
258
259  return ret;
260}
261
262
263string humanDuration(time_t passed)
264{
265  ostringstream ret;
266  if(passed<60)
267    ret<<passed<<" seconds";
268  else if(passed<3600)
269    ret<<setprecision(2)<<passed/60.0<<" minutes";
270  else if(passed<86400)
271    ret<<setprecision(3)<<passed/3600.0<<" hours";
272  else if(passed<(86400*30.41))
273    ret<<setprecision(3)<<passed/86400.0<<" days";
274  else
275    ret<<setprecision(3)<<passed/(86400*30.41)<<" months";
276
277  return ret.str();
278}
279
280DTime::DTime()
281{
282//  set(); // saves lots of gettimeofday calls
283}
284
285DTime::DTime(const DTime &dt)
286{
287  d_set=dt.d_set;
288}
289
290time_t DTime::time()
291{
292  return d_set.tv_sec;
293}
294
295const string unquotify(const string &item)
296{
297  if(item.size()<2)
298    return item;
299
300  string::size_type bpos=0, epos=item.size();
301
302  if(item[0]=='"') 
303    bpos=1;
304
305  if(item[epos-1]=='"')
306    epos-=1;
307
308  return item.substr(bpos,epos-bpos);
309}
310
311void stripLine(string &line)
312{
313  string::size_type pos=line.find_first_of("\r\n");
314  if(pos!=string::npos) {
315    line.resize(pos);
316  }
317}
318
319string urlEncode(const string &text)
320{
321  string ret;
322  for(string::const_iterator i=text.begin();i!=text.end();++i)
323    if(*i==' ')ret.append("%20");
324    else ret.append(1,*i);
325  return ret;
326}
327
328string getHostname()
329{
330#ifdef WIN32
331# define MAXHOSTNAMELEN 1025
332#endif // WIN32
333
334  char tmp[MAXHOSTNAMELEN];
335  if(gethostname(tmp, MAXHOSTNAMELEN))
336    return "UNKNOWN";
337
338  return tmp;
339}
340
341string itoa(int i)
342{
343  ostringstream o;
344  o<<i;
345  return o.str();
346}
347
348string uitoa(unsigned int i) // MSVC 6 doesn't grok overloading (un)signed
349{
350  ostringstream o;
351  o<<i;
352  return o.str();
353}
354
355
356string stringerror()
357{
358  return strerror(errno);
359}
360
361#ifdef WIN32
362string netstringerror()
363{
364  char buf[512];
365  int err=WSAGetLastError();
366  if(FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
367                     0, buf, sizeof(buf)-1, NULL)) {
368    return string(buf);
369  }
370  else {
371    return strerror(err);
372  }
373}
374#else
375string netstringerror()
376{
377  return stringerror();
378}
379#endif
380
381void cleanSlashes(string &str)
382{
383  string::const_iterator i;
384  string out;
385  for(i=str.begin();i!=str.end();++i) {
386    if(*i=='/' && i!=str.begin() && *(i-1)=='/')
387      continue;
388    out.append(1,*i);
389  }
390  str=out;
391}
392
393
394bool IpToU32(const string &str, uint32_t *ip)
395{
396  if(str.empty()) {
397    *ip=0;
398    return true;
399  }
400 
401  struct in_addr inp;
402  if(Utility::inet_aton(str.c_str(), &inp)) {
403    *ip=inp.s_addr;
404    return true;
405  }
406  return false;
407}
408
409string U32ToIP(uint32_t val)
410{
411  char tmp[17];
412  snprintf(tmp, sizeof(tmp)-1, "%u.%u.%u.%u", 
413           (val >> 24)&0xff,
414           (val >> 16)&0xff,
415           (val >>  8)&0xff,
416           (val      )&0xff);
417  return tmp;
418}
419
420
421const string sockAddrToString(struct sockaddr_in *remote) 
422{   
423  if(remote->sin_family == AF_INET) {
424    struct sockaddr_in sip;
425    memcpy(&sip,(struct sockaddr_in*)remote,sizeof(sip));
426    return inet_ntoa(sip.sin_addr);
427  }
428  else {
429    char tmp[128];
430   
431    if(!Utility::inet_ntop(AF_INET6, ( const char * ) &((struct sockaddr_in6 *)remote)->sin6_addr, tmp, sizeof(tmp)))
432      return "IPv6 untranslateable";
433
434    return tmp;
435  }
436}
437
438string makeHexDump(const string& str)
439{
440  char tmp[5];
441  string ret;
442  ret.reserve((int)(str.size()*2.2));
443
444  for(string::size_type n=0;n<str.size();++n) {
445    sprintf(tmp,"%02x ", (unsigned char)str[n]);
446    ret+=tmp;
447  }
448  return ret;
449}
450
451
452
453// shuffle, maintaining some semblance of order
454void shuffle(vector<DNSResourceRecord>& rrs)
455{
456  vector<DNSResourceRecord>::iterator first, second;
457  for(first=rrs.begin();first!=rrs.end();++first) 
458    if(first->d_place==DNSResourceRecord::ANSWER && first->qtype.getCode() != QType::CNAME) // CNAME must come first
459      break;
460  for(second=first;second!=rrs.end();++second)
461    if(second->d_place!=DNSResourceRecord::ANSWER)
462      break;
463 
464  if(second-first>1)
465    random_shuffle(first,second);
466 
467  // now shuffle the additional records
468  for(first=second;first!=rrs.end();++first) 
469    if(first->d_place==DNSResourceRecord::ADDITIONAL && first->qtype.getCode() != QType::CNAME) // CNAME must come first
470      break;
471  for(second=first;second!=rrs.end();++second)
472    if(second->d_place!=DNSResourceRecord::ADDITIONAL)
473      break;
474 
475  if(second-first>1)
476    random_shuffle(first,second);
477
478  // we don't shuffle the rest
479}
480
481
482void normalizeTV(struct timeval& tv)
483{
484  if(tv.tv_usec > 1000000) {
485    ++tv.tv_sec;
486    tv.tv_usec-=1000000;
487  }
488  else if(tv.tv_usec < 0) {
489    --tv.tv_sec;
490    tv.tv_usec+=1000000;
491  }
492}
493
494const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs)
495{
496  struct timeval ret;
497  ret.tv_sec=lhs.tv_sec + rhs.tv_sec;
498  ret.tv_usec=lhs.tv_usec + rhs.tv_usec;
499  normalizeTV(ret);
500  return ret;
501}
502
503const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs)
504{
505  struct timeval ret;
506  ret.tv_sec=lhs.tv_sec - rhs.tv_sec;
507  ret.tv_usec=lhs.tv_usec - rhs.tv_usec;
508  normalizeTV(ret);
509  return ret;
510}
511
512pair<string, string> splitField(const string& inp, char sepa)
513{
514  pair<string, string> ret;
515  string::size_type cpos=inp.find(sepa);
516  if(cpos==string::npos)
517    ret.first=inp;
518  else {
519    ret.first=inp.substr(0, cpos);
520    ret.second=inp.substr(cpos+1);
521  }
522  return ret;
523}
524
525boost::optional<int> logFacilityToLOG(unsigned int facility)
526{
527  boost::optional<int> ret;
528
529  switch(facility) {
530  case 0:
531    return LOG_LOCAL0;
532  case 1:
533    return(LOG_LOCAL1);
534  case 2:
535    return(LOG_LOCAL2);
536  case 3:
537    return(LOG_LOCAL3);
538  case 4:
539    return(LOG_LOCAL4);
540  case 5:
541    return(LOG_LOCAL5);
542  case 6:
543    return(LOG_LOCAL6);
544  case 7:
545    return(LOG_LOCAL7);
546  default:
547    return ret;
548  }
549}
Note: See TracBrowser for help on using the browser.