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