From: Peter van Dijk Date: Fri, 12 Oct 2012 09:14:49 +0000 (+0000) Subject: import axfr-lock patch by Ruben d'Arco. This patch aims to prevent slaving zones... X-Git-Tag: auth-3.2-rc1~75 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a71bee2974cade1c3aa7240a2365518aa93826d5;p=thirdparty%2Fpdns.git import axfr-lock patch by Ruben d'Arco. This patch aims to prevent slaving zones twice in parallel, and adds some useful diagnostics. git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@2807 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- diff --git a/pdns/communicator.cc b/pdns/communicator.cc index a5209c5ee3..28aa63c2ba 100644 --- a/pdns/communicator.cc +++ b/pdns/communicator.cc @@ -45,7 +45,6 @@ void CommunicatorClass::retrievalLoopThread(void) continue; sr=d_suckdomains.front(); - d_suckdomains.pop_front(); } try { suck(sr.domain,sr.master); @@ -53,16 +52,23 @@ void CommunicatorClass::retrievalLoopThread(void) catch(AhuException& ae) { cerr<<"Error: "<(); + uqIndex.erase(sr); + } } + } void CommunicatorClass::go() { pthread_t tid; - pthread_create(&tid,0,&launchhelper,this); + pthread_create(&tid,0,&launchhelper,this); // Starts CommunicatorClass::mainloop() for(int n=0; n < ::arg().asNum("retrieval-threads"); ++n) - pthread_create(&tid, 0, &retrieveLaunchhelper, this); + pthread_create(&tid, 0, &retrieveLaunchhelper, this); // Starts CommunicatorClass::retrievalLoopThread() } diff --git a/pdns/communicator.hh b/pdns/communicator.hh index 2d322c79e3..d2e15a6d6b 100644 --- a/pdns/communicator.hh +++ b/pdns/communicator.hh @@ -60,6 +60,7 @@ typedef multi_index_container< ordered_unique, identity > > > UniQueue; +typedef UniQueue::index::type domains_by_name_t; class NotificationQueue { @@ -78,13 +79,13 @@ public: bool removeIf(const string &remote, uint16_t id, const string &domain) { - for(d_nqueue_t::iterator i=d_nqueue.begin();i!=d_nqueue.end();++i) { + for(d_nqueue_t::iterator i=d_nqueue.begin(); i!=d_nqueue.end(); ++i) { // cout<id<<" "<ip<<" "<domain<<" "<ip,':'); + tie(remoteIP, port)=splitField(remote, ':'); + tie(ourIP, port)=splitField(i->ip, ':'); if(i->id==id && ourIP == remoteIP && i->domain==domain) { d_nqueue.erase(i); return true; @@ -131,7 +132,7 @@ private: time_t next; }; - typedef std::listd_nqueue_t; + typedef std::list d_nqueue_t; d_nqueue_t d_nqueue; }; @@ -156,12 +157,14 @@ public: void drillHole(const string &domain, const string &ip); bool justNotified(const string &domain, const string &ip); - void addSuckRequest(const string &domain, const string &master, bool priority=false); + void addSuckRequest(const string &domain, const string &master); void addSlaveCheckRequest(const DomainInfo& di, const ComboAddress& remote); void addTrySuperMasterRequest(DNSPacket *p); void notify(const string &domain, const string &ip); void mainloop(); void retrievalLoopThread(); + void sendNotification(int sock, const string &domain, const ComboAddress& remote, uint16_t id); + static void *launchhelper(void *p) { static_cast(p)->mainloop(); diff --git a/pdns/mastercommunicator.cc b/pdns/mastercommunicator.cc index 3ac1fc8462..8a72e31a21 100644 --- a/pdns/mastercommunicator.cc +++ b/pdns/mastercommunicator.cc @@ -129,10 +129,9 @@ time_t CommunicatorClass::doNotifications() ComboAddress from; Utility::socklen_t fromlen=sizeof(from); char buffer[1500]; - int size; - // receive incoming notifications on the nonblocking socket and take them off the list - int sock; + int size, sock; + // receive incoming notifications on the nonblocking socket and take them off the list while(waitFor2Data(d_nsock4, d_nsock6, 0, 0, &sock) > 0) { size=recvfrom(sock,buffer,sizeof(buffer),0,(struct sockaddr *)&from,&fromlen); if(size < 0) @@ -183,6 +182,18 @@ time_t CommunicatorClass::doNotifications() return d_nq.earliest(); } +void CommunicatorClass::sendNotification(int sock, const string& domain, const ComboAddress& remote, uint16_t id) +{ + vector packet; + DNSPacketWriter pw(packet, domain, QType::SOA, 1, Opcode::Notify); + pw.getHeader()->id = id; + pw.getHeader()->aa = true; + + if(sendto(sock, &packet[0], packet.size(), 0, (struct sockaddr*)(&remote), remote.getSocklen()) < 0) { + throw ResolverException("Unable to send notify to "+remote.toStringWithPort()+": "+stringerror()); + } +} + void CommunicatorClass::drillHole(const string &domain, const string &ip) { Lock l(&d_holelock); diff --git a/pdns/misc.cc b/pdns/misc.cc index f822673e14..42b73b3c2e 100644 --- a/pdns/misc.cc +++ b/pdns/misc.cc @@ -322,7 +322,7 @@ int waitForRWData(int fd, bool waitForRead, int seconds, int useconds) return ret; } -// returns -1 in case if error, 0 if no data is available, 1 if there is. In the first two cases, errno is set +// returns -1 in case of error, 0 if no data is available, 1 if there is. In the first two cases, errno is set int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int*fd) { int ret; diff --git a/pdns/resolver.cc b/pdns/resolver.cc index 7689c5b313..9cc3b8487c 100644 --- a/pdns/resolver.cc +++ b/pdns/resolver.cc @@ -45,19 +45,6 @@ #include "namespaces.hh" -int sendNotification(int sock, const string& domain, const ComboAddress& remote, uint16_t id) -{ - vector packet; - DNSPacketWriter pw(packet, domain, QType::SOA, 1, Opcode::Notify); - pw.getHeader()->id = id; - pw.getHeader()->aa = true; - - if(sendto(sock, &packet[0], packet.size(), 0, (struct sockaddr*)(&remote), remote.getSocklen())<0) { - throw ResolverException("Unable to send notify to "+remote.toStringWithPort()+": "+stringerror()); - } - return true; -} - int makeQuerySocket(const ComboAddress& local, bool udpOrTCP) { ComboAddress ourLocal(local); diff --git a/pdns/resolver.hh b/pdns/resolver.hh index 391de613be..3633bf2ddc 100644 --- a/pdns/resolver.hh +++ b/pdns/resolver.hh @@ -44,9 +44,6 @@ public: ResolverException(const string &reason) : AhuException(reason){} }; -// send out an update notification for a domain to an IPv4/v6 address -int sendNotification(int sock, const string &domain, const ComboAddress& remote, uint16_t id); - // make an IPv4 or IPv6 query socket int makeQuerySocket(const ComboAddress& local, bool udpOrTCP); //! Resolver class. Can be used synchronously and asynchronously, over IPv4 and over IPv6 (simultaneously) diff --git a/pdns/slavecommunicator.cc b/pdns/slavecommunicator.cc index 368433a4cb..04bf34d56b 100644 --- a/pdns/slavecommunicator.cc +++ b/pdns/slavecommunicator.cc @@ -48,20 +48,15 @@ template bool rfc1982LessThan(T a, T b) return ((signed)(a - b)) < 0; } -void CommunicatorClass::addSuckRequest(const string &domain, const string &master, bool priority) +void CommunicatorClass::addSuckRequest(const string &domain, const string &master) { Lock l(&d_lock); - SuckRequest sr; sr.domain = domain; sr.master = master; pair res; - if(priority) { - res=d_suckdomains.push_front(sr); - } - else { - res=d_suckdomains.push_back(sr); - } + + res=d_suckdomains.push_back(sr); if(res.second) { d_suck_sem.post(); @@ -484,7 +479,7 @@ void CommunicatorClass::slaveRefresh(PacketHandler *P) { UeberBackend *B=dynamic_cast(P->getBackend()); vector rdomains; - vector sdomains; // the bool is for 'presigned' + vector sdomains; // the bool is for 'presigned' vector trysuperdomains; { @@ -513,7 +508,6 @@ void CommunicatorClass::slaveRefresh(PacketHandler *P) DNSSECKeeper dk(B); // NOW HEAR THIS! This DK uses our B backend, so no interleaved access! { Lock l(&d_lock); - typedef UniQueue::index::type domains_by_name_t; domains_by_name_t& nameindex=boost::multi_index::get(d_suckdomains); BOOST_FOREACH(DomainInfo& di, rdomains) { @@ -523,8 +517,10 @@ void CommunicatorClass::slaveRefresh(PacketHandler *P) continue; // remove unfresh domains already queued for AXFR, no sense polling them again sr.master=*di.masters.begin(); - if(nameindex.count(sr)) + if(nameindex.count(sr)) { + L<