]> granicus.if.org Git - pdns/commitdiff
aki tuomi ported the remotebackend to rapidjson and made use of libcurl optional...
authorBert Hubert <bert.hubert@netherlabs.nl>
Thu, 6 Dec 2012 20:14:04 +0000 (20:14 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Thu, 6 Dec 2012 20:14:04 +0000 (20:14 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@2973 d19b8d6e-7fed-0310-83ef-9ca221ded41b

configure.ac
modules/remotebackend/Makefile.am
modules/remotebackend/OBJECTLIBS
modules/remotebackend/httpconnector.cc
modules/remotebackend/pipeconnector.cc
modules/remotebackend/remotebackend.cc
modules/remotebackend/remotebackend.hh
modules/remotebackend/unixconnector.cc
pdns/Makefile.am

index 6e51bd509887d8f3f8fa0fa72cb4a2835713f366..93c58e70e3df605cf8f488af8a28387a5c0de357 100644 (file)
@@ -217,7 +217,6 @@ AC_ARG_ENABLE(cryptopp,
  [  --enable-cryptopp  Use Crypto++],enable_cryptopp=yes, enable_cryptopp=no)
 AC_MSG_RESULT($enable_cryptopp)
 AM_CONDITIONAL(CRYPTOPP,test x"$enable_cryptopp" = "xyes")
-
 if test "x$enable_botan110" = "xyes"
 then
        PKG_CHECK_MODULES(BOTAN110, botan-1.10, HAVE_BOTAN110=yes, AC_MSG_ERROR([Could not find botan 1.10]))
@@ -234,6 +233,19 @@ then
         AC_DEFINE(HAVE_BOTAN18,1,[If we have botan 1.8])
 fi
 
+AC_ARG_ENABLE(remotebackend_http, [  --enable-remotebackend-http       Enable HTTP connector for remotebackend],enable_remotebackend_http=yes, enable_remotebackend_http=no)
+AC_MSG_CHECKING(whether to enable http connector in remotebackend)
+AC_MSG_RESULT($enable_remotebackend_http)
+AM_CONDITIONAL(REMOTEBACKEND_HTTP,test x"$enable_remotebackend_http" = "xyes")
+if test "x$enable_remotebackend_http" = "xyes"
+then
+        PKG_CHECK_MODULES(LIBCURL, libcurl, HAVE_LIBCURL=yes, AC_MSG_ERROR([Could not find libcurl]))
+        AC_SUBST(LIBCURL_LIBS)
+        AC_SUBST(LIBCURL_CFLAGS)
+        AC_DEFINE(HAVE_LIBCURL,1,[If we have libcurl])
+       AC_DEFINE(REMOTEBACKEND_HTTP,1,[If we want HTTP connector])
+fi
+
 AC_MSG_CHECKING(whether we should build static binaries)
 
 AC_ARG_ENABLE(static-binaries, 
index 72d96c0f45ec35b7a38c8b7717e920440e942e4a..a47f8bbae6ff8b846e24813c1d633ba84eace8f4 100644 (file)
@@ -1,4 +1,4 @@
-AM_CPPFLAGS=@THREADFLAGS@ $(BOOST_CPPFLAGS)
+AM_CPPFLAGS=@THREADFLAGS@ $(BOOST_CPPFLAGS) $(LIBCURL_CFLAGS) -I../../pdns/ext/rapidjson/include
 #if !ALLSTATIC
 #install-exec-local:
 #       install .lib/libremotebackend.so.0.0.0 @libdir@
@@ -10,4 +10,4 @@ lib_LTLIBRARIES = libremotebackend.la
 libremotebackend_la_SOURCES=remotebackend.hh remotebackend.cc unixconnector.cc httpconnector.cc pipeconnector.cc 
 
 libremotebackend_la_LDFLAGS=-module -avoid-version
-libremotebackend_la_LIBS=-lboost_system -ljsoncpp -lcurl
+libremotebackend_la_LIBS=$(LIBCURL_LIBS)
index cb251b2025cc481b201ae52cb99f1b0feb18c70d..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1 +0,0 @@
--ljsoncpp -lcurl
index 6bfd0fe4e45326937c1ffc410a0a3bde1d4ba4c1..6e629407115c492c6780179c98b00cdb13aeeed7 100644 (file)
@@ -10,6 +10,7 @@
 #define UNIX_PATH_MAX 108
 #endif
 
+#ifdef REMOTEBACKEND_HTTP
 HTTPConnector::HTTPConnector(std::map<std::string,std::string> options) {
     this->d_url = options.find("url")->second;
     if (options.find("url-suffix") != options.end()) {
@@ -32,25 +33,33 @@ size_t httpconnector_write_data(void *buffer, size_t size, size_t nmemb, void *u
 }
 
 // converts json value into string
-void HTTPConnector::json2string(const Json::Value &input, std::string &output) {
-   if (input.isString()) output = input.asString();
-   else if (input.isNull()) output = "";
-   else if (input.isUInt()) output = lexical_cast<std::string>(input.asUInt());
-   else if (input.isInt()) output = lexical_cast<std::string>(input.asInt());
+void HTTPConnector::json2string(const rapidjson::Value &input, std::string &output) {
+   if (input.IsString()) output = input.GetString();
+   else if (input.IsNull()) output = "";
+   else if (input.IsUint()) output = lexical_cast<std::string>(input.GetUint());
+   else if (input.IsInt()) output = lexical_cast<std::string>(input.GetInt());
    else output = "inconvertible value";
 }
 
+void HTTPConnector::addUrlComponent(const rapidjson::Value &parameters, const char *element, std::stringstream& ss) {
+    rapidjson::Value nullval;
+    std::string sparam;
+    nullval.SetNull();
+    const rapidjson::Value& param = (parameters.HasMember(element)?parameters[element]:nullval);
+    if (param.IsNull() == false) {
+       json2string(param, sparam);
+       ss << "/" << sparam;
+    }
+}
+
+
 // builds our request
-void HTTPConnector::requestbuilder(const std::string &method, const Json::Value &parameters, struct curl_slist **slist)
+void HTTPConnector::requestbuilder(const std::string &method, const rapidjson::Value &parameters, struct curl_slist **slist)
 {
     std::stringstream ss;
-    Json::Value param;
     std::string sparam;
     char *tmpstr;
 
-    // check for certain elements
-    std::vector<std::string> members = parameters.getMemberNames();
-
     // special names are qname, name, zonename, kind, others go to headers
 
     ss << d_url;
@@ -59,33 +68,13 @@ void HTTPConnector::requestbuilder(const std::string &method, const Json::Value
 
     // add the url components, if found, in following order.
     // id must be first due to the fact that the qname/name can be empty
-    if ((param = parameters.get("id", Json::Value())).isNull() == false) {
-       json2string(param, sparam);
-       ss << "/" << sparam;
-    }
-    if ((param = parameters.get("zonename", Json::Value())).isNull() == false) {
-       json2string(param, sparam);
-       ss << "/" << sparam;
-    }
 
-    if ((param = parameters.get("qname", Json::Value())).isNull() == false) {
-       json2string(param, sparam);
-       ss << "/" << sparam;
-    }
-    
-    if ((param = parameters.get("name", Json::Value())).isNull() == false) {
-       json2string(param, sparam);
-       ss << "/" << sparam;
-    }
-
-    if ((param = parameters.get("kind", Json::Value())).isNull() == false) {
-       json2string(param, sparam);
-       ss << "/" << sparam;
-    }
-    if ((param = parameters.get("qtype", Json::Value())).isNull() == false) {
-       json2string(param, sparam);
-       ss << "/" << sparam;
-    }
+    addUrlComponent(parameters, "id", ss);
+    addUrlComponent(parameters, "zonename", ss);
+    addUrlComponent(parameters, "qname", ss);
+    addUrlComponent(parameters, "name", ss);
+    addUrlComponent(parameters, "kind", ss);
+    addUrlComponent(parameters, "qtype", ss);
 
     // finally add suffix
     ss << d_url_suffix;
@@ -100,9 +89,9 @@ void HTTPConnector::requestbuilder(const std::string &method, const Json::Value
     } else if (method == "addDomainKey") {
         // create post with keydata
         std::stringstream ss2;
-        param = parameters["key"]; 
-        ss2 << "flags=" << param["flags"].asUInt() << "&active=" << (param["active"].asBool() ? 1 : 0) << "&content=";
-        tmpstr = curl_easy_escape(d_c, param["content"].asCString(), 0);
+        const rapidjson::Value& param = parameters["key"]; 
+        ss2 << "flags=" << param["flags"].GetUint() << "&active=" << (param["active"].GetBool() ? 1 : 0) << "&content=";
+        tmpstr = curl_easy_escape(d_c, param["content"].GetString(), 0);
         ss2 << tmpstr;
         sparam = ss2.str();
         curl_easy_setopt(d_c, CURLOPT_POSTFIELDSIZE, sparam.size());
@@ -112,12 +101,12 @@ void HTTPConnector::requestbuilder(const std::string &method, const Json::Value
         int n=0;
         // copy all metadata values into post
         std::stringstream ss2;
-        param = parameters["value"];
+        const rapidjson::Value& param = parameters["value"];
         curl_easy_setopt(d_c, CURLOPT_POST, 1);
         // this one has values too
-        if (param.isArray()) {
-           for(Json::ValueIterator i = param.begin(); i != param.end(); i++) {
-              ss2 << "value" << (++n) << "=" << (*i).asString() << "&";
+        if (param.IsArray()) {
+           for(rapidjson::Value::ConstValueIterator i = param.Begin(); i != param.End(); i++) {
+              ss2 << "value" << (++n) << "=" << i->GetString() << "&";
            }
         }
         sparam = ss2.str();
@@ -132,15 +121,16 @@ void HTTPConnector::requestbuilder(const std::string &method, const Json::Value
     }
 
     // put everything else into headers
-    BOOST_FOREACH(std::string member, members) {
+    for (rapidjson::Value::ConstMemberIterator iter = parameters.MemberBegin(); iter != parameters.MemberEnd(); ++iter) {
       char header[1024];
+      const char *member = iter->name.GetString();
       // these are not put into headers for obvious reasons
-      if (member == "zonename" || member == "qname" ||
-          member == "name" || member == "kind" ||
-          member == "qtype" || member == "id" ||
-          member == "key" ) continue;
+      if (!strncmp(member,"zonename",8) || !strncmp(member,"qname",5) ||
+          !strncmp(member,"name",4) || !strncmp(member,"kind",4) ||
+          !strncmp(member,"qtype",5) || !strncmp(member,"id",2) ||
+          !strncmp(member,"key",3)) continue;
       json2string(parameters[member], sparam);
-      snprintf(header, sizeof header, "X-RemoteBackend-%s: %s", member.c_str(), sparam.c_str());
+      snprintf(header, sizeof header, "X-RemoteBackend-%s: %s", iter->name.GetString(), sparam.c_str());
       (*slist) = curl_slist_append((*slist), header);
     };
 
@@ -148,7 +138,7 @@ void HTTPConnector::requestbuilder(const std::string &method, const Json::Value
     curl_easy_setopt(d_c, CURLOPT_HTTPHEADER, *slist); 
 }
 
-int HTTPConnector::send_message(const Json::Value &input) {
+int HTTPConnector::send_message(const rapidjson::Document &input) {
     int rv;
     long rcode;
     struct curl_slist *slist;
@@ -164,7 +154,7 @@ int HTTPConnector::send_message(const Json::Value &input) {
     slist = NULL;
 
     // build request
-    requestbuilder(input["method"].asString(), input["parameters"], &slist);
+    requestbuilder(input["method"].GetString(), input["parameters"], &slist);
 
     // setup write function helper
     curl_easy_setopt(d_c, CURLOPT_WRITEFUNCTION, &(httpconnector_write_data));
@@ -193,14 +183,17 @@ int HTTPConnector::send_message(const Json::Value &input) {
     return rv;
 }
 
-int HTTPConnector::recv_message(Json::Value &output) {
-    Json::Reader r;
+int HTTPConnector::recv_message(rapidjson::Document &output) {
+    rapidjson::StringStream ss(d_data.c_str());
     int rv = -1;
+    output.ParseStream<0>(ss);
 
     // offer whatever we read in send_message
-    if (r.parse(d_data, output) == true)
+    if (output.HasParseError() == false)
        rv = d_data.size();
 
     d_data = ""; // cleanup here
     return rv;
 }
+
+#endif
index 133e36e42503b35dcc1d6bee4e66c7cac41661e2..b2cd5777eecb745cad471959d5e162122e90e1b1 100644 (file)
@@ -18,14 +18,19 @@ PipeConnector::~PipeConnector(){
 
 void PipeConnector::launch() {
   if (coproc != NULL) return;
+  rapidjson::Value val;
+  rapidjson::Document init,res;
+  coproc = new CoProcess(this->command, 2000);
+  init.SetObject();
+  val = "initialize";
+  init.AddMember("method",val, init.GetAllocator());
+  val.SetObject();
+  init.AddMember("parameters", val, init.GetAllocator());
 
-  Json::Value init,res;
-  coproc = new CoProcess(this->command, 2);
-  init["method"] = "initialize";
-  init["parameters"] = Json::Value();
-
-  for(std::map<std::string,std::string>::iterator i = options.begin(); i != options.end(); i++)
-    init["parameters"][i->first] = i->second;
+  for(std::map<std::string,std::string>::iterator i = options.begin(); i != options.end(); i++) {
+    val = i->second.c_str();
+    init["parameters"].AddMember(i->first.c_str(), val, init.GetAllocator());
+  }
 
   this->send(init);
   if (this->recv(res)==false) {
@@ -33,11 +38,11 @@ void PipeConnector::launch() {
   }
 }
 
-int PipeConnector::send_message(const Json::Value &input)
+int PipeConnector::send_message(const rapidjson::Document &input)
 {
    std::string data;
-   Json::FastWriter writer;
-   data = writer.write(input);
+
+   data = makeStringFromDocument(input);
 
    launch();
    try {
@@ -51,22 +56,24 @@ int PipeConnector::send_message(const Json::Value &input)
    } 
 }
 
-int PipeConnector::recv_message(Json::Value &output) 
+int PipeConnector::recv_message(rapidjson::Document &output) 
 {
-   Json::Reader r;
+   rapidjson::GenericReader<rapidjson::UTF8<> , rapidjson::MemoryPoolAllocator<> > r;
    std::string tmp;
-   std::string data;
+   std::string s_output;
+   int nread=0;
+
    launch();
    try {
-      std::string line;
       while(1) {
         coproc->receive(tmp);
-        data.append(tmp);
-        if (r.parse(data,output) == true) 
-          return data.size();
+        s_output.append(tmp);
+        rapidjson::StringStream ss(s_output.c_str());
+        output.ParseStream<0>(ss); 
+        if (output.HasParseError() == false)
+          return s_output.size();
       }
-   }
-   catch(AhuException &ae) {
+   } catch(AhuException &ae) {
       L<<Logger::Warning<<"[pipeconnector] "<<" unable to receive data from coprocess. "<<ae.reason<<endl;
       delete coproc;
       coproc = NULL;
index 1f4adebf91e6a1eca039c73000a86b70297fe961..6d1b644079e1946471bfb47bd9f38f246996710b 100644 (file)
@@ -8,7 +8,7 @@ static const char *kBackendId = "[RemoteBackend]";
  * we need to do some treatment to the value before
  * sending it downwards.
  */
-bool Connector::send(Json::Value &value) {
+bool Connector::send(rapidjson::Document &value) {
     return send_message(value);
 }
 
@@ -18,21 +18,29 @@ bool Connector::send(Json::Value &value) {
  * that the receiving happened ok, and extract
  * result. Logging is performed here, too. 
  */
-bool Connector::recv(Json::Value &value) {
-    Json::Value input;
+bool Connector::recv(rapidjson::Value &value) {
+    rapidjson::Document input;
     if (recv_message(input)>0) {
        bool rv = true;
        // check for error
-       value = input.get("result",Json::Value());
-       if (value.isNull() || (value.isBool() && value.asBool() == false)) {
+       if (input.HasMember("result")) {
+          value = input["result"];
+       } else {
+          value = false;
+          return false;
+       }
+       if (!value.IsObject() && (value.IsBool() && value.GetBool() == false)) {
            rv = false;
-          value = Json::Value(false);
-        } 
-        Json::Value messages = input.get("log", Json::Value());
-        if (messages.isArray()) {
-           // log em all
-           for(Json::ValueIterator iter = messages.begin(); iter != messages.end(); iter++) {
-              L<<Logger::Info<<"[remotebackend]:"<< (*iter).asString()<<std::endl;
+          value = false;
+        }
+        if (input.HasMember("log")) {
+           const rapidjson::Value& messages = input["log"];
+           if (messages.IsArray()) {
+              // log em all
+              for (rapidjson::Value::ConstValueIterator iter = messages.Begin(); iter != messages.End(); ++iter)
+                 L<<Logger::Info<<"[remotebackend]:"<< iter->GetString() <<std::endl;
+           } else if (messages.IsString()) { // could be just a string, too
+               L<<Logger::Info<<"[remotebackend]:"<< messages.GetString() <<std::endl;
            }
         }
         return rv;
@@ -96,10 +104,12 @@ int RemoteBackend::build(const std::string &connstr) {
       }
 
       // connectors know what they are doing
-      if (type == "http") {
-        this->connector = new HTTPConnector(options);
-      } else if (type == "unix") {
+      if (type == "unix") {
         this->connector = new UnixsocketConnector(options);
+#ifdef REMOTEBACKEND_HTTP
+      } else if (type == "http") {
+        this->connector = new HTTPConnector(options);
+#endif
       } else if (type == "pipe") {
         this->connector = new PipeConnector(options);
       } else {
@@ -114,103 +124,123 @@ int RemoteBackend::build(const std::string &connstr) {
  * data is mainly left alone, some defaults are assumed. 
  */
 void RemoteBackend::lookup(const QType &qtype, const std::string &qdomain, DNSPacket *pkt_p, int zoneId) {
-   Json::Value query,args;
+   rapidjson::Document query;
+   rapidjson::Value parameters;
 
    if (d_index != -1) 
       throw AhuException("Attempt to lookup while one running");
 
-   args["qtype"] = qtype.getName();
-   args["qname"] = qdomain;
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "lookup", query.GetAllocator())
+   parameters.SetObject();
+   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) {
-     args["remote"] = pkt_p->getRemote();
-     args["local"] = pkt_p->getLocal();
-     args["real-remote"] = pkt_p->getRealRemote().toString();
+     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());
    }
-   args["zone-id"] = zoneId;
-   query["method"] = "lookup";
-   query["parameters"] = args;
+   JSON_ADD_MEMBER(parameters, "zone-id", zoneId, query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
 
    if (connector->send(query) == false || connector->recv(d_result) == false)  return;
 
-   // OK. we have result values in result
-   if (d_result.isArray() == false) return;
+   // OK. we have result parametersues in result
+   if (d_result.IsArray() == false) return;
    d_index = 0;
 }
 
 bool RemoteBackend::get(DNSResourceRecord &rr) {
    if (d_index == -1) return false;
-   
-   Json::Value empty("");
-   Json::Value emptyint(-1);
+   rapidjson::Value value;
 
-   rr.qtype = d_result[d_index].get("qtype",empty).asString();
-   rr.qname = d_result[d_index].get("qname",empty).asString();
+   value = "";
+   rr.qtype = JSON_GET(d_result[d_index], "qtype", value).GetString();
+   rr.qname = JSON_GET(d_result[d_index], "qname", value).GetString();
    rr.qclass = QClass::IN;
-   rr.content = d_result[d_index].get("content",empty).asString();
-   rr.ttl = d_result[d_index].get("ttl",emptyint).asInt();
-   rr.domain_id = d_result[d_index].get("domain_id",emptyint).asInt();
-   rr.priority = d_result[d_index].get("priority",emptyint).asInt();
+   rr.content = JSON_GET(d_result[d_index], "content",value).GetString();
+   value = -1;
+   rr.ttl = JSON_GET(d_result[d_index], "ttl",value).GetInt();
+   rr.domain_id = JSON_GET(d_result[d_index],"domain_id",value).GetInt();
+   rr.priority = JSON_GET(d_result[d_index],"priority",value).GetInt();
+   value = 1;
    if (d_dnssec) 
-     rr.auth = d_result[d_index].get("auth", Json::Value(1)).asInt();
+     rr.auth = JSON_GET(d_result[d_index],"auth", value).GetInt();
    else
      rr.auth = 1;
-   rr.scopeMask = d_result[d_index].get("scopeMask",Json::Value(0)).asInt();
+   value = 0;
+   rr.scopeMask = JSON_GET(d_result[d_index],"scopeMask", value).GetInt();
 
    d_index++;
    
    // id index is out of bounds, we know the results end here. 
-   if (d_index == static_cast<int>(d_result.size())) {
-     d_result = Json::Value();
+   if (d_index == static_cast<int>(d_result.Size())) {
+     d_result.SetNull();
      d_index = -1;
    }
    return true;
 }
 
 bool RemoteBackend::list(const std::string &target, int domain_id) {
-   Json::Value query;
+   rapidjson::Document query;
+   rapidjson::Value parameters;
 
    if (d_index != -1) 
       throw AhuException("Attempt to lookup while one running");
 
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "list", query.GetAllocator());
    query["method"] = "list";
-   query["parameters"] = Json::Value();
-   query["parameters"]["zonename"] = target;
-   query["parameters"]["domain-id"] = domain_id;
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "zonename", target.c_str(), query.GetAllocator()); 
+   JSON_ADD_MEMBER(parameters, "domain-id", domain_id, query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
 
    if (connector->send(query) == false || connector->recv(d_result) == false) 
      return false;
-   d_index = 0;
+   if (d_result.IsArray() == false) 
+     return false;
 
+   d_index = 0;
    return true;
 }
 
 bool RemoteBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after) {
-   Json::Value query,answer;
+   rapidjson::Document query;
+   rapidjson::Value answer,parameters;
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
 
-   query["method"] = "getBeforeAndAfterNamesAbsolute";
-   query["parameters"] = Json::Value();
-   query["parameters"]["id"] = id;
-   query["parameters"]["qname"] = qname;
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "getBeforeAndAfterNamesAbsolute", query.GetAllocator());
+   
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator());
+   JSON_ADD_MEMBER(parameters, "qname", qname.c_str(), query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
 
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
-   
-   unhashed = answer["unhashed"].asString();
-   before = answer["before"].asString();
-   after = answer["after"].asString();
+
+   unhashed = answer["unhashed"].GetString();
+   before = answer["before"].GetString();
+   after = answer["after"].GetString();
   
    return true;
 }
 
 bool RemoteBackend::getDomainMetadata(const std::string& name, const std::string& kind, std::vector<std::string>& meta) {
-   Json::Value query,answer;
+   rapidjson::Document query;
+   rapidjson::Value answer,parameters;
+
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "getDomainMetadata", query.GetAllocator());
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "name", name.c_str(), query.GetAllocator());
+   JSON_ADD_MEMBER(parameters, "kind", kind.c_str(), query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
 
-   query["method"] = "getDomainMetadata";
-   query["parameters"] = Json::Value();
-   query["parameters"]["name"] = name;
-   query["parameters"]["kind"] = kind;
    if (connector->send(query) == false)
      return false;
    meta.clear();
@@ -219,52 +249,61 @@ bool RemoteBackend::getDomainMetadata(const std::string& name, const std::string
    if (connector->recv(answer) == false)
      return true;
 
-   for(Json::ValueIterator iter = answer.begin(); iter != answer.end(); iter++) {
-          meta.push_back((*iter).asString());
+   for(rapidjson::Value::ValueIterator iter = answer.Begin(); iter != answer.End(); iter++) {
+          meta.push_back(iter->GetString());
    }
 
    return true;
 }
 
 bool RemoteBackend::setDomainMetadata(const string& name, const std::string& kind, const std::vector<std::string>& meta) {
-   Json::Value query,answer;
-   query["method"] = "setDomainMetadata";
-   query["parameters"] = Json::Value();
-   query["parameters"]["name"] = name;
-   query["parameters"]["kind"] = kind;
-   query["parameters"]["value"] = Json::Value();
+   rapidjson::Document query;
+   rapidjson::Value answer,parameters,val;
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "setDomainMetadata", query.GetAllocator());
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "name", name.c_str(), query.GetAllocator());
+   JSON_ADD_MEMBER(parameters, "kind", kind.c_str(), query.GetAllocator());
+   val.SetArray();
    BOOST_FOREACH(std::string value, meta) {
-     query["parameters"]["value"].append(value);
+     val.PushBack(value.c_str(), query.GetAllocator());
    }
+   parameters.AddMember("value", val, query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
 
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
 
-   return answer.asBool();
+   if (answer.IsBool())
+      return answer.GetBool();
+   return false;
 }
 
 
 bool RemoteBackend::getDomainKeys(const std::string& name, unsigned int kind, std::vector<DNSBackend::KeyData>& keys) {
-   Json::Value query,answer;
+   rapidjson::Document query;
+   rapidjson::Value answer,parameters;
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
 
-   query["method"] = "getDomainKeys";
-   query["parameters"] = Json::Value();
-   query["parameters"]["name"] = name;
-   query["parameters"]["kind"] = kind;
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "getDomainKeys", query.GetAllocator());
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "name", name.c_str(), query.GetAllocator());
+   JSON_ADD_MEMBER(parameters, "kind", kind, query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
 
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
 
    keys.clear();
 
-   for(Json::ValueIterator iter = answer.begin(); iter != answer.end(); iter++) {
+   for(rapidjson::Value::ValueIterator iter = answer.Begin(); iter != answer.End(); iter++) {
       DNSBackend::KeyData key;
-      key.id = (*iter)["id"].asUInt();
-      key.flags = (*iter)["flags"].asUInt();
-      key.active = (*iter)["active"].asBool();
-      key.content = (*iter)["content"].asString();
+      key.id = (*iter)["id"].GetUint();
+      key.flags = (*iter)["flags"].GetUint();
+      key.active = (*iter)["active"].GetBool();
+      key.content = (*iter)["content"].GetString();
       keys.push_back(key);
    }
 
@@ -272,66 +311,85 @@ bool RemoteBackend::getDomainKeys(const std::string& name, unsigned int kind, st
 }
 
 bool RemoteBackend::removeDomainKey(const string& name, unsigned int id) { 
-   Json::Value query,answer;
+   rapidjson::Document query;
+   rapidjson::Value answer,parameters;
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
-   query["method"] = "remoteDomainKey";
-   query["parameters"] = Json::Value();
-   query["parameters"]["name"] = name;
-   query["parameters"]["id"] = id;
+
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "getDomainKeys", query.GetAllocator());
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "name", name.c_str(), query.GetAllocator());
+   JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
 
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
 
-   return answer.asBool();
+   return answer.GetBool();
 }
 
 int RemoteBackend::addDomainKey(const string& name, const KeyData& key) {
-   Json::Value query,answer;
+   rapidjson::Document query;
+   rapidjson::Value answer,parameters,jkey;
 
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
-   query["method"] = "addDomainKey";
-   query["parameters"] = Json::Value();
-   query["parameters"]["name"] = name;
-   query["parameters"]["key"] = Json::Value();
-   query["parameters"]["key"]["flags"] = key.flags;
-   query["parameters"]["key"]["active"] = key.active;
-   query["parameters"]["key"]["content"] = key.content;
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "addDomainKey", query.GetAllocator());
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "name", name.c_str(), query.GetAllocator());
+   jkey.SetObject();
+   JSON_ADD_MEMBER(jkey, "flags", key.flags, query.GetAllocator());
+   JSON_ADD_MEMBER(jkey, "active", key.active, query.GetAllocator());
+   JSON_ADD_MEMBER(jkey, "content", key.content.c_str(), query.GetAllocator());
+   parameters.AddMember("key", jkey, query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
 
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
 
-   return answer.asInt();
+   return answer.GetInt();
 }
 
 bool RemoteBackend::activateDomainKey(const string& name, unsigned int id) {
-   Json::Value query,answer;
+   rapidjson::Document query;
+   rapidjson::Value answer, parameters;
+
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
-   query["method"] = "activateDomainKey";
-   query["parameters"] = Json::Value();
-   query["parameters"]["name"] = name;
-   query["parameters"]["id"] = id;
+
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "activateDomainKey", query.GetAllocator());
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "name", name.c_str(), query.GetAllocator());
+   JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
 
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
 
-   return answer.asBool();
+   return answer.GetBool();
 }
 
 bool RemoteBackend::deactivateDomainKey(const string& name, unsigned int id) {
-   Json::Value query,answer;
+   rapidjson::Document query;
+   rapidjson::Value answer, parameters;
+
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
-   query["method"] = "deactivateDomainKey";
-   query["parameters"] = Json::Value();
-   query["parameters"]["name"] = name;
-   query["parameters"]["id"] = id;
+
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "deactivateDomainKey", query.GetAllocator());
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "name", name.c_str(), query.GetAllocator());
+   JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
+
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
 
-   return answer.asBool();
+   return answer.GetBool();
 }
 
 bool RemoteBackend::doesDNSSEC() {
@@ -339,50 +397,64 @@ bool RemoteBackend::doesDNSSEC() {
 }
 
 bool RemoteBackend::getTSIGKey(const std::string& name, std::string* algorithm, std::string* content) {
-   Json::Value query,answer;
-   query["method"] = "getTSIGKey";
-   query["parameters"] = Json::Value();
-   query["parameters"]["name"] = name;
+   rapidjson::Document query;
+   rapidjson::Value answer, parameters;
+
+   // no point doing dnssec if it's not supported
+   if (d_dnssec == false) return false;
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "getTSIGKey", query.GetAllocator());
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "name", name.c_str(), query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
 
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
 
    if (algorithm != NULL)
-     algorithm->assign(answer["algorithm"].asString());
+     algorithm->assign(answer["algorithm"].GetString());
    if (content != NULL)
-     content->assign(answer["content"].asString());
+     content->assign(answer["content"].GetString());
    
    return true;
 }
 
 bool RemoteBackend::getDomainInfo(const string &domain, DomainInfo &di) {
-   Json::Value query,answer;
+   rapidjson::Document query;
+   rapidjson::Value answer, parameters;
+   rapidjson::Value value;
    std::string kind;
-   query["method"] = "getDomainInfo";
-   query["parameters"] = Json::Value();
-   query["parameters"]["name"] = domain;
+
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "getDomainInfo", query.GetAllocator());
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "name", domain.c_str(), query.GetAllocator());
+   query.AddMember("parameters", parameters, query.GetAllocator());
 
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
 
    // make sure we got zone & kind
-   if (!answer.isMember("zone")) {
+   if (!answer.HasMember("zone")) {
       L<<Logger::Error<<kBackendId<<"Missing zone in getDomainInfo return value"<<endl;
       throw new AhuException();
    }
+   value = -1;
    // parse return value. we need at least zone,serial,kind
-   di.id = answer.get("id", Json::Value(-1)).asInt();
-   di.zone = answer["zone"].asString();
-   if (answer.isMember("masters") && answer["masters"].isArray()) {
-     Json::Value value = answer["masters"];
-     for(Json::Value::iterator i = value.begin(); i != value.end(); i++) {
-        di.masters.push_back((*i).asString());
+   di.id = JSON_GET(answer,"id",value).GetInt();
+   di.zone = answer["zone"].GetString();
+   if (answer.HasMember("masters") && answer["masters"].IsArray()) {
+     rapidjson::Value& value = answer["masters"];
+     for(rapidjson::Value::ValueIterator i = value.Begin(); i != value.End(); i++) {
+        di.masters.push_back(i->GetString());
      }
    }
-   di.notified_serial = answer.get("notified_serial", Json::Value(-1)).asInt();
-   di.serial = answer.get("serial", Json::Value(0)).asInt();
-   di.last_check = answer.get("last_check", Json::Value(0)).asInt();
-   kind = answer.get("kind", Json::Value("native")).asString();
+   di.notified_serial = JSON_GET(answer, "notified_serial", value).GetInt();
+   value = 0;
+   di.serial = JSON_GET(answer,"serial", value).GetInt();
+   di.last_check = JSON_GET(answer,"last_check", value).GetInt();
+   value = "native";
+   kind = JSON_GET(answer, "kind", value).GetString();
    if (kind == "master") {
       di.kind = DomainInfo::Master;
    } else if (kind == "slave") {
@@ -395,12 +467,15 @@ bool RemoteBackend::getDomainInfo(const string &domain, DomainInfo &di) {
 }
 
 void RemoteBackend::setNotified(uint32_t id, uint32_t serial) {
-   Json::Value query,answer;
-   std::string kind;
-   query["method"] = "setNotified";
-   query["parameters"] = Json::Value();
-   query["parameters"]["id"] = id;
-   query["parameters"]["serial"] = serial;
+   rapidjson::Document query;
+   rapidjson::Value answer, parameters;
+  
+   query.SetObject();
+   JSON_ADD_MEMBER(query, "method", "setNotified", query.GetAllocator());
+   parameters.SetObject();
+   JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator());
+   JSON_ADD_MEMBER(parameters, "serial", id, query.GetAllocator());
+
    if (connector->send(query) == false || connector->recv(answer) == false) {
       L<<Logger::Error<<kBackendId<<"Failed to execute RPC for RemoteBackend::setNotified("<<id<<","<<serial<<")"<<endl;
    }
@@ -426,6 +501,7 @@ 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="")
@@ -439,7 +515,9 @@ class RemoteLoader
    public:
       RemoteLoader()
       {
+#ifdef REMOTEBACKEND_HTTP
          curl_global_init(CURL_GLOBAL_ALL);
+#endif
          BackendMakers().report(new RemoteBackendFactory);
          L<<Logger::Notice<<kBackendId<<" This is the remotebackend version "VERSION" ("__DATE__", "__TIME__") reporting"<<endl;
       }
index 78e3f32b178feca3b4a35aa0eeadab82a9e494dc..a5b8b02ead7baa50814e2432e5e805ebc63466c3 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef REMOTEBACKEND_REMOTEBACKEND_HH
 
 #include <string>
+#include <sstream>
 #include "pdns/namespaces.hh"
 #include <pdns/dns.hh>
 #include <pdns/dnsbackend.hh>
 #include <pdns/logger.hh>
 #include <pdns/arguments.hh>
 #include <boost/lexical_cast.hpp>
-#include <jsoncpp/json/json.h>
+#include <rapidjson/rapidjson.h>
+#include <rapidjson/document.h>
 #include "../pipebackend/coprocess.hh"
 #include <curl/curl.h>
+#include "pdns/json.hh"
+
+#define JSON_GET(obj,val,def) (obj.HasMember(val)?obj["" val ""]:def)
+#define JSON_ADD_MEMBER(obj, name, val, alloc) { rapidjson::Value __xval; __xval = val; obj.AddMember(name, __xval, alloc); }
 
 class Connector {
    public:
     virtual ~Connector() {};
-    bool send(Json::Value &value);
-    bool recv(Json::Value &value);
-    virtual int send_message(const Json::Value &input) = 0;
-    virtual int recv_message(Json::Value &output) = 0;
+    bool send(rapidjson::Document &value);
+    bool recv(rapidjson::Value &value);
+    virtual int send_message(const rapidjson::Document &input) = 0;
+    virtual int recv_message(rapidjson::Document &output) = 0;
 };
 
 // fwd declarations
@@ -28,8 +34,8 @@ class UnixsocketConnector: public Connector {
   public:
     UnixsocketConnector(std::map<std::string,std::string> options);
     virtual ~UnixsocketConnector();
-    virtual int send_message(const Json::Value &input);
-    virtual int recv_message(Json::Value &output);
+    virtual int send_message(const rapidjson::Document &input);
+    virtual int recv_message(rapidjson::Document &output);
   private:
     ssize_t read(std::string &data);
     ssize_t write(const std::string &data);
@@ -40,24 +46,26 @@ class UnixsocketConnector: public Connector {
     bool connected;
 };
 
+#ifdef REMOTEBACKEND_HTTP
 class HTTPConnector: public Connector {
   public:
 
   HTTPConnector(std::map<std::string,std::string> options);
   ~HTTPConnector();
 
-  virtual int send_message(const Json::Value &input);
-  virtual int recv_message(Json::Value &output);
-  friend size_t ::httpconnector_write_data(void*, size_t, size_t, void*);
-
+  virtual int send_message(const rapidjson::Document &input);
+  virtual int recv_message(rapidjson::Document &output);
+  friend size_t ::httpconnector_write_data(void*, size_t, size_t, void *value);
   private:
     std::string d_url;
     std::string d_url_suffix;
     CURL *d_c;
     std::string d_data;
-    void json2string(const Json::Value &input, std::string &output);
-    void requestbuilder(const std::string &method, const Json::Value &parameters, struct curl_slist **slist);
+    void json2string(const rapidjson::Value &input, std::string &output);
+    void requestbuilder(const std::string &method, const rapidjson::Value &parameters, struct curl_slist **slist);
+    void addUrlComponent(const rapidjson::Value &parameters, const char *element, std::stringstream& ss);
 };
+#endif
 
 class PipeConnector: public Connector {
   public:
@@ -65,8 +73,8 @@ class PipeConnector: public Connector {
   PipeConnector(std::map<std::string,std::string> options);
   ~PipeConnector();
 
-  virtual int send_message(const Json::Value &input);
-  virtual int recv_message(Json::Value &output);
+  virtual int send_message(const rapidjson::Document &input);
+  virtual int recv_message(rapidjson::Document &output);
 
   private:
 
@@ -105,7 +113,7 @@ class RemoteBackend : public DNSBackend
     int build(const std::string &connstr);
     Connector *connector;
     bool d_dnssec;
-    Json::Value d_result;
+    rapidjson::Value d_result;
     int d_index; 
 };
 #endif
index 8f7d14d2c4a330bdb6480498a0562aaa6f162348..560f1da131b29b82d0265f463a38d23b0a87e518 100644 (file)
@@ -4,7 +4,6 @@
 #include <unistd.h>
 #include <sys/select.h>
 #include <fcntl.h>
-
 #ifndef UNIX_PATH_MAX 
 #define UNIX_PATH_MAX 108
 #endif
@@ -26,21 +25,22 @@ UnixsocketConnector::~UnixsocketConnector() {
    }
 }
 
-int UnixsocketConnector::send_message(const Json::Value &input) {
+int UnixsocketConnector::send_message(const rapidjson::Document &input) {
         std::string data;
-        Json::FastWriter writer;
         int rv;
-        data = writer.write(input);
+        data = makeStringFromDocument(input);
+        data = data + "\n";
         rv = this->write(data);
         if (rv == -1)
           return -1;
         return rv;
 }
 
-int UnixsocketConnector::recv_message(Json::Value &output) {
+int UnixsocketConnector::recv_message(rapidjson::Document &output) {
         int rv,nread;
         std::string s_output;
-        Json::Reader r;
+        rapidjson::GenericReader<rapidjson::UTF8<> , rapidjson::MemoryPoolAllocator<> > r;
+
         time_t t0;
 
         nread = 0;
@@ -58,9 +58,10 @@ int UnixsocketConnector::recv_message(Json::Value &output) {
           if (rv>0) {
             nread += rv;
             s_output.append(temp);
-            if (r.parse(s_output,output)==true) {
-               return nread;
-            }
+            rapidjson::StringStream ss(s_output.c_str());
+            output.ParseStream<0>(ss); 
+            if (output.HasParseError() == false)
+              return s_output.size();
           }
         }
 
@@ -114,7 +115,8 @@ void UnixsocketConnector::reconnect() {
    struct sockaddr_un sock;
    struct timeval tv;
    fd_set rd;
-   Json::Value init,res;
+   rapidjson::Document init,res;
+   rapidjson::Value val;
 
    if (connected) return; // no point reconnecting if connected...
    connected = true;
@@ -147,10 +149,16 @@ void UnixsocketConnector::reconnect() {
    }
    // send initialize
 
-   init["method"] = "initialize";
-   init["parameters"] = Json::Value();
-   for(std::map<std::string,std::string>::iterator i = options.begin(); i != options.end(); i++)
-      init["parameters"][i->first] = i->second;
+   init.SetObject();
+   val = "initialize";
+   init.AddMember("method",val, init.GetAllocator());
+   val.SetObject();
+   init.AddMember("parameters", val, init.GetAllocator());
+
+   for(std::map<std::string,std::string>::iterator i = options.begin(); i != options.end(); i++) {
+     val = i->second.c_str();
+     init["parameters"].AddMember(i->first.c_str(), val, init.GetAllocator());
+   } 
 
    this->send_message(init);
    if (this->recv_message(res) == false) {
index 1baeb8bcedceb0addb19425b0b0feace0dcdec00..65efb189a28d9721efb98d7ebb21aec7ae562951 100644 (file)
@@ -4,7 +4,7 @@ else
 AM_CXXFLAGS=-DSYSCONFDIR=\"@sysconfdir@\" -DLIBDIR=\"@libdir@\" -DLOCALSTATEDIR=\"@socketdir@\" -Ibackends/bind @THREADFLAGS@ $(LUA_CFLAGS) $(SQLITE3_CFLAGS) -Iext/polarssl-1.1.2/include -Iext/rapidjson/include
 
 endif
-AM_CPPFLAGS=-Ibackends/bind $(BOOST_CPPFLAGS) @THREADFLAGS@ 
+AM_CPPFLAGS=-Ibackends/bind $(BOOST_CPPFLAGS) @THREADFLAGS@ $(LIBCURL_CFLAGS)
 
 if BOTAN110
 AM_CPPFLAGS += $(BOTAN110_CFLAGS)
@@ -68,8 +68,8 @@ md5.hh signingpipe.cc signingpipe.hh dnslabeltext.cc lua-pdns.cc lua-auth.cc lua
 ednssubnet.cc ednssubnet.hh cachecleaner.hh json.cc json.hh 
 
 #
-pdns_server_LDFLAGS=@moduleobjects@ @modulelibs@ @DYNLINKFLAGS@ @LIBDL@ @THREADFLAGS@  $(BOOST_SERIALIZATION_LDFLAGS) -rdynamic
-pdns_server_LDADD= ext/polarssl-1.1.2/library/libpolarssl.a $(BOOST_SERIALIZATION_LIBS) $(LUA_LIBS) $(SQLITE3_LIBS)
+pdns_server_LDFLAGS=@moduleobjects@ @modulelibs@ @DYNLINKFLAGS@ @LIBDL@ @THREADFLAGS@  $(BOOST_SERIALIZATION_LDFLAGS) -rdynamic 
+pdns_server_LDADD= ext/polarssl-1.1.2/library/libpolarssl.a $(BOOST_SERIALIZATION_LIBS) $(LUA_LIBS) $(SQLITE3_LIBS) $(LIBCURL_LIBS)
 
 if BOTAN110
 pdns_server_SOURCES += botan110signers.cc botansigners.cc
@@ -106,7 +106,7 @@ pdnssec_SOURCES=pdnssec.cc dbdnsseckeeper.cc sstuff.hh dnsparser.cc dnsparser.hh
 
 
 pdnssec_LDFLAGS=@moduleobjects@ @modulelibs@ @DYNLINKFLAGS@ @LIBDL@ @THREADFLAGS@  $(BOOST_PROGRAM_OPTIONS_LDFLAGS) $(BOOST_SERIALIZATION_LDFLAGS)
-pdnssec_LDADD= ext/polarssl-1.1.2/library/libpolarssl.a $(BOOST_PROGRAM_OPTIONS_LIBS) $(BOOST_SERIALIZATION_LIBS) $(SQLITE3_LIBS)
+pdnssec_LDADD= ext/polarssl-1.1.2/library/libpolarssl.a $(BOOST_PROGRAM_OPTIONS_LIBS) $(BOOST_SERIALIZATION_LIBS) $(SQLITE3_LIBS) $(LIBCURL_LIBS)
 
 if BOTAN110
 pdnssec_SOURCES += botan110signers.cc botansigners.cc