From b21dd877c5700b7a67c1c7c6dbb61c6d994855e9 Mon Sep 17 00:00:00 2001 From: Peter van Dijk Date: Mon, 10 Dec 2012 14:30:49 +0000 Subject: [PATCH] service pack 2 for the remotebackend, submitted by Aki Tuomi. Additional patch by Kees Monshouwer for ruby 1.8 compatibility. Closes #635. git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@2980 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- modules/remotebackend/httpconnector.cc | 9 ++- modules/remotebackend/pipeconnector.cc | 6 +- .../remotebackend/regression-tests/backend.rb | 2 +- .../regression-tests/http-backend.rb | 8 +-- .../regression-tests/pipe-backend.rb | 4 +- modules/remotebackend/remotebackend.cc | 24 +++++--- modules/remotebackend/remotebackend.hh | 2 + modules/remotebackend/unixconnector.cc | 14 +++-- pdns/docs/pdns.xml | 57 ++++++++++++++++--- regression-tests/start-test-stop | 3 + 10 files changed, 101 insertions(+), 28 deletions(-) diff --git a/modules/remotebackend/httpconnector.cc b/modules/remotebackend/httpconnector.cc index efb378d5a..4ab9deec3 100644 --- a/modules/remotebackend/httpconnector.cc +++ b/modules/remotebackend/httpconnector.cc @@ -22,6 +22,10 @@ HTTPConnector::HTTPConnector(std::map options) { } else { this->d_url_suffix = ""; } + this->timeout = 2; + if (options.find("timeout") != options.end()) { + this->timeout = boost::lexical_cast(options.find("timeout")->second)/1000; + } } HTTPConnector::~HTTPConnector() { @@ -83,7 +87,7 @@ void HTTPConnector::requestbuilder(const std::string &method, const rapidjson::V // finally add suffix ss << d_url_suffix; curl_easy_setopt(d_c, CURLOPT_URL, ss.str().c_str()); - + (*slist) = NULL; // set the correct type of request based on method if (method == "activateDomainKey" || method == "deactivateDomainKey") { @@ -154,7 +158,8 @@ int HTTPConnector::send_message(const rapidjson::Document &input) { d_c = curl_easy_init(); d_data = ""; curl_easy_setopt(d_c, CURLOPT_NOSIGNAL, 1); - curl_easy_setopt(d_c, CURLOPT_TIMEOUT, 2); + curl_easy_setopt(d_c, CURLOPT_TIMEOUT, this->timeout); + slist = NULL; // build request diff --git a/modules/remotebackend/pipeconnector.cc b/modules/remotebackend/pipeconnector.cc index b2cd5777e..2f256552d 100644 --- a/modules/remotebackend/pipeconnector.cc +++ b/modules/remotebackend/pipeconnector.cc @@ -20,7 +20,11 @@ void PipeConnector::launch() { if (coproc != NULL) return; rapidjson::Value val; rapidjson::Document init,res; - coproc = new CoProcess(this->command, 2000); + int timeout=2000; + if (options.find("timeout") != options.end()) { + timeout = boost::lexical_cast(options.find("timeout")->second); + } + coproc = new CoProcess(this->command, timeout); init.SetObject(); val = "initialize"; init.AddMember("method",val, init.GetAllocator()); diff --git a/modules/remotebackend/regression-tests/backend.rb b/modules/remotebackend/regression-tests/backend.rb index 8f8594180..444e40218 100755 --- a/modules/remotebackend/regression-tests/backend.rb +++ b/modules/remotebackend/regression-tests/backend.rb @@ -1,4 +1,4 @@ -#!/usr/bin/ruby1.9.1 +#!/usr/bin/ruby require 'json' require 'sqlite3' diff --git a/modules/remotebackend/regression-tests/http-backend.rb b/modules/remotebackend/regression-tests/http-backend.rb index 8a49989dc..6bf6be373 100755 --- a/modules/remotebackend/regression-tests/http-backend.rb +++ b/modules/remotebackend/regression-tests/http-backend.rb @@ -1,4 +1,4 @@ -#!/usr/bin/ruby1.9.1 +#!/usr/bin/ruby require "rubygems" #require "bundler/setup" require "webrick" @@ -6,10 +6,10 @@ require "../modules/remotebackend/regression-tests/dnsbackend" require "../modules/remotebackend/regression-tests/backend" server = WEBrick::HTTPServer.new( - Port: 62434, - BindAddress: "localhost", + :Port=>62434, + :BindAddress=>"localhost", # Logger: WEBrick::Log.new("remotebackend-server.log"), - AccessLog: [ [ File.open("remotebackend-access.log", "w"), WEBrick::AccessLog::COMBINED_LOG_FORMAT ] ] + :AccessLog=>[ [ File.open("remotebackend-access.log", "w"), WEBrick::AccessLog::COMBINED_LOG_FORMAT ] ] ) be = Handler.new("../modules/remotebackend/regression-tests/remote.sqlite3") diff --git a/modules/remotebackend/regression-tests/pipe-backend.rb b/modules/remotebackend/regression-tests/pipe-backend.rb index a71c519b9..271c78212 100755 --- a/modules/remotebackend/regression-tests/pipe-backend.rb +++ b/modules/remotebackend/regression-tests/pipe-backend.rb @@ -1,4 +1,4 @@ -#!/usr/bin/ruby1.9.1 +#!/usr/bin/ruby require 'json' require '../modules/remotebackend/regression-tests/backend' @@ -28,7 +28,7 @@ begin res, log = h.send(method) end puts ({:result => res, :log => log}).to_json - f.puts ({:result => res, :log => log}).to_json + f.puts({:result => res, :log => log}).to_json rescue JSON::ParserError puts ({:result => false, :log => "Cannot parse input #{line}"}).to_json next diff --git a/modules/remotebackend/remotebackend.cc b/modules/remotebackend/remotebackend.cc index 6d1b64407..622897bf6 100644 --- a/modules/remotebackend/remotebackend.cc +++ b/modules/remotebackend/remotebackend.cc @@ -136,11 +136,18 @@ void RemoteBackend::lookup(const QType &qtype, const std::string &qdomain, DNSPa JSON_ADD_MEMBER(parameters, "qtype", qtype.getName().c_str(), query.GetAllocator()); JSON_ADD_MEMBER(parameters, "qname", qdomain.c_str(), query.GetAllocator()); - if (pkt_p != NULL) { - JSON_ADD_MEMBER(parameters, "remote", pkt_p->getRemote().c_str(), query.GetAllocator()); - JSON_ADD_MEMBER(parameters, "local", pkt_p->getRemote().c_str(), query.GetAllocator()); - JSON_ADD_MEMBER(parameters, "real-remote", pkt_p->getRealRemote().toString().c_str(), query.GetAllocator()); + string localIP="0.0.0.0"; + string remoteIP="0.0.0.0"; + string realRemote="0.0.0.0/0"; + if (pkt_p) { + localIP=pkt_p->getLocal(); + realRemote = pkt_p->getRealRemote().toString(); + remoteIP = pkt_p->getRemote(); } + + JSON_ADD_MEMBER(parameters, "remote", remoteIP.c_str(), query.GetAllocator()); + JSON_ADD_MEMBER(parameters, "local", localIP.c_str(), query.GetAllocator()); + JSON_ADD_MEMBER(parameters, "real-remote", realRemote.c_str(), query.GetAllocator()); JSON_ADD_MEMBER(parameters, "zone-id", zoneId, query.GetAllocator()); query.AddMember("parameters", parameters, query.GetAllocator()); @@ -249,8 +256,12 @@ bool RemoteBackend::getDomainMetadata(const std::string& name, const std::string if (connector->recv(answer) == false) return true; - for(rapidjson::Value::ValueIterator iter = answer.Begin(); iter != answer.End(); iter++) { - meta.push_back(iter->GetString()); + if (answer.IsArray()) { + for(rapidjson::Value::ValueIterator iter = answer.Begin(); iter != answer.End(); iter++) { + meta.push_back(iter->GetString()); + } + } else if (answer.IsString()) { + meta.push_back(answer.GetString()); } return true; @@ -501,7 +512,6 @@ class RemoteBackendFactory : public BackendFactory { declare(suffix,"dnssec","Enable dnssec support","no"); declare(suffix,"connection-string","Connection string",""); - declare(suffix,"timeout","Timeout in milliseconds to wait for reply","2000"); } DNSBackend *make(const std::string &suffix="") diff --git a/modules/remotebackend/remotebackend.hh b/modules/remotebackend/remotebackend.hh index 98445380a..924b27876 100644 --- a/modules/remotebackend/remotebackend.hh +++ b/modules/remotebackend/remotebackend.hh @@ -47,6 +47,7 @@ class UnixsocketConnector: public Connector { int fd; std::string path; bool connected; + int timeout; }; #ifdef REMOTEBACKEND_HTTP @@ -64,6 +65,7 @@ class HTTPConnector: public Connector { std::string d_url_suffix; CURL *d_c; std::string d_data; + int timeout; void json2string(const rapidjson::Value &input, std::string &output); void requestbuilder(const std::string &method, const rapidjson::Value ¶meters, struct curl_slist **slist); void addUrlComponent(const rapidjson::Value ¶meters, const char *element, std::stringstream& ss); diff --git a/modules/remotebackend/unixconnector.cc b/modules/remotebackend/unixconnector.cc index 560f1da13..c7894de30 100644 --- a/modules/remotebackend/unixconnector.cc +++ b/modules/remotebackend/unixconnector.cc @@ -13,6 +13,10 @@ UnixsocketConnector::UnixsocketConnector(std::map optio L<timeout = 2000; + if (options.find("timeout") != options.end()) { + this->timeout = boost::lexical_cast(options.find("timeout")->second); + } this->path = options.find("path")->second; this->options = options; this->connected = false; @@ -41,13 +45,14 @@ int UnixsocketConnector::recv_message(rapidjson::Document &output) { std::string s_output; rapidjson::GenericReader , rapidjson::MemoryPoolAllocator<> > r; - time_t t0; + struct timeval t0,t; nread = 0; - t0 = time(NULL); + gettimeofday(&t0, NULL); + memcpy(&t,&t0,sizeof(t0)); s_output = ""; - - while(time(NULL) - t0 < 2) { // 2 second timeout + + while((t.tv_sec - t0.tv_sec)*1000 + (t.tv_usec - t0.tv_usec)/1000 < this->timeout) { std::string temp; temp.clear(); @@ -63,6 +68,7 @@ int UnixsocketConnector::recv_message(rapidjson::Document &output) { if (output.HasParseError() == false) return s_output.size(); } + gettimeofday(&t, NULL); } return -1; diff --git a/pdns/docs/pdns.xml b/pdns/docs/pdns.xml index 31a8b01ff..8a5e1e062 100644 --- a/pdns/docs/pdns.xml +++ b/pdns/docs/pdns.xml @@ -17961,7 +17961,8 @@ record building scripts on his Compiling - Install following libraries for dependencies: libjsoncpp, libcurl. To compile this backend, you need to configure --with-modules="remote pipe", for now. + Install following libraries for dependencies: libjsoncpp. To compile this backend, you need to configure --with-modules="remote pipe", for + now. If you want to use http connector, you need libcurl and use --enable-remotebackend-http. Usage @@ -17976,11 +17977,12 @@ remote-connection-string=<type>:<param>=<value>,<param>= You can pass as many parameters as you want. For unix and pipe backends, these are passed along to the remote end as initialization. See . + Initialize is not called for http backend. Unix backend - parameters: path + parameters: path, timeout (default 2000ms) @@ -17991,11 +17993,11 @@ remote-connection-string=unix:path=/path/to/socket Pipe backend - parameters: command + parameters: command,timeout (default 2000ms) -remote-connection-string=unix:command=/path/to/executable +remote-connection-string=unix:command=/path/to/executable,timeout=2000 @@ -18003,7 +18005,7 @@ remote-connection-string=unix:command=/path/to/executable HTTP backend - parameters: url, url-suffix + parameters: url, url-suffix, timeout (default 2000) HTTP backend tries to do RESTful requests to your server. See examples. @@ -18011,10 +18013,11 @@ remote-connection-string=unix:command=/path/to/executable URL should not end with /, and url-suffix is optional, but if you define it, it's up to you to write the ".php" or ".json". Lack of dot causes lack of dot in - URL. + URL. Timeout is divided by 1000 because libcurl only supports seconds, but this is + given in milliseconds for consistency with other backends. - + API Queries @@ -18039,6 +18042,46 @@ remote-connection-string=unix:command=/path/to/executable Methods + +Method: initialize + + + Mandatory: + Yes (except HTTP backend) + + + Parameters: + all parameters in connection string + + + Reply: + true on success / false on failure + + + Description + Called to initialize the backend. This is not called for HTTP backend. You should +do your initializations here. + + + Example JSON/RPC: + + +Query: + +{"method":"initialize", "parameters":{"command":"/path/to/something", "timeout":"2000", "something":"else"}} + + + +Response: + +{"result":true} + + + + + + + Method: lookup diff --git a/regression-tests/start-test-stop b/regression-tests/start-test-stop index d886b17ea..9b5e2351b 100755 --- a/regression-tests/start-test-stop +++ b/regression-tests/start-test-stop @@ -375,6 +375,9 @@ __EOF__ narrow=$(echo $context | cut -d- -f 4) testsdir=../modules/remotebackend/regression-tests/ + # cleanup unbound-host.conf to avoid failures + rm -f unbound-host.conf + case $remotetype in http) connstr="http:url=http://localhost:62434/dns" -- 2.40.0