# INCLUDES=-I/usr/include/mysql
-rec_control_SOURCES=rec_channel.cc rec_channel.hh rec_control.cc
+rec_control_SOURCES=rec_channel.cc rec_channel.hh rec_control.cc arguments.cc arguments.hh
pdns_recursor_SOURCES=syncres.cc resolver.hh misc.cc unix_utility.cc qtype.cc \
-logger.cc statbag.cc dnspacket.cc arguments.cc lwres.cc pdns_recursor.cc lwres.hh \
-mtasker.hh sillyrecords.cc syncres.hh recursor_cache.cc recursor_cache.hh dnsparser.cc \
+logger.cc statbag.cc arguments.cc lwres.cc pdns_recursor.cc lwres.hh \
+mtasker.hh syncres.hh recursor_cache.cc recursor_cache.hh dnsparser.cc \
dnswriter.cc dnswriter.hh dnsrecords.cc dnsrecords.hh rcpgenerator.cc rcpgenerator.hh \
base64.cc base64.hh zoneparser-tng.cc zoneparser-tng.hh rec_channel.cc rec_channel.hh \
rec_channel_rec.cc
exit(99);
}
-
if(arg()["config-name"]!="")
s_programname+="-"+arg()["config-name"];
else
localdir=dirname(strdup(socketname.c_str()));
-
const vector<string>&commands=arg().getCommands();
if(commands.empty()) {
#include <cstring>
#include <string>
#include <vector>
-#include "dnspacket.hh"
#include "dns.hh"
#include "qtype.hh"
-#include "tcpreceiver.hh"
#include "ahuexception.hh"
#include "statbag.hh"
#include "arguments.hh"
#include <unistd.h>
#include "mtasker.hh"
#include <utility>
-#include "dnspacket.hh"
#include "statbag.hh"
#include "arguments.hh"
#include "syncres.hh"
#include "dnsrecords.hh"
#include "zoneparser-tng.hh"
#include "rec_channel.hh"
+#include "logger.hh"
using namespace boost;
void makeControlChannelSocket()
{
- s_rcc.listen("pdns_recursor.controlsocket");
+ s_rcc.listen(::arg()["socket-dir"]+"/pdns_recursor.controlsocket");
}
void makeClientSocket()
}
#endif
-uint64_t counter, qcounter;
+uint64_t counter;
bool statsWanted;
void doStats(void)
{
- if(qcounter) {
- L<<Logger::Error<<"stats: "<<qcounter<<" questions, "<<RC.size()<<" cache entries, "<<SyncRes::s_negcache.size()<<" negative entries, "
+ if(g_stats.qcounter) {
+ L<<Logger::Error<<"stats: "<<g_stats.qcounter<<" questions, "<<RC.size()<<" cache entries, "<<SyncRes::s_negcache.size()<<" negative entries, "
<<(int)((RC.cacheHits*100.0)/(RC.cacheHits+RC.cacheMisses))<<"% cache hits"<<endl;
L<<Logger::Error<<"stats: throttle map: "<<SyncRes::s_throttle.size()<<", ns speeds: "
<<SyncRes::s_nsSpeeds.size()<<endl; // ", bytes: "<<RC.bytes()<<endl;
string remote;
string msg=s_rcc.recv(&remote);
RecursorControlParser rcp;
- s_rcc.send(rcp.getAnswer(msg), &remote);
+ RecursorControlParser::func_t* command;
+ string answer=rcp.getAnswer(msg, &command);
+ s_rcc.send(answer, &remote);
+ command();
}
if(FD_ISSET(d_clientsock,&readfds)) { // do we have a UDP question response?
if(dc->d_mdp.d_header.qr)
L<<Logger::Error<<"Ignoring answer on server socket!"<<endl;
else {
- ++qcounter;
+ ++g_stats.qcounter;
dc->setSocket(*i);
dc->d_tcp=false;
MT->makeThread(startDoResolve, (void*) dc, "udp");
if(dc->d_mdp.d_header.qr)
L<<Logger::Error<<"Ignoring answer on server socket!"<<endl;
else {
- ++qcounter;
+ ++g_stats.qcounter;
+ ++g_stats.tcpqcounter;
MT->makeThread(startDoResolve, dc, "tcp");
}
}
strcpy(local.sun_path, fname.c_str());
if(bind(d_fd, (sockaddr*)&local,sizeof(local))<0)
- throw AhuException("Unable to bind to controlsocket: "+string(strerror(errno)));
+ throw AhuException("Unable to bind to controlsocket '"+fname+"': "+string(strerror(errno)));
return d_fd;
}
-void RecursorControlChannel::connect(const string& fname)
+void RecursorControlChannel::connect(const string& path, const string& fname)
{
struct sockaddr_un local, remote;
if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
throw AhuException(string("Setsockopt failed: ")+strerror(errno));
- string localname="./blah";
+ string localname=path+"/lsockXXXXXX";
+ strcpy(local.sun_path, localname.c_str());
+
+ if(mkstemp(local.sun_path) < 0)
+ throw AhuException("Unable to generate local temporary file in directory '"+path+"': "+string(strerror(errno)));
local.sun_family=AF_UNIX;
- strcpy(local.sun_path,localname.c_str());
- int err=unlink(localname.c_str());
+ int err=unlink(local.sun_path);
if(err < 0 && errno!=ENOENT)
throw AhuException("Unable to remove local controlsocket: "+string(strerror(errno)));
memset(&remote,0,sizeof(remote));
remote.sun_family=AF_UNIX;
- strcpy(remote.sun_path,fname.c_str());
+ strcpy(remote.sun_path,(path+"/"+fname).c_str());
if(::connect(d_fd, (sockaddr*)&remote, sizeof(remote)) < 0) {
unlink(local.sun_path);
- throw AhuException("Unable to connect to remote '"+fname+"': "+string(strerror(errno)));
+ throw AhuException("Unable to connect to remote '"+path+fname+"': "+string(strerror(errno)));
}
}
{
public:
int listen(const std::string& filename);
- void connect(const std::string& filename);
+ void connect(const std::string& path, const std::string& filename);
uint64_t getStat(const std::string& name);
{
public:
RecursorControlParser();
- std::string getAnswer(const std::string& question);
+ static void nop(void){}
+ typedef void func_t(void);
+ std::string getAnswer(const std::string& question, func_t** func);
};
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include "logger.hh"
using namespace std;
using namespace boost;
gettimeofday(&now, 0);
optional<float> delay=g_stats.queryrate.get(now, 10);
if(delay)
- return 1000000/(*delay);
+ return (uint32_t)(1000000/(*delay));
else
return 0;
}
RecursorControlParser::RecursorControlParser()
{
- extern uint64_t qcounter;
- addGetStat("questions", &qcounter);
+ addGetStat("questions", &g_stats.qcounter);
+ addGetStat("tcp-questions", &g_stats.tcpqcounter);
addGetStat("cache-hits", &RC.cacheHits);
addGetStat("cache-misses", &RC.cacheMisses);
addGetStat("qa-latency", &g_stats.avgLatencyUsec);
- addGetStat("all-questions", &qcounter);
addGetStat("negcache-entries", boost::bind(&SyncRes::negcache_t::size, ref(SyncRes::s_negcache)));
addGetStat("throttle-entries", boost::bind(&SyncRes::throttle_t::size, ref(SyncRes::s_throttle)));
addGetStat("nsspeeds-entries", boost::bind(&SyncRes::nsspeeds_t::size, ref(SyncRes::s_nsSpeeds)));
addGetStat("query-rate", getQueryRate);
}
-string RecursorControlParser::getAnswer(const string& question)
+static void doExit()
{
+ L<<Logger::Error<<"Exiting on user request"<<endl;
+ exit(1);
+}
+
+string RecursorControlParser::getAnswer(const string& question, RecursorControlParser::func_t** command)
+{
+ *command=nop;
vector<string> words;
stringtok(words, question);
if(words.empty())
- return "invalid command";
+ return "invalid command\n";
string cmd=toLower(words[0]);
vector<string>::const_iterator begin=words.begin()+1, end=words.end();
if(cmd=="get")
return doGet(begin, end);
- if(cmd=="quit")
- exit(1);
+ if(cmd=="quit") {
+ *command=&doExit;
+ return "bye\n";
+ }
if(cmd=="dump-cache")
return doDumpCache(begin, end);
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2006 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
#include "rec_channel.hh"
#include <iostream>
#include "ahuexception.hh"
+#include "arguments.hh"
using namespace std;
+ArgvMap &arg()
+{
+ static ArgvMap arg;
+ return arg;
+}
+
+static void initArguments(int argc, char** argv)
+{
+ arg().set("config-dir","Location of configuration directory (pdns.conf)")=SYSCONFDIR;
+ arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR;
+ arg().setCmd("help","Provide this helpful message");
+
+ arg().laxParse(argc,argv);
+ if(arg().mustDo("help")) {
+ cerr<<"syntax:"<<endl<<endl;
+ cerr<<arg().helpstring(arg()["help"])<<endl;
+ exit(99);
+ }
+
+}
+
int main(int argc, char** argv)
try
{
+ initArguments(argc, argv);
+
RecursorControlChannel rccS;
- rccS.connect("pdns_recursor.controlsocket");
+ rccS.connect(arg()["socket-dir"], "pdns_recursor.controlsocket");
+ const vector<string>&commands=arg().getCommands();
string command;
- for(int i=1; i< argc; ++i) {
- if(i>1)
+ for(int i=0; i< commands.size(); ++i) {
+ if(i>0)
command+=" ";
- command+=argv[i];
+ command+=commands[i];
}
-
-
rccS.send(command);
-
string receive=rccS.recv();
-
cout<<receive;
}
catch(AhuException& ae)
};
extern MemRecursorCache RC;
-extern uint64_t qcounter;
extern MTasker<PacketID,string>* MT;
struct RecursorStats
PulseRate queryrate;
uint64_t answers0_1, answers1_10, answers10_100, answers100_1000, answersSlow;
uint64_t avgLatencyUsec;
+ uint64_t qcounter;
+ uint64_t tcpqcounter;
};
extern RecursorStats g_stats;
rrdtool create pdns_recursor.rrd -s 60 \
DS:questions:COUNTER:600:0:100000 \
+DS:tcp-questions:COUNTER:600:0:100000 \
DS:cache-entries:GAUGE:600:0:U \
DS:throttle-entries:GAUGE:600:0:U \
DS:concurrent-queries:GAUGE:600:0:50000 \
STACK:nxdomainanswers#ffa500:"nxdomain answers/s"\
STACK:servfailanswers#ff0000:"servfail answers/s"
+ rrdtool graph --start -$1 $WWWPREFIX/tcp-questions-$2.png -w $WSIZE -h $HSIZE -l 0\
+ -t "TCP question and answer counts per second" \
+ -v "packets" \
+ DEF:tcpquestions=pdns_recursor.rrd:tcp-questions:AVERAGE \
+ LINE2:tcpquestions#0000ff:"questions/s"\
+
rrdtool graph --start -$1 $WWWPREFIX/latencies-$2.png -w $WSIZE -h $HSIZE -l 0\
-t "Questions answered within latency" \
-v "questions" \
#!/bin/bash
TSTAMP=$(date +%s)
-cd ../..
-VARIABLES="questions cache-entries concurrent-queries\
+VARIABLES="questions tcp-questions cache-entries concurrent-queries\
nxdomain-answers noerror-answers\
servfail-answers tcp-outqueries\
outgoing-timeouts nsspeeds-entries negcache-entries all-outqueries throttled-out\
cache-hits cache-misses answers0-1 answers1-10 answers10-100 answers100-1000 answers-slow\
qa-latency throttle-entries"
-UVARIABLES=$(echo $VARIABLES | tr '[a-z]' '[A-Z]' | tr - _ )
+UVARIABLES=$(echo $VARIABLES | tr '[a-z]' '[A-Z]' | tr - _ )
-./rec_control GET $VARIABLES |
+rec_control GET $VARIABLES |
(
for a in $UVARIABLES
do