root/trunk/pdns/pdns/tcpreceiver.cc @ 1871

Revision 1871, 20.9 KB (checked in by ahu, 2 years ago)

restore NSEC generation & signatures for AXFR.

  • 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-2011  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    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17*/
18#include "packetcache.hh"
19#include "utility.hh"
20#include "dnssecinfra.hh"
21#include "dnsseckeeper.hh"
22#include <cstdio>
23#include <cstring>
24#include <cstdlib>
25#include <sys/types.h>
26#include <iostream>
27#include <string>
28#include "tcpreceiver.hh"
29#include "sstuff.hh"
30#include <boost/foreach.hpp>
31#include <errno.h>
32#include <signal.h>
33
34#include "ueberbackend.hh"
35#include "dnspacket.hh"
36#include "nameserver.hh"
37#include "distributor.hh"
38#include "lock.hh"
39#include "logger.hh"
40#include "arguments.hh"
41
42#include "packethandler.hh"
43#include "statbag.hh"
44#include "resolver.hh"
45#include "communicator.hh"
46#include "namespaces.hh"
47
48extern PacketCache PC;
49extern StatBag S;
50
51/**
52\file tcpreceiver.cc
53\brief This file implements the tcpreceiver that receives and answers questions over TCP/IP
54*/
55
56pthread_mutex_t TCPNameserver::s_plock = PTHREAD_MUTEX_INITIALIZER;
57Semaphore *TCPNameserver::d_connectionroom_sem;
58PacketHandler *TCPNameserver::s_P; 
59int TCPNameserver::s_timeout;
60NetmaskGroup TCPNameserver::d_ng;
61
62void TCPNameserver::go()
63{
64  L<<Logger::Error<<"Creating backend connection for TCP"<<endl;
65  s_P=0;
66  try {
67    s_P=new PacketHandler;
68  }
69  catch(AhuException &ae) {
70    L<<Logger::Error<<Logger::NTLog<<"TCP server is unable to launch backends - will try again when questions come in"<<endl;
71    L<<Logger::Error<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae.reason<<endl;
72  }
73  pthread_create(&d_tid, 0, launcher, static_cast<void *>(this));
74}
75
76void *TCPNameserver::launcher(void *data)
77{
78  static_cast<TCPNameserver *>(data)->thread();
79  return 0;
80}
81
82// throws AhuException if things didn't go according to plan, returns 0 if really 0 bytes were read
83int readnWithTimeout(int fd, void* buffer, unsigned int n, bool throwOnEOF=true)
84{
85  unsigned int bytes=n;
86  char *ptr = (char*)buffer;
87  int ret;
88  while(bytes) {
89    ret=read(fd, ptr, bytes);
90    if(ret < 0) {
91      if(errno==EAGAIN) {
92        ret=waitForData(fd, 5);
93        if(ret < 0)
94          throw NetworkError("Waiting for data read");
95        if(!ret)
96          throw NetworkError("Timeout reading data");
97        continue;
98      }
99      else
100        throw NetworkError("Reading data: "+stringerror());
101    }
102    if(!ret) {
103      if(!throwOnEOF && n == bytes)
104        return 0;
105      else
106        throw NetworkError("Did not fulfill read from TCP due to EOF");
107    }
108   
109    ptr += ret;
110    bytes -= ret;
111  }
112  return n;
113}
114
115// ditto
116void writenWithTimeout(int fd, const void *buffer, unsigned int n)
117{
118  unsigned int bytes=n;
119  const char *ptr = (char*)buffer;
120  int ret;
121  while(bytes) {
122    ret=write(fd, ptr, bytes);
123    if(ret < 0) {
124      if(errno==EAGAIN) {
125        ret=waitForRWData(fd, false, 5, 0);
126        if(ret < 0)
127          throw NetworkError("Waiting for data write");
128        if(!ret)
129          throw NetworkError("Timeout writing data");
130        continue;
131      }
132      else
133        throw NetworkError("Writing data: "+stringerror());
134    }
135    if(!ret) {
136      throw NetworkError("Did not fulfill TCP write due to EOF");
137    }
138   
139    ptr += ret;
140    bytes -= ret;
141  }
142}
143
144void connectWithTimeout(int fd, struct sockaddr* remote, size_t socklen)
145{
146  int err;
147  Utility::socklen_t len=sizeof(err);
148
149#ifndef WIN32
150  if((err=connect(fd, remote, socklen))<0 && errno!=EINPROGRESS) 
151#else
152  if((err=connect(clisock, remote, socklen))<0 && WSAGetLastError() != WSAEWOULDBLOCK ) 
153#endif // WIN32
154    throw NetworkError("connect: "+stringerror());
155
156  if(!err)
157    goto done;
158 
159  err=waitForRWData(fd, false, 5, 0);
160  if(err == 0)
161    throw NetworkError("Timeout connecting to remote");
162  if(err < 0)
163    throw NetworkError("Error connecting to remote");
164
165  if(getsockopt(fd, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
166    throw NetworkError("Error connecting to remote: "+stringerror()); // Solaris
167
168  if(err)
169    throw NetworkError("Error connecting to remote: "+string(strerror(err)));
170
171 done:
172  ;
173}
174
175void TCPNameserver::sendPacket(shared_ptr<DNSPacket> p, int outsock)
176{
177  DNSSECKeeper dk;
178  const char *buf=p->getData(&dk);
179  uint16_t len=htons(p->len);
180  writenWithTimeout(outsock, &len, 2);
181  writenWithTimeout(outsock, buf, p->len);
182}
183
184
185void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote)
186try
187{
188  readnWithTimeout(fd, mesg, pktlen);
189}
190catch(NetworkError& ae) {
191  throw NetworkError("Error reading DNS data from TCP client "+remote.toString()+": "+ae.what());
192}
193
194static void proxyQuestion(shared_ptr<DNSPacket> packet)
195{
196  int sock=socket(AF_INET, SOCK_STREAM, 0);
197  if(sock < 0)
198    throw NetworkError("Error making TCP connection socket to recursor: "+stringerror());
199
200  Utility::setNonBlocking(sock);
201  ServiceTuple st;
202  st.port=53;
203  parseService(::arg()["recursor"],st);
204
205  try {
206    ComboAddress recursor(st.host, st.port);
207    connectWithTimeout(sock, (struct sockaddr*)&recursor, recursor.getSocklen());
208    const string &buffer=packet->getString();
209   
210    uint16_t len=htons(buffer.length()), slen;
211   
212    writenWithTimeout(sock, &len, 2);
213    writenWithTimeout(sock, buffer.c_str(), buffer.length());
214   
215    int ret;
216   
217    ret=readnWithTimeout(sock, &len, 2);
218    len=ntohs(len);
219
220    char answer[len];
221    ret=readnWithTimeout(sock, answer, len);
222
223    slen=htons(len);
224    writenWithTimeout(packet->getSocket(), &slen, 2);
225   
226    writenWithTimeout(packet->getSocket(), answer, len);
227  }
228  catch(NetworkError& ae) {
229    close(sock);
230    throw NetworkError("While proxying a question to recursor "+st.host+": " +ae.what());
231  }
232  close(sock);
233  return;
234}
235
236void *TCPNameserver::doConnection(void *data)
237{
238  shared_ptr<DNSPacket> packet;
239  // Fix gcc-4.0 error (on AMD64)
240  int fd=(int)(long)data; // gotta love C (generates a harmless warning on opteron)
241  pthread_detach(pthread_self());
242  Utility::setNonBlocking(fd);
243  try {
244    char mesg[512];
245   
246    DLOG(L<<"TCP Connection accepted on fd "<<fd<<endl);
247    bool logDNSDetails= ::arg().mustDo("log-dns-details");
248    for(;;) {
249      ComboAddress remote;
250      socklen_t remotelen=sizeof(remote);
251      if(getpeername(fd, (struct sockaddr *)&remote, &remotelen) < 0) {
252        L<<Logger::Error<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl;
253        break;
254      }
255
256      uint16_t pktlen;
257      if(!readnWithTimeout(fd, &pktlen, 2, false))
258        break;
259      else
260        pktlen=ntohs(pktlen);
261
262      if(pktlen>511) {
263        L<<Logger::Error<<"Received an overly large question from "<<remote.toString()<<", dropping"<<endl;
264        break;
265      }
266     
267      getQuestion(fd,mesg,pktlen,remote);
268      S.inc("tcp-queries");     
269
270      packet=shared_ptr<DNSPacket>(new DNSPacket);
271      packet->setRemote(&remote);
272      packet->d_tcp=true;
273      packet->setSocket(fd);
274      if(packet->parse(mesg, pktlen)<0)
275        break;
276     
277      if(packet->qtype.getCode()==QType::AXFR || packet->qtype.getCode()==QType::IXFR ) {
278        if(doAXFR(packet->qdomain, packet, fd)) 
279          S.inc("tcp-answers"); 
280        continue;
281      }
282
283      shared_ptr<DNSPacket> reply; 
284      shared_ptr<DNSPacket> cached= shared_ptr<DNSPacket>(new DNSPacket);
285      if(logDNSDetails) 
286        L << Logger::Notice<<"Remote "<< packet->remote.toString() <<" wants '" << packet->qdomain<<"|"<<packet->qtype.getName() << 
287        "', do = " <<packet->d_dnssecOk <<", bufsize = "<< packet->getMaxReplyLen()<<": ";
288
289
290      if(!packet->d.rd && packet->couldBeCached() && PC.get(packet.get(), cached.get())) { // short circuit - does the PacketCache recognize this question?
291        if(logDNSDetails)
292          L<<"packetcache HIT"<<endl;
293        cached->setRemote(&packet->remote);
294        cached->d.id=packet->d.id;
295        cached->d.rd=packet->d.rd; // copy in recursion desired bit
296        cached->commitD(); // commit d to the packet                        inlined
297
298        sendPacket(cached, fd);
299        S.inc("tcp-answers");
300        continue;
301      }
302      if(logDNSDetails)
303          L<<"packetcache MISS"<<endl; 
304      {
305        Lock l(&s_plock);
306        if(!s_P) {
307          L<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
308          s_P=new PacketHandler;
309        }
310        bool shouldRecurse;
311
312        reply=shared_ptr<DNSPacket>(s_P->questionOrRecurse(packet.get(), &shouldRecurse)); // we really need to ask the backend :-)
313
314        if(shouldRecurse) {
315          proxyQuestion(packet);
316          continue;
317        }
318      }
319
320      if(!reply)  // unable to write an answer?
321        break;
322       
323      S.inc("tcp-answers");
324      sendPacket(reply, fd);
325    }
326  }
327  catch(DBException &e) {
328    Lock l(&s_plock);
329    delete s_P;
330    s_P = 0;
331
332    L<<Logger::Error<<"TCP Connection Thread unable to answer a question because of a backend error, cycling"<<endl;
333  }
334  catch(AhuException &ae) {
335    Lock l(&s_plock);
336    delete s_P;
337    s_P = 0; // on next call, backend will be recycled
338    L<<Logger::Error<<"TCP nameserver had error, cycling backend: "<<ae.reason<<endl;
339  }
340  catch(NetworkError &e) {
341    L<<Logger::Info<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
342  }
343
344  catch(std::exception &e) {
345    L<<Logger::Error<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
346  }
347  catch( ... )
348  {
349    L << Logger::Error << "TCP Connection Thread caught unknown exception." << endl;
350  }
351  d_connectionroom_sem->post();
352  Utility::closesocket(fd);
353
354  return 0;
355}
356
357bool TCPNameserver::canDoAXFR(shared_ptr<DNSPacket> q)
358{
359  if(::arg().mustDo("disable-axfr"))
360    return false;
361
362  if(!::arg().mustDo("per-zone-axfr-acls") && (::arg()["allow-axfr-ips"].empty() || d_ng.match( (ComboAddress *) &q->remote )))
363    return true;
364
365  if(::arg().mustDo("per-zone-axfr-acls")) {
366    SOAData sd;
367    sd.db=(DNSBackend *)-1;
368    if(s_P->getBackend()->getSOA(q->qdomain,sd)) {
369      DNSBackend *B=sd.db;
370      if (B->checkACL(string("allow-axfr"), q->qdomain, q->getRemote())) {
371        return true;
372      }
373    } 
374  }
375
376  extern CommunicatorClass Communicator;
377
378  if(Communicator.justNotified(q->qdomain, q->getRemote())) { // we just notified this ip
379    L<<Logger::Warning<<"Approved AXFR of '"<<q->qdomain<<"' from recently notified slave "<<q->getRemote()<<endl;
380    return true;
381  }
382
383  return false;
384}
385
386namespace {
387struct NSECEntry
388{
389  set<uint16_t> d_set;
390  unsigned int d_ttl;
391};
392}
393/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
394int TCPNameserver::doAXFR(const string &target, shared_ptr<DNSPacket> q, int outsock)
395{
396  shared_ptr<DNSPacket> outpacket;
397  DNSSECKeeper dk;
398  bool noAXFRBecauseOfNSEC3=false;
399  if(dk.getNSEC3PARAM(target)) {
400    L<<Logger::Error<<"Not doing AXFR of an NSEC3 zone.."<<endl;
401    noAXFRBecauseOfNSEC3=true;
402  }
403
404  if(!canDoAXFR(q) || noAXFRBecauseOfNSEC3) {
405    L<<Logger::Error<<"AXFR of domain '"<<target<<"' denied to "<<q->getRemote()<<endl;
406
407    outpacket=shared_ptr<DNSPacket>(q->replyPacket());
408    outpacket->setRcode(RCode::Refused); 
409    // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
410    sendPacket(outpacket,outsock);
411    return 0;
412  }
413 
414 
415 
416  L<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
417  outpacket=shared_ptr<DNSPacket>(q->replyPacket());
418
419  DNSResourceRecord soa; 
420  DNSResourceRecord rr;
421
422  SOAData sd;
423  sd.db=(DNSBackend *)-1; // force uncached answer
424  {
425    Lock l(&s_plock);
426   
427    // find domain_id via SOA and list complete domain. No SOA, no AXFR
428   
429    DLOG(L<<"Looking for SOA"<<endl);
430    if(!s_P) {
431      L<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
432      s_P=new PacketHandler;
433    }
434
435    if(!s_P->getBackend()->getSOA(target, sd)) {
436      L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative"<<endl;
437      outpacket->setRcode(9); // 'NOTAUTH'
438      sendPacket(outpacket,outsock);
439      return 0;
440    }
441
442  }
443  PacketHandler P; // now open up a database connection, we'll need it
444
445  sd.db=(DNSBackend *)-1; // force uncached answer
446  if(!P.getBackend()->getSOA(target, sd)) {
447      L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
448    outpacket->setRcode(9); // 'NOTAUTH'
449    sendPacket(outpacket,outsock);
450    return 0;
451  }
452
453  soa.qname=target;
454  soa.qtype=QType::SOA;
455  soa.content=serializeSOAData(sd);
456  soa.ttl=sd.ttl;
457  soa.domain_id=sd.domain_id;
458  soa.auth = true;
459  soa.d_place=DNSResourceRecord::ANSWER;
460   
461  if(!sd.db || sd.db==(DNSBackend *)-1) {
462    L<<Logger::Error<<"Error determining backend for domain '"<<target<<"' trying to serve an AXFR"<<endl;
463    outpacket->setRcode(RCode::ServFail);
464    sendPacket(outpacket,outsock);
465    return 0;
466  }
467 
468  DLOG(L<<"Issuing list command - opening dedicated database connection"<<endl);
469
470  DNSBackend *B=sd.db; // get the RIGHT backend
471
472  // now list zone
473  if(!(B->list(target, sd.domain_id))) { 
474    L<<Logger::Error<<"Backend signals error condition"<<endl;
475    outpacket->setRcode(2); // 'SERVFAIL'
476    sendPacket(outpacket,outsock);
477    return 0;
478  }
479  /* write first part of answer */
480
481  DLOG(L<<"Sending out SOA"<<endl);
482  outpacket=shared_ptr<DNSPacket>(q->replyPacket());
483  outpacket->addRecord(soa); // AXFR format begins and ends with a SOA record, so we add one
484  //  sendPacket(outpacket, outsock);
485  typedef map<string, NSECEntry, CanonicalCompare> nsecrepo_t;
486  nsecrepo_t nsecrepo;
487  // this is where the DNSKEYs go 
488
489  DNSSECKeeper::keyset_t keys = dk.getKeys(target);
490  BOOST_FOREACH(const DNSSECKeeper::keyset_t::value_type& value, keys) {
491    rr.qname = target;
492    rr.qtype = QType(QType::DNSKEY);
493    rr.ttl = sd.default_ttl;
494    rr.content = value.first.getDNSKEY().getZoneRepresentation();
495    NSECEntry& ne = nsecrepo[rr.qname];
496   
497    ne.d_set.insert(rr.qtype.getCode());
498    ne.d_ttl = rr.ttl;
499    outpacket->addRecord(rr);
500  }
501  /* now write all other records */
502
503  int count=0;
504  int chunk=100; // FIXME: this should probably be autosizing
505  if(::arg().mustDo("strict-rfc-axfrs"))
506    chunk=1;
507
508  outpacket->setCompress(false);
509  outpacket->d_dnssecOk=true; // WRONG
510
511  while(B->get(rr)) {
512    if(rr.auth || rr.qtype.getCode() == QType::NS) {
513      NSECEntry& ne = nsecrepo[rr.qname];
514      ne.d_set.insert(rr.qtype.getCode());
515      ne.d_ttl = rr.ttl;
516    }
517    if(rr.qtype.getCode() == QType::SOA)
518      continue; // skip SOA - would indicate end of AXFR
519
520    if(rr.qtype.getCode() == QType::NS) {
521      // cerr<<rr.qname<<" NS, auth="<<rr.auth<<endl;
522    }
523
524    outpacket->addRecord(rr);
525
526    if(!((++count)%chunk)) {
527      count=0;
528   
529      sendPacket(outpacket, outsock);
530
531      outpacket=shared_ptr<DNSPacket>(q->replyPacket());
532      outpacket->setCompress(false);
533      outpacket->d_dnssecOk=true; // WRONG
534      // FIXME: Subsequent messages SHOULD NOT have a question section, though the final message MAY.
535    }
536  }
537 
538  if(dk.haveActiveKSKFor(target)) {
539    for(nsecrepo_t::const_iterator iter = nsecrepo.begin(); iter != nsecrepo.end(); ++iter) {
540  //    cerr<<"Adding for '"<<iter->first<<"'\n";
541      NSECRecordContent nrc;
542      nrc.d_set = iter->second.d_set;
543      nrc.d_set.insert(QType::RRSIG);
544      nrc.d_set.insert(QType::NSEC);
545      if(boost::next(iter) != nsecrepo.end()) {
546        nrc.d_next = boost::next(iter)->first;
547      }
548      else
549        nrc.d_next=nsecrepo.begin()->first;
550 
551      rr.qname = iter->first;
552 
553      rr.ttl = iter->second.d_ttl;
554      rr.content = nrc.getZoneRepresentation();
555      rr.qtype = QType::NSEC;
556      rr.d_place = DNSResourceRecord::ANSWER;
557      rr.auth=true;
558      outpacket->addRecord(rr);
559      count++;
560    }
561  }
562 
563  if(count) {
564    sendPacket(outpacket, outsock);
565  }
566
567  DLOG(L<<"Done writing out records"<<endl);
568  /* and terminate with yet again the SOA record */
569  outpacket=shared_ptr<DNSPacket>(q->replyPacket());
570  soa.priority=1234;
571  outpacket->addRecord(soa);
572  sendPacket(outpacket, outsock);
573  DLOG(L<<"last packet - close"<<endl);
574  L<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
575
576  return 1;
577}
578
579TCPNameserver::~TCPNameserver()
580{
581  delete d_connectionroom_sem;
582}
583
584TCPNameserver::TCPNameserver()
585{
586//  sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
587  d_connectionroom_sem = new Semaphore( ::arg().asNum( "max-tcp-connections" ));
588
589  s_timeout=10;
590  vector<string>locals;
591  stringtok(locals,::arg()["local-address"]," ,");
592
593  vector<string>locals6;
594  stringtok(locals6,::arg()["local-ipv6"]," ,");
595
596  if(locals.empty() && locals6.empty())
597    throw AhuException("No local address specified");
598
599  d_highfd=0;
600
601  vector<string> parts;
602  stringtok( parts, ::arg()["allow-axfr-ips"], ", \t" ); // is this IP on the guestlist?
603  for( vector<string>::const_iterator i = parts.begin(); i != parts.end(); ++i ) {
604    d_ng.addMask( *i );
605  }
606
607#ifndef WIN32
608  signal(SIGPIPE,SIG_IGN);
609#endif // WIN32
610
611  for(vector<string>::const_iterator laddr=locals.begin();laddr!=locals.end();++laddr) {
612    int s=socket(AF_INET,SOCK_STREAM,0); 
613
614    if(s<0) 
615      throw AhuException("Unable to acquire TCP socket: "+stringerror());
616
617    ComboAddress local(*laddr, ::arg().asNum("local-port"));
618     
619    int tmp=1;
620    if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
621      L<<Logger::Error<<"Setsockopt failed"<<endl;
622      exit(1); 
623    }
624
625    if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
626      L<<Logger::Error<<"binding to TCP socket: "<<strerror(errno)<<endl;
627      throw AhuException("Unable to bind to TCP socket");
628    }
629   
630    listen(s,128);
631    L<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
632    d_sockets.push_back(s);
633    struct pollfd pfd;
634    memset(&pfd, 0, sizeof(pfd));
635    pfd.fd = s;
636    pfd.events = POLLIN;
637
638    d_prfds.push_back(pfd);
639
640    d_highfd=max(s,d_highfd);
641  }
642
643#if !WIN32 && HAVE_IPV6
644  for(vector<string>::const_iterator laddr=locals6.begin();laddr!=locals6.end();++laddr) {
645    int s=socket(AF_INET6,SOCK_STREAM,0); 
646
647    if(s<0) 
648      throw AhuException("Unable to acquire TCPv6 socket: "+stringerror());
649
650    ComboAddress local(*laddr, ::arg().asNum("local-port"));
651
652    int tmp=1;
653    if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
654      L<<Logger::Error<<"Setsockopt failed"<<endl;
655      exit(1); 
656    }
657
658    if(bind(s, (const sockaddr*)&local, local.getSocklen())<0) {
659      L<<Logger::Error<<"binding to TCP socket: "<<strerror(errno)<<endl;
660      throw AhuException("Unable to bind to TCPv6 socket");
661    }
662   
663    listen(s,128);
664    L<<Logger::Error<<"TCPv6 server bound to "<<local.toStringWithPort()<<endl;
665    d_sockets.push_back(s);
666
667    struct pollfd pfd;
668    memset(&pfd, 0, sizeof(pfd));
669    pfd.fd = s;
670    pfd.events = POLLIN;
671
672    d_prfds.push_back(pfd);
673    d_highfd=max(s, d_highfd);
674  }
675#endif // WIN32
676}
677
678
679//! Start of TCP operations thread, we launch a new thread for each incoming TCP question
680void TCPNameserver::thread()
681{
682  struct timeval tv;
683  tv.tv_sec=1;
684  tv.tv_usec=0;
685  try {
686    for(;;) {
687      int fd;
688      struct sockaddr_in remote;
689      Utility::socklen_t addrlen=sizeof(remote);
690
691      int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
692      if(ret <= 0)
693        continue;
694
695      int sock=-1;
696      BOOST_FOREACH(const struct pollfd& pfd, d_prfds) {
697        if(pfd.revents == POLLIN) {
698          sock = pfd.fd;
699          addrlen=sizeof(remote);
700
701          if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
702            L<<Logger::Error<<"TCP question accept error: "<<strerror(errno)<<endl;
703           
704            if(errno==EMFILE) {
705              L<<Logger::Error<<Logger::NTLog<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
706              exit(1);
707            }
708          }
709          else {
710            pthread_t tid;
711            d_connectionroom_sem->wait(); // blocks if no connections are available
712
713            int room;
714            d_connectionroom_sem->getValue( &room);
715            if(room<1)
716              L<<Logger::Warning<<Logger::NTLog<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
717
718            if(pthread_create(&tid, 0, &doConnection, (void *)fd)) {
719              L<<Logger::Error<<"Error creating thread: "<<stringerror()<<endl;
720              d_connectionroom_sem->post();
721            }
722          }
723        }
724      }
725    }
726  }
727  catch(AhuException &AE) {
728    L<<Logger::Error<<"TCP Namerserver thread dying because of fatal error: "<<AE.reason<<endl;
729  }
730  catch(...) {
731    L<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
732  }
733  exit(1); // take rest of server with us
734}
735
736
Note: See TracBrowser for help on using the browser.