root/trunk/pdns/pdns/receiver.cc @ 108

Revision 108, 14.6 KB (checked in by ahu, 10 years ago)

generic sql commands

  • 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: receiver.cc,v 1.6 2003/01/02 15:43:00 ahu Exp $
20#include <cstdio>
21#include <signal.h>
22#include <cstring>
23#include <cstdlib>
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <netinet/in.h>
27#include <arpa/inet.h>
28#include <iostream>
29#include <string>
30#include <sys/stat.h>
31#include <unistd.h>
32#include <sys/time.h>
33#include <sys/types.h>
34#include <sys/wait.h>
35#include <errno.h>
36#include <pthread.h>
37#include <unistd.h>
38#include <sys/mman.h>
39#include <fcntl.h>
40#include <fstream>
41
42#include "config.h"
43#include "dns.hh"
44#include "dnsbackend.hh"
45#include "ueberbackend.hh"
46#include "dnspacket.hh"
47#include "nameserver.hh"
48#include "distributor.hh"
49#include "logger.hh"
50#include "arguments.hh"
51#include "packethandler.hh"
52#include "statbag.hh"
53#include "tcpreceiver.hh"
54#include "packetcache.hh"
55#include "ws.hh"
56#include "misc.hh"
57#include "dynlistener.hh"
58#include "dynhandler.hh"
59#include "communicator.hh"
60#include "dnsproxy.hh"
61#include "utility.hh"
62#include "common_startup.hh"
63
64time_t s_starttime;
65
66string s_programname="pdns"; // used in packethandler.cc
67
68char *funnytext=
69"*****************************************************************************\n"\
70"Ok, you just ran pdns_server through 'strings' hoping to find funny messages.\n"\
71"Well, you found one. \n"\
72"Two ions are flying through their particle accelerator, says the one to the\n"
73"other 'I think I've lost an electron!' \n"\
74"So the other one says, 'Are you sure?'. 'YEAH! I'M POSITIVE!'\n"\
75"                                            the pdns crew - pdns@powerdns.com\n"
76"*****************************************************************************\n";
77
78
79// start (sys)logging
80
81/** \var Logger L
82\brief All logging is done via L, a Logger instance
83*/
84
85
86/**
87\file receiver.cc
88\brief The main loop of powerdns
89
90This file is where it all happens - main is here, as are the two pivotal threads qthread() and athread()
91*/
92
93void daemonize(void)
94{
95  if(fork())
96    exit(0); // bye bye
97 
98  setsid(); 
99
100  // cleanup open fds, but skip sockets
101  close(0);
102  close(1);
103  close(2);
104
105}
106
107
108static int cpid;
109
110static void takedown(int i)
111{
112  if(cpid) {
113    L<<Logger::Error<<"Guardian is killed, taking down children with us"<<endl;
114    kill(cpid,SIGKILL);
115    exit(1);
116  }
117}
118
119static void writePid(void)
120{
121  string fname=arg()["socket-dir"]+"/"+s_programname+".pid";
122  ofstream of(fname.c_str());
123  if(of)
124    of<<getpid()<<endl;
125  else
126    L<<Logger::Error<<"Requested to write pid for "<<getpid()<<" to "<<fname<<" failed: "<<strerror(errno)<<endl;
127}
128
129int d_fd1[2], d_fd2[2];
130FILE *d_fp;
131
132static string DLRestHandler(const vector<string>&parts, pid_t ppid)
133{
134  string line;
135 
136  for(vector<string>::const_iterator i=parts.begin();i!=parts.end();++i) {
137    if(i!=parts.begin())
138      line.append(1,' ');
139    line.append(*i);
140  }
141  line.append(1,'\n');
142 
143  write(d_fd1[1],line.c_str(),line.size()+1);
144  char mesg[512];
145  string response;
146  while(fgets(mesg,sizeof(mesg),d_fp)) {
147    if(*mesg=='\n')
148      break;
149    response+=mesg;
150  }
151  chomp(response,"\n");
152  return response;
153}
154
155static string DLCycleHandler(const vector<string>&parts, pid_t ppid)
156{
157  kill(cpid,SIGKILL); // why?
158  return "ok";
159}
160
161static int guardian(int argc, char **argv)
162{
163  if(isGuarded(argv))
164    return 0;
165
166  int infd=0, outfd=1;
167
168  DynListener dlg(s_programname);
169  dlg.registerFunc("QUIT",&DLQuitHandler);
170  dlg.registerFunc("CYCLE",&DLCycleHandler);
171  dlg.registerFunc("PING",&DLPingHandler);
172  dlg.registerFunc("STATUS",&DLStatusHandler);
173  dlg.registerRestFunc(&DLRestHandler);
174  dlg.go();
175  string progname=argv[0];
176
177  bool first=true;
178  cpid=0;
179
180  for(;;) {
181    int pid;
182    setStatus("Launching child");
183
184    if(pipe(d_fd1)<0 || pipe(d_fd2)<0) {
185      L<<Logger::Critical<<"Unable to open pipe for coprocess: "<<strerror(errno)<<endl;
186      exit(1);
187    }
188
189    if(!(pid=fork())) { // child
190      signal(SIGTERM, SIG_DFL);
191
192      signal(SIGHUP, SIG_DFL);
193      signal(SIGUSR1, SIG_DFL);
194      signal(SIGUSR2, SIG_DFL);
195
196      char **const newargv=new char*[argc+2];
197      int n;
198
199      if(arg()["config-name"]!="") {
200        progname+="-"+arg()["config-name"];
201        L<<Logger::Error<<"Virtual configuration name: "<<arg()["config-name"]<<endl;
202      }
203
204      newargv[0]=strdup(const_cast<char *>((progname+"-instance").c_str()));
205      for(n=1;n<argc;n++) {
206        newargv[n]=argv[n];
207      }
208      newargv[n]=0;
209     
210      L<<Logger::Error<<"Guardian is launching an instance"<<endl;
211      close(d_fd1[1]);
212      close(d_fd2[0]);
213
214      if(d_fd1[0]!= infd) {
215        dup2(d_fd1[0], infd);
216        close(d_fd1[0]);
217      }
218
219      if(d_fd2[1]!= outfd) {
220        dup2(d_fd2[1], outfd);
221        close(d_fd2[1]);
222      }
223      if(execv(argv[0], newargv)<0) {
224        L<<Logger::Error<<"Unable to execv '"<<argv[0]<<"': "<<strerror(errno)<<endl;
225        char **p=newargv;
226        while(*p)
227          L<<Logger::Error<<*p++<<endl;
228
229        exit(1);
230      }
231      L<<Logger::Error<<"execve returned!!"<<endl;
232      // never reached
233    }
234    else if(pid>0) { // parent
235      close(d_fd1[0]);
236      close(d_fd2[1]);
237      if(!(d_fp=fdopen(d_fd2[0],"r"))) {
238        L<<Logger::Critical<<"Unable to associate a file pointer with pipe: "<<stringerror()<<endl;
239        exit(1);
240      }
241      setbuf(d_fp,0); // no buffering please, confuses select
242
243      if(first) {
244        first=false;
245        signal(SIGTERM, takedown);
246
247        signal(SIGHUP, SIG_IGN);
248        signal(SIGUSR1, SIG_IGN);
249        signal(SIGUSR2, SIG_IGN);
250
251        writePid();
252      }
253
254      int status;
255      cpid=pid;
256      for(;;) {
257        int ret=waitpid(pid,&status,WNOHANG);
258
259        if(ret<0) {
260          L<<Logger::Error<<"In guardian loop, waitpid returned error: "<<strerror(errno)<<endl;
261          L<<Logger::Error<<"Dying"<<endl;
262          exit(1);
263        }
264        else if(ret) // something exited
265          break;
266        else { // child is alive
267          // execute some kind of ping here
268          if(DLQuitPlease())
269            takedown(1);
270          setStatus("Child running on pid "+itoa(pid));
271          sleep(1);
272        }
273      }
274      close(d_fd1[1]);
275      fclose(d_fp);
276
277      if(WIFEXITED(status)) {
278        int ret=WEXITSTATUS(status);
279
280        if(ret==99) {
281          L<<Logger::Error<<"Child requested a stop, exiting"<<endl;
282          exit(1);
283        }
284        setStatus("Child died with code "+itoa(ret));
285        L<<Logger::Error<<"Our pdns instance exited with code "<<ret<<endl;
286        L<<Logger::Error<<"Respawning"<<endl;
287
288        sleep(1);
289        continue;
290      }
291      if(WIFSIGNALED(status)) {
292        int sig=WTERMSIG(status);
293        setStatus("Child died because of signal "+itoa(sig));
294        L<<Logger::Error<<"Our pdns instance ("<<pid<<") exited after signal "<<sig<<endl;
295#ifdef WCOREDUMP
296        if(WCOREDUMP(status)) 
297          L<<Logger::Error<<"Dumped core"<<endl;
298#endif
299
300        L<<Logger::Error<<"Respawning"<<endl;
301        sleep(1);
302        continue;
303      }
304      L<<Logger::Error<<"No clue what happened! Respawning"<<endl;
305    }
306    else {
307      L<<Logger::Error<<"Unable to fork: "<<strerror(errno)<<endl;
308      exit(1);
309    }
310  }
311}
312
313static void UNIX_declareArguments()
314{
315  static char pietje[128]="!@@SYSCONFDIR@@:";
316  arg().set("config-dir","Location of configuration directory (pdns.conf)")=
317    strcmp(pietje+1,"@@SYSCONFDIR@@:") ? pietje+strlen("@@SYSCONFDIR@@:")+1 : SYSCONFDIR;
318 
319  arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
320  arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR;
321  arg().set("module-dir","Default directory for modules")=LIBDIR;
322  arg().set("chroot","If set, chroot to this directory for more security")="";
323  arg().set("logging-facility","Log under a specific facility")="";
324  arg().set("daemon","Operate as a daemon")="no";
325
326}
327
328static void loadModules()
329{
330  if(!arg()["load-modules"].empty()) { 
331    vector<string>modules;
332   
333    stringtok(modules,arg()["load-modules"],",");
334   
335    for(vector<string>::const_iterator i=modules.begin();i!=modules.end();++i) {
336      bool res;
337      const string &module=*i;
338     
339      if(module.find(".")==string::npos)
340        res=UeberBackend::loadmodule(arg()["module-dir"]+"/lib"+module+"backend.so");
341      else if(module[0]=='/' || (module[0]=='.' && module[1]=='/') || (module[0]=='.' && module[1]=='.'))    // absolute or current path
342        res=UeberBackend::loadmodule(module);
343      else
344        res=UeberBackend::loadmodule(arg()["module-dir"]+"/"+module);
345     
346      if(res==false) {
347        L<<Logger::Error<<"receiver unable to load module "<<module<<endl;
348        exit(1);
349      }
350    }
351  }
352}
353
354
355
356#ifdef __linux__
357#include <execinfo.h>
358static void tbhandler(int num)
359{
360  L<<Logger::Critical<<"Got a signal "<<num<<", attempting to print trace: "<<endl;
361  void *array[20]; //only care about last 17 functions (3 taken with tracing support)
362  size_t size;
363  char **strings;
364  size_t i;
365 
366  size = backtrace (array, 20);
367  strings = backtrace_symbols (array, size); //Need -rdynamic gcc (linker) flag for this to work
368 
369  for (i = 0; i < size; i++) //skip useless functions
370    L<<Logger::Error<<strings[i]<<endl;
371 
372 
373  signal(SIGABRT, SIG_DFL);
374  abort();//hopefully will give core
375
376}
377#endif
378
379//! The main function of pdns, the pdns process
380int main(int argc, char **argv)
381{ 
382  s_programname="pdns";
383  s_starttime=time(0);
384
385#ifdef __linux__
386  signal(SIGSEGV,tbhandler);
387  signal(SIGFPE,tbhandler);
388  signal(SIGABRT,tbhandler);
389  signal(SIGILL,tbhandler);
390#endif
391
392
393  L.toConsole(Logger::Warning);
394  try {
395    declareArguments();
396    UNIX_declareArguments();
397     
398    arg().laxParse(argc,argv); // do a lax parse
399   
400    if(arg()["config-name"]!="") 
401      s_programname+="-"+arg()["config-name"];
402   
403    (void)theL(s_programname);
404   
405    string configname=arg()["config-dir"]+"/"+s_programname+".conf";
406    cleanSlashes(configname);
407
408    if(!arg().mustDo("config") && !arg().mustDo("no-config")) // "config" == print a configuration file
409      arg().laxFile(configname.c_str());
410   
411    arg().laxParse(argc,argv); // reparse so the commandline still wins
412    if(!arg()["logging-facility"].empty()) {
413      int facility=arg().asNum("logging-facility");
414      switch(facility) {
415      case 0:
416        theL().setFacility(LOG_LOCAL0);
417        break;
418      case 1:
419        theL().setFacility(LOG_LOCAL1);
420        break;
421      case 2:
422        theL().setFacility(LOG_LOCAL2);
423        break;
424      case 3:
425        theL().setFacility(LOG_LOCAL3);
426        break;
427      case 4:
428        theL().setFacility(LOG_LOCAL4);
429        break;
430      case 5:
431        theL().setFacility(LOG_LOCAL5);
432        break;
433      case 6:
434        theL().setFacility(LOG_LOCAL6);
435        break;
436      case 7:
437        theL().setFacility(LOG_LOCAL7);
438        break;
439      default:
440        L<<Logger::Error<<"Unknown logging facility level"<<facility<<endl;
441        break;
442      }
443    }
444
445    L.toConsole((Logger::Urgency)(arg().asNum("loglevel"))); 
446
447    if(arg().mustDo("help") || arg().mustDo("config")) {
448      arg().set("daemon")="no";
449      arg().set("guardian")="no";
450    }
451
452    if(arg().mustDo("guardian") && !isGuarded(argv)) {
453      if(arg().mustDo("daemon")) {
454        L.toConsole(Logger::Critical);
455        daemonize();
456      }
457      guardian(argc, argv); 
458      // never get here, guardian will reinvoke process
459      cerr<<"Um, we did get here!"<<endl;
460    }
461   
462    // we really need to do work - either standalone or as an instance
463   
464    loadModules();
465    BackendMakers().launch(arg()["launch"]); // vrooooom!
466     
467    if(arg().mustDo("help")) {
468      cerr<<"syntax:"<<endl<<endl;
469      cerr<<arg().helpstring(arg()["help"])<<endl;
470      exit(99);
471    }
472   
473    if(arg().mustDo("config")) {
474      cout<<arg().configstring()<<endl;
475      exit(99);
476    }
477
478    if(arg().mustDo("list-modules")) {
479      vector<string>modules=BackendMakers().getModules();
480      cerr<<"Modules available:"<<endl;
481      for(vector<string>::const_iterator i=modules.begin();i!=modules.end();++i)
482        cout<<*i<<endl;
483
484      exit(99);
485    }
486    if(!BackendMakers().numLauncheable()) {
487      L<<Logger::Error<<"Unable to launch, no backends configured for querying"<<endl;
488        exit(99); // this isn't going to fix itself either
489    }   
490    if(arg().mustDo("daemon")) {
491      L.toConsole(Logger::None);
492      if(!isGuarded(argv))
493        daemonize();
494    }
495
496    if(isGuarded(argv)) {
497      L<<Logger::Warning<<"This is a guarded instance of pdns"<<endl;
498      dl=new DynListener; // listens on stdin
499    }
500    else {
501      L<<Logger::Warning<<"This is a standalone pdns"<<endl; 
502     
503      if(arg().mustDo("control-console"))
504        dl=new DynListener();
505      else
506        dl=new DynListener(s_programname);
507     
508      writePid();
509    }
510    dl->registerFunc("SHOW",&DLShowHandler);
511    dl->registerFunc("RPING",&DLPingHandler);
512    dl->registerFunc("QUIT",&DLRQuitHandler);
513    dl->registerFunc("UPTIME",&DLUptimeHandler);
514    dl->registerFunc("NOTIFY-HOST",&DLNotifyHostHandler);
515    dl->registerFunc("NOTIFY",&DLNotifyHandler);
516    dl->registerFunc("RELOAD",&DLReloadHandler);
517    dl->registerFunc("REDISCOVER",&DLRediscoverHandler);
518    dl->registerFunc("VERSION",&DLVersionHandler);
519    dl->registerFunc("PURGE",&DLPurgeHandler);
520    dl->registerFunc("CCOUNTS",&DLCCHandler);
521    dl->registerFunc("SET",&DLSettingsHandler);
522    dl->registerFunc("RETRIEVE",&DLNotifyRetrieveHandler);
523
524   
525    // reparse, with error checking
526    if(!arg().mustDo("no-config"))
527      arg().file(configname.c_str());
528    arg().parse(argc,argv);
529    UeberBackend::go();
530    N=new UDPNameserver; // this fails when we are not root, throws exception
531   
532    if(!arg().mustDo("disable-tcp"))
533      TN=new TCPNameserver; 
534  }
535  catch(const ArgException &A) {
536    L<<Logger::Error<<"Fatal error: "<<A.reason<<endl;
537    exit(1);
538  }
539 
540  declareStats();
541  DLOG(L<<Logger::Warning<<"Verbose logging in effect"<<endl);
542 
543  L<<Logger::Warning<<"PowerDNS "<<VERSION<<" (C) 2002 PowerDNS.COM BV ("<<__DATE__", "__TIME__<<") starting up"<<endl;
544
545  L<<Logger::Warning<<"PowerDNS comes with ABSOLUTELY NO WARRANTY. "
546    "This is free software, and you are welcome to redistribute it "
547    "according to the terms of the GPL version 2."<<endl;
548
549
550  try {
551
552    mainthread();
553  }
554  catch(AhuException &AE) {
555    if(!arg().mustDo("daemon"))
556      cerr<<"Exiting because: "<<AE.reason<<endl;
557    L<<Logger::Error<<"Exiting because: "<<AE.reason<<endl;
558  }     
559  catch(exception &e) {
560    if(!arg().mustDo("daemon"))
561      cerr<<"Exiting because of STL error: "<<e.what()<<endl;
562    L<<Logger::Error<<"Exiting because of STL error: "<<e.what()<<endl;
563  }
564  catch(...) {
565    cerr<<"Uncaught exception of unknown type - sorry"<<endl;
566  }
567
568  exit(1);
569 
570}
571
572
Note: See TracBrowser for help on using the browser.