root/trunk/pdns/pdns/ueberbackend.cc @ 76

Revision 76, 10.8 KB (checked in by ahu, 11 years ago)

small fixes

  • 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  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 as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18*/
19// $Id: ueberbackend.cc,v 1.5 2002/12/16 12:51:20 ahu Exp $
20/* (C) Copyright 2002 PowerDNS.COM BV */
21#include "utility.hh"
22
23#ifdef HAVE_CONFIG_H
24# include "config.h"
25#endif // HAVE_CONFIG_H
26
27#include <string>
28#include <map>
29#include <sys/types.h>
30
31#include <errno.h>
32#include <iostream>
33#include <sstream>
34#include <functional>
35
36#include "dns.hh"
37#include "arguments.hh"
38#include "dnsbackend.hh"
39#include "ueberbackend.hh"
40#include "dnspacket.hh"
41#include "logger.hh"
42#include "statbag.hh"
43#include "packetcache.hh"
44
45extern StatBag S;
46
47vector<UeberBackend *>UeberBackend::instances;
48pthread_mutex_t UeberBackend::instances_lock=PTHREAD_MUTEX_INITIALIZER;
49
50sem_t UeberBackend::d_dynserialize;
51string UeberBackend::programname;
52string UeberBackend::s_status;
53
54// initially we are blocked
55bool UeberBackend::d_go=false;
56pthread_mutex_t  UeberBackend::d_mut = PTHREAD_MUTEX_INITIALIZER;
57pthread_cond_t UeberBackend::d_cond = PTHREAD_COND_INITIALIZER;
58
59int UeberBackend::s_s=-1; // ?
60
61#ifdef NEED_RTLD_NOW
62#define RTLD_NOW RTLD_LAZY
63#endif
64
65//! Loads a module and reports it to all UeberBackend threads
66bool UeberBackend::loadmodule(const string &name)
67{
68  // TODO: Implement dynamic loading?
69#if !defined(WIN32) && !defined(DARWIN)
70  void *dlib=dlopen(name.c_str(), RTLD_NOW);
71 
72  if(dlib == NULL) {
73    L<<Logger::Warning <<"Unable to load module '"<<name<<"': "<<dlerror() << endl; 
74    return false;
75  }
76 
77  return true;
78
79#else
80  L << Logger::Warning << "This version doesn't support dynamic loading (yet)." << endl;
81   return false;
82
83#endif // WIN32
84
85}
86
87void UeberBackend::go(void)
88{
89  pthread_mutex_lock(&d_mut);
90  d_go=true;
91  pthread_cond_broadcast(&d_cond);
92  pthread_mutex_unlock(&d_mut);
93}
94
95bool UeberBackend::getDomainInfo(const string &domain, DomainInfo &di)
96{
97  for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
98    if((*i)->getDomainInfo(domain, di))
99      return true;
100  return false;
101}
102
103void UeberBackend::reload()
104{
105  for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
106  {
107    ( *i )->reload();
108  }
109}
110
111void UeberBackend::rediscover()
112{
113  for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
114  {
115    ( *i )->rediscover();
116  }
117}
118
119
120void UeberBackend::getUnfreshSlaveInfos(vector<DomainInfo>* domains)
121{
122  for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
123  {
124    ( *i )->getUnfreshSlaveInfos( domains );
125  } 
126}
127
128
129
130void UeberBackend::getUpdatedMasters(vector<DomainInfo>* domains)
131{
132  for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
133  {
134    ( *i )->getUpdatedMasters( domains );
135  }
136}
137
138
139bool UeberBackend::getSOA(const string &domain, SOAData &sd)
140{
141  d_question.qtype=QType::SOA;
142  d_question.qname=domain;
143  d_question.zoneId=-1;
144   
145  int cstat=cacheHas(d_question,d_answer);
146  if(cstat==0) {
147    return false;
148  }
149  else if(cstat==1) {
150    // ehm
151    DNSPacket::fillSOAData(d_answer.content,sd);
152    sd.domain_id=d_answer.domain_id;
153    sd.ttl=d_answer.ttl;
154
155    return true;
156  }
157   
158
159  for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
160    if((*i)->getSOA(domain, sd)) {
161      DNSResourceRecord rr;
162      rr.qname=domain;
163      rr.qtype=QType::SOA;
164      rr.content=DNSPacket::serializeSOAData(sd);
165      rr.ttl=sd.ttl;
166      rr.domain_id=sd.domain_id;
167      addOneCache(d_question,rr);
168      return true;
169    }
170
171  addNegCache(d_question); 
172  return false;
173}
174
175bool UeberBackend::superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *account, DNSBackend **db)
176{
177  for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
178    if((*i)->superMasterBackend(ip,domain,nsset,account, db))
179      return true;
180  return false;
181
182}
183
184void UeberBackend::setStatus(const string &st)
185{
186  s_status=st;
187}
188
189UeberBackend::UeberBackend()
190{
191  UeberBackend("default");
192}
193
194UeberBackend::UeberBackend(const string &pname)
195{
196  programname=pname;
197  pthread_mutex_lock(&instances_lock);
198  instances.push_back(this); // report to the static list of ourself
199  pthread_mutex_unlock(&instances_lock);
200
201  tid=pthread_self(); 
202  stale=false;
203
204  backends=BackendMakers().all();
205}
206
207void UeberBackend::die()
208{
209  cleanup();
210  stale=true;
211}
212
213void del(DNSBackend* d)
214{
215  delete d;
216}
217
218void UeberBackend::cleanup()
219{
220  pthread_mutex_lock(&instances_lock);
221
222  remove(instances.begin(),instances.end(),this);
223  instances.resize(instances.size()-1);
224
225  pthread_mutex_unlock(&instances_lock);
226
227  for_each(backends.begin(),backends.end(),del);
228}
229
230int UeberBackend::cacheHas(const Question &q, DNSResourceRecord &rr)
231{
232  extern PacketCache PC;
233  static int *qcachehit=S.getPointer("query-cache-hit");
234  static int *qcachemiss=S.getPointer("query-cache-miss");
235
236  static int negqueryttl=arg().asNum("negquery-cache-ttl");
237  static int queryttl=arg().asNum("query-cache-ttl");
238  if(!negqueryttl && !queryttl) {
239    (*qcachemiss)++;
240    return -1;
241  }
242
243  string content;
244  //  L<<Logger::Warning<<"looking up: "<<q.qname+"|N|"+q.qtype.getName()+"|"+itoa(q.zoneId)<<endl;
245  bool ret=PC.getKey(q.qname+"|Q|"+q.qtype.getName()+"|"+itoa(q.zoneId), content);   // think about lowercasing here
246
247  if(!ret) {
248    (*qcachemiss)++;
249    return -1;
250  }
251
252  (*qcachehit)++;
253  if(content.empty())
254    return 0;
255  rr.unSerialize(content);
256  return 1;
257}
258
259void UeberBackend::addNegCache(const Question &q)
260{
261  extern PacketCache PC;
262  static int negqueryttl=arg().asNum("negquery-cache-ttl");
263  if(!negqueryttl)
264    return;
265  //  L<<Logger::Warning<<"negative inserting: "<<q.qname+"|N|"+q.qtype.getName()+"|"+itoa(q.zoneId)<<endl;
266  PC.insert(q.qname+"|Q|"+q.qtype.getName()+"|"+itoa(q.zoneId),"",negqueryttl);
267}
268
269void UeberBackend::addOneCache(const Question &q, const DNSResourceRecord &rr)
270{
271  extern PacketCache PC;
272  static int queryttl=arg().asNum("query-cache-ttl");
273  if(!queryttl)
274    return;
275
276  PC.insert(q.qname+"|Q|"+q.qtype.getName()+"|"+itoa(q.zoneId),rr.serialize(),queryttl);
277}
278
279
280UeberBackend::~UeberBackend()
281{
282  DLOG(L<<Logger::Error<<"UeberBackend destructor called, removing ourselves from instances, and deleting our backends"<<endl);
283  cleanup();
284}
285
286// this handle is more magic than most
287void UeberBackend::lookup(const QType &qtype,const string &qname, DNSPacket *pkt_p, int zoneId)
288{
289  if(stale) {
290    L<<Logger::Error<<"Stale ueberbackend received question, signalling that we want to be recycled"<<endl;
291    throw AhuException("We are stale, please recycle");
292  }
293
294  DLOG(L<<"UeberBackend received question for "<<qtype.getName()<<" of "<<qname<<endl);
295  if(!d_go) {
296    pthread_mutex_lock(&d_mut);
297    while (d_go==false) {
298      L<<Logger::Error<<"UeberBackend is blocked, waiting for 'go'"<<endl;
299      pthread_cond_wait(&d_cond, &d_mut);
300      L<<Logger::Error<<"Broadcast received, unblocked"<<endl;
301    }
302    pthread_mutex_unlock(&d_mut);
303  }
304
305  d_handle.i=0;
306  d_handle.qtype=qtype;
307  d_handle.qname=qname;
308  d_handle.pkt_p=pkt_p;
309  d_ancount=0;
310
311  if(!backends.size()) {
312    L<<Logger::Error<<Logger::NTLog<<"No database backends available - unable to answer questions."<<endl;
313    stale=true; // please recycle us!
314    throw AhuException("We are stale, please recycle");
315  }
316  else {
317    d_question.qtype=qtype;
318    d_question.qname=qname;
319    d_question.zoneId=zoneId;
320    int cstat=cacheHas(d_question,d_answer);
321    if(cstat<0) { // nothing
322      d_negcached=d_cached=false;
323      (d_handle.d_hinterBackend=backends[d_handle.i++])->lookup(qtype, qname,pkt_p,zoneId);
324    } 
325    else if(cstat==0) {
326      d_negcached=true;
327      d_cached=false;
328    }
329    else {
330      d_negcached=false;
331      d_cached=true;
332    }
333  }
334
335  d_handle.parent=this;
336
337}
338
339bool UeberBackend::get(DNSResourceRecord &rr)
340{
341  if(d_negcached) {
342    return false; 
343  }
344
345  if(d_cached) {
346    rr=d_answer;
347    d_negcached=true; // ugly, confusing
348    return true;
349  }
350
351  if(!d_handle.get(rr)) {
352    if(!d_ancount && !d_handle.qname.empty()) // don't cache axfr
353      addNegCache(d_question);
354
355    if(d_ancount==1) {
356      addOneCache(d_question,lastrr);
357    }
358
359    return false;
360  }
361
362  if(!d_ancount++) {
363    lastrr=rr;
364  }
365  return true;
366}
367
368bool UeberBackend::list(int domain_id)
369{
370  d_cached=d_negcached=false;
371  d_ancount=0;
372  if(stale) {
373    L<<Logger::Error<<"Stale ueberbackend received question, signalling that we want to be recycled"<<endl;
374    throw AhuException("We are stale, please recycle");
375  }
376
377  DLOG(L<<"UeberBackend received list request for domain id "<<domain_id<<endl);
378
379  pthread_mutex_lock(&d_mut);
380  while (d_go==false) {
381    L<<Logger::Error<<"UeberBackend is blocked, waiting for 'go'"<<endl;
382    pthread_cond_wait(&d_cond, &d_mut);
383    L<<Logger::Error<<"Broadcast received, unblocked"<<endl;
384  }
385
386  pthread_mutex_unlock(&d_mut);
387
388  d_handle.i=0;
389  d_handle.pkt_p=0;
390  d_handle.qname="";
391  d_negcached=false;
392
393  if(!backends.size()) {
394    return 0; // we failed
395  }
396  else {
397    while(!(d_handle.d_hinterBackend=backends[d_handle.i++])->list(domain_id) && d_handle.i<backends.size())
398      ;
399  }
400  d_handle.parent=this;
401
402  return true;
403}
404 
405
406int UeberBackend::handle::instances=0;
407
408UeberBackend::handle::handle()
409{
410  //  L<<Logger::Warning<<"Handle instances: "<<instances<<endl;
411  instances++;
412}
413
414UeberBackend::handle::~handle()
415{
416  instances--;
417}
418
419
420
421
422
423bool UeberBackend::handle::get(DNSResourceRecord &r)
424{
425  DLOG(L << "Ueber get() was called for a "<<qtype.getName()<<" record" << endl);
426  bool isMore=false;
427  while(d_hinterBackend && !(isMore=d_hinterBackend->get(r))) { // this backend out of answers
428    if(i<parent->backends.size()) {
429      DLOG(L<<"Backend #"<<i<<" of "<<parent->backends.size()
430           <<" out of answers, taking next"<<endl);
431     
432      d_hinterBackend=parent->backends[i++];
433      d_hinterBackend->lookup(qtype,qname,pkt_p);
434    }
435    else 
436      break;
437
438    DLOG(L<<"Now asking backend #"<<i<<endl);
439  }
440
441  if(!isMore && i==parent->backends.size()) {
442    DLOG(L<<"UeberBackend reached end of backends"<<endl);
443    return false;
444  }
445
446  DLOG(L<<"Found an answering backend - will not try another one"<<endl);
447  i=parent->backends.size(); // don't go on to the next backend
448  return true;
449}
Note: See TracBrowser for help on using the browser.