]> granicus.if.org Git - pdns/commitdiff
Use Json11 instead of RapidJSON
authorAki Tuomi <cmouse@cmouse.fi>
Fri, 8 Jan 2016 12:38:39 +0000 (14:38 +0200)
committerAki Tuomi <cmouse@cmouse.fi>
Mon, 11 Jan 2016 18:44:19 +0000 (20:44 +0200)
modules/remotebackend/httpconnector.cc
modules/remotebackend/pipeconnector.cc
modules/remotebackend/remotebackend.cc
modules/remotebackend/remotebackend.hh
modules/remotebackend/unixconnector.cc
modules/remotebackend/zmqconnector.cc

index db18969fbaf4f263fb1a833b7a0f1d06ebdd4990..5ac8309114deee89ccbf7179a3749d1df706f1a0 100644 (file)
@@ -47,47 +47,20 @@ HTTPConnector::~HTTPConnector() {
       delete d_socket;
 }
 
-// converts json value into string
-bool HTTPConnector::json2string(const rapidjson::Value &input, std::string &output) {
-   if (input.IsString()) output = input.GetString();
-   else if (input.IsNull()) output = "";
-   else if (input.IsUint64()) output = std::to_string(input.GetUint64());
-   else if (input.IsInt64()) output = std::to_string(input.GetInt64());
-   else if (input.IsUint()) output = std::to_string(input.GetUint());
-   else if (input.IsInt()) output = std::to_string(input.GetInt());
-   else return false;
-   return true;
-}
-
-void HTTPConnector::addUrlComponent(const rapidjson::Value &parameters, const char *element, std::stringstream& ss) {
-    rapidjson::Value nullval;
+void HTTPConnector::addUrlComponent(const Json &parameters, const string& element, std::stringstream& ss) {
     std::string sparam;
-    nullval.SetNull();
-    const rapidjson::Value& param = (parameters.HasMember(element)?parameters[element]:nullval);
-    if (param.IsNull() == false) {
-       json2string(param, sparam);
-       ss << "/" << sparam;
-    }
+    if (parameters[element] != Json())
+       ss << "/" << asString(parameters[element]);
 }
 
-template <class T> std::string buildMemberListArgs(std::string prefix, const T* value) {
+std::string HTTPConnector::buildMemberListArgs(std::string prefix, const Json& args) {
     std::stringstream stream;
 
-    for (rapidjson::Value::ConstMemberIterator itr = value->MemberBegin(); itr != value->MemberEnd(); itr++) {
-        stream << prefix << "[" << itr->name.GetString() << "]=";
-
-        if (itr->value.IsUint64()) {
-            stream << itr->value.GetUint64();
-        } else if (itr->value.IsInt64()) {
-            stream << itr->value.GetInt64();
-        } else if (itr->value.IsUint()) {
-            stream << itr->value.GetUint();
-        } else if (itr->value.IsInt()) {
-            stream << itr->value.GetInt();
-        } else if (itr->value.IsBool()) {
-            stream << (itr->value.GetBool() ? 1 : 0);
-        } else if (itr->value.IsString()) {
-            stream << YaHTTP::Utility::encodeURL(itr->value.GetString(), false);
+    for(const auto& pair: args.object_items()) {
+        if (pair.second.is_bool()) {
+          stream << (pair.second.bool_value()?"1":"0");
+        } else {
+          stream << prefix << "[" << pair.first << "]=" << this->asString(pair.second);
         }
 
         stream << "&";
@@ -97,7 +70,7 @@ template <class T> std::string buildMemberListArgs(std::string prefix, const T*
 }
 
 // builds our request (near-restful)
-void HTTPConnector::restful_requestbuilder(const std::string &method, const rapidjson::Value &parameters, YaHTTP::Request& req)
+void HTTPConnector::restful_requestbuilder(const std::string &method, const Json& parameters, YaHTTP::Request& req)
 {
     std::stringstream ss;
     std::string sparam;
@@ -125,18 +98,17 @@ void HTTPConnector::restful_requestbuilder(const std::string &method, const rapi
         // create an empty post
         verb = "POST";
     } else if (method == "setTSIGKey") {
-        req.POST()["algorithm"] = parameters["algorithm"].GetString();
-        req.POST()["content"] = parameters["content"].GetString();
+        req.POST()["algorithm"] = parameters["algorithm"].string_value();
+        req.POST()["content"] = parameters["content"].string_value();
         req.preparePost();
         verb = "PATCH";
     } else if (method == "deleteTSIGKey") {
         verb = "DELETE";
     } else if (method == "addDomainKey") {
-        const rapidjson::Value& param = parameters["key"];
-        json2string(param["flags"],sparam);
-        req.POST()["flags"] = sparam;
-        req.POST()["active"] = (param["active"].GetBool() ? "1" : "0");
-        req.POST()["content"] = param["content"].GetString();
+        const Json& param = parameters["key"];
+        req.POST()["flags"] = asString(param["flags"]);
+        req.POST()["active"] = (param["active"].bool_value() ? "1" : "0");
+        req.POST()["content"] = param["content"].string_value();
         req.preparePost();
         verb = "PUT";
     } else if (method == "isMaster") {
@@ -147,10 +119,8 @@ void HTTPConnector::restful_requestbuilder(const std::string &method, const rapi
         addUrlComponent(parameters, "ip", ss);
         addUrlComponent(parameters, "domain", ss);
         // then we need to serialize rrset payload into POST
-        size_t index = 0;
-        for(rapidjson::Value::ConstValueIterator itr = parameters["nsset"].Begin(); itr != parameters["nsset"].End(); itr++) {
-            index++;
-            ss2 << buildMemberListArgs("nsset[" + std::to_string(index) + "]", itr) << "&";
+        for(size_t index = 0; index < parameters["nsset"].array_items().size(); index++) {
+            ss2 << buildMemberListArgs("nsset[" + std::to_string(index) + "]", parameters["nsset"][index]) << "&";
         }
         req.body = ss2.str().substr(0, ss2.str().size()-1);
         req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
@@ -159,17 +129,15 @@ void HTTPConnector::restful_requestbuilder(const std::string &method, const rapi
     } else if (method == "createSlaveDomain") {
         addUrlComponent(parameters, "ip", ss);
         addUrlComponent(parameters, "domain", ss);
-        if (parameters.HasMember("account")) {
-           req.POST()["account"] = parameters["account"].GetString();
+        if (parameters["account"].is_string()) {
+           req.POST()["account"] = parameters["account"].string_value();
         }
         req.preparePost();
         verb = "PUT";
     } else if (method == "replaceRRSet") {
         std::stringstream ss2;
-        size_t index = 0;
-        for(rapidjson::Value::ConstValueIterator itr = parameters["rrset"].Begin(); itr != parameters["rrset"].End(); itr++) {
-            index++;
-            ss2 << buildMemberListArgs("rrset[" + std::to_string(index) + "]", itr);
+        for(size_t index = 0; index < parameters["rrset"].array_items().size(); index++) {
+            ss2 << buildMemberListArgs("rrset[" + std::to_string(index) + "]", parameters["rrset"][index]);
         }
         req.body = ss2.str();
         req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
@@ -177,15 +145,18 @@ void HTTPConnector::restful_requestbuilder(const std::string &method, const rapi
         verb = "PATCH";
     } else if (method == "feedRecord") {
         addUrlComponent(parameters, "trxid", ss);
-        req.body = buildMemberListArgs("rr", &parameters["rr"]);
+        req.body = buildMemberListArgs("rr", parameters["rr"]);
         req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
         req.headers["content-length"] = std::to_string(req.body.size());
         verb = "PATCH";
     } else if (method == "feedEnts") {
         std::stringstream ss2;
         addUrlComponent(parameters, "trxid", ss);
-        for(rapidjson::Value::ConstValueIterator itr = parameters["nonterm"].Begin(); itr != parameters["nonterm"].End(); itr++) {
-          ss2 << "nonterm[]=" << YaHTTP::Utility::encodeURL(itr->GetString(), false) << "&";
+        for(const auto& param: parameters["nonterm"].array_items()) {
+          ss2 << "nonterm[]=" << YaHTTP::Utility::encodeURL(param.string_value(), false) << "&";
+        }
+        for(const auto& param: parameters["auth"].array_items()) {
+          ss2 << "auth[]=" << (param["auth"].bool_value()?"1":"0") << "&";
         }
         req.body = ss2.str().substr(0, ss2.str().size()-1);
         req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
@@ -195,9 +166,12 @@ void HTTPConnector::restful_requestbuilder(const std::string &method, const rapi
         std::stringstream ss2;
         addUrlComponent(parameters, "domain", ss);
         addUrlComponent(parameters, "trxid", ss);
-        ss2 << "times=" << parameters["times"].GetInt() << "&salt=" << YaHTTP::Utility::encodeURL(parameters["salt"].GetString(), false) << "&narrow=" << (parameters["narrow"].GetBool() ? 1 : 0) << "&";
-        for(rapidjson::Value::ConstValueIterator itr = parameters["nonterm"].Begin(); itr != parameters["nonterm"].End(); itr++) {
-          ss2 << "nonterm[]=" << YaHTTP::Utility::encodeURL(itr->GetString(), false) << "&";
+        ss2 << "times=" << parameters["times"].int_value() << "&salt=" << YaHTTP::Utility::encodeURL(parameters["salt"].string_value(), false) << "&narrow=" << (parameters["narrow"].bool_value() ? 1 : 0) << "&";
+        for(const auto& param: parameters["nonterm"].array_items()) {
+          ss2 << "nonterm[]=" << YaHTTP::Utility::encodeURL(param.string_value(), false) << "&";
+        }
+        for(const auto& param: parameters["auth"].array_items()) {
+          ss2 << "auth[]=" << (param["auth"].bool_value()?"1":"0") << "&";
         }
         req.body = ss2.str().substr(0, ss2.str().size()-1);
         req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
@@ -212,18 +186,17 @@ void HTTPConnector::restful_requestbuilder(const std::string &method, const rapi
         verb = "POST";
     } else if (method == "calculateSOASerial") {
         addUrlComponent(parameters, "domain", ss);
-        req.body = buildMemberListArgs("sd", &parameters["sd"]);
+        req.body = buildMemberListArgs("sd", parameters["sd"]);
         req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
         req.headers["content-length"] = std::to_string(req.body.size());
         verb = "POST";
     } else if (method == "setDomainMetadata") {
         // copy all metadata values into post
         std::stringstream ss2;
-        const rapidjson::Value& param = parameters["value"];
         // this one has values too
-        if (param.IsArray()) {
-           for(rapidjson::Value::ConstValueIterator i = param.Begin(); i != param.End(); i++) {
-              ss2 << "value[]=" << YaHTTP::Utility::encodeURL(i->GetString(), false) << "&";
+        if (parameters["value"].is_array()) {
+           for(const auto& val: parameters["value"].array_items()) {
+              ss2 << "value[]=" << YaHTTP::Utility::encodeURL(val.string_value(), false) << "&";
            }
         }
         req.body = ss2.str().substr(0, ss2.str().size()-1);
@@ -234,19 +207,16 @@ void HTTPConnector::restful_requestbuilder(const std::string &method, const rapi
         // this one is delete
         verb = "DELETE";
     } else if (method == "setNotified") {
-        json2string(parameters["serial"],sparam);
-        req.POST()["serial"] = sparam;
+        req.POST()["serial"] = std::to_string(parameters["serial"].number_value());
         req.preparePost();
         verb = "PATCH";
     } else if (method == "directBackendCmd") {
-        json2string(parameters["query"],sparam);
-        req.POST()["query"] = sparam;
+        req.POST()["query"] = parameters["query"].string_value();
         req.preparePost();
         verb = "POST";
     } else if (method == "searchRecords" || method == "searchComments") {
-        json2string(parameters["pattern"],sparam);
-        req.GET()["pattern"] = sparam;
-        req.GET()["maxResults"] = std::to_string(parameters["maxResults"].GetInt());
+        req.GET()["pattern"] = parameters["pattern"].string_value();
+        req.GET()["maxResults"] = std::to_string(parameters["maxResults"].int_value());
         verb = "GET";
     } else {
         // perform normal get
@@ -254,17 +224,16 @@ void HTTPConnector::restful_requestbuilder(const std::string &method, const rapi
     }
 
     // put everything else into headers
-    for (rapidjson::Value::ConstMemberIterator iter = parameters.MemberBegin(); iter != parameters.MemberEnd(); ++iter) {
-      std::string member = iter->name.GetString();
+    for(const auto& pair: parameters.object_items()) {
+      std::string member = pair.first;
       // whitelist header parameters
       if ((member == "trxid" ||
            member == "local" || 
            member == "remote" ||
            member == "real-remote" ||
-           member == "zone-id") && 
-          json2string(parameters[member.c_str()], sparam)) {
+           member == "zone-id")) {
         std::string hdr = "x-remotebackend-" + member;
-        req.headers[hdr] = sparam;
+        req.headers[hdr] = pair.second.string_value();
       }
     };
 
@@ -275,14 +244,11 @@ void HTTPConnector::restful_requestbuilder(const std::string &method, const rapi
     req.headers["accept"] = "application/json";
 }
 
-void HTTPConnector::post_requestbuilder(const rapidjson::Document &input, YaHTTP::Request& req) {
-    rapidjson::StringBuffer output;
-    rapidjson::Writer<rapidjson::StringBuffer> w(output);
+void HTTPConnector::post_requestbuilder(const Json& input, YaHTTP::Request& req) {
     if (this->d_post_json) {
+        std::string out = input.dump();
         req.setup("POST", d_url);
         // simple case, POST JSON into url. nothing fancy.
-        input.Accept(w);
-        std::string out(output.GetString(), output.Size());
         req.headers["Content-Type"] = "text/javascript; charset=utf-8";
         req.headers["Content-Length"] = std::to_string(out.size());
         req.headers["accept"] = "application/json";
@@ -290,17 +256,16 @@ void HTTPConnector::post_requestbuilder(const rapidjson::Document &input, YaHTTP
     } else {
         std::stringstream url,content;
         // call url/method.suffix
-        input["parameters"].Accept(w);
-        url << d_url << "/" << input["method"].GetString() << d_url_suffix;
+        url << d_url << "/" << input["method"].string_value() << d_url_suffix;
         req.setup("POST", url.str());
         // then build content
-        req.POST()["parameters"] = output.GetString();
+        req.POST()["parameters"] = input["parameters"].dump();
         req.preparePost();
         req.headers["accept"] = "application/json";
     }
 }
 
-int HTTPConnector::send_message(const rapidjson::Document &input) {
+int HTTPConnector::send_message(const Json& input) {
     int rv,ec,fd;
     
     std::vector<std::string> members;
@@ -313,7 +278,7 @@ int HTTPConnector::send_message(const rapidjson::Document &input) {
     if (d_post)
       post_requestbuilder(input, req);
     else
-      restful_requestbuilder(input["method"].GetString(), input["parameters"], req);
+      restful_requestbuilder(input["method"].string_value(), input["parameters"], req);
 
     rv = -1;
     req.headers["connection"] = "Keep-Alive"; // see if we can streamline requests (not needed, strictly speaking)
@@ -385,7 +350,7 @@ int HTTPConnector::send_message(const rapidjson::Document &input) {
     return rv;
 }
 
-int HTTPConnector::recv_message(rapidjson::Document &output) {
+int HTTPConnector::recv_message(Json& output) {
     YaHTTP::AsyncResponseLoader arl;
     YaHTTP::Response resp;
 
@@ -433,15 +398,11 @@ int HTTPConnector::recv_message(rapidjson::Document &output) {
       return -1;
     }
 
-    rapidjson::StringStream ss(resp.body.c_str());
     int rv = -1;
-    output.ParseStream<0>(ss);
-
-    // offer whatever we read in send_message
-    if (output.HasParseError() == false)
-       rv = rd;
-    else
-       rv = -1;
+    std::string err;
+    output = Json::parse(resp.body, err);
+    if (output != nullptr) return resp.body.size();
+    L<<Logger::Error<<"Cannot parse JSON reply: "<<err<<endl;
 
     return rv;
 }
index 52934fa5ec6feed6a0863a041c5e1adacf65b9dd..338269a8245aefe453c31402b4ca71436271a556 100644 (file)
@@ -1,9 +1,6 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sstream>
 #include "remotebackend.hh"
 
 PipeConnector::PipeConnector(std::map<std::string,std::string> options) {
@@ -96,32 +93,22 @@ void PipeConnector::launch() {
        no way to log this either - only thing we can do is make sure that our parent catches this soonest! */
   }
 
-  rapidjson::Value val;
-  rapidjson::Document init,res;
-  init.SetObject();
-  val = "initialize";
+  Json::array parameters;
+  Json msg = Json(Json::object{
+    { "method", "initialize" },
+    { "parameters", Json(options) },
+  });
 
-  init.AddMember("method",val, init.GetAllocator());
-  val.SetObject();
-  init.AddMember("parameters", val, init.GetAllocator());
-
-  for(auto 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) {
+  this->send(msg);
+  msg = nullptr;
+  if (this->recv(msg)==false) {
     L<<Logger::Error<<"Failed to initialize coprocess"<<std::endl;
   }
 }
 
-int PipeConnector::send_message(const rapidjson::Document &input)
+int PipeConnector::send_message(const Json& input)
 {
-   rapidjson::StringBuffer output;
-   rapidjson::Writer<rapidjson::StringBuffer> w(output);
-   input.Accept(w);
-   auto line = std::string(output.GetString(), output.Size());
+   auto line = input.dump();
    launch();
 
    line.append(1,'\n');
@@ -140,11 +127,10 @@ int PipeConnector::send_message(const rapidjson::Document &input)
    return sent;
 }
 
-int PipeConnector::recv_message(rapidjson::Document &output) 
+int PipeConnector::recv_message(Json& output)
 {
    std::string receive;
-   rapidjson::GenericReader<rapidjson::UTF8<> , rapidjson::MemoryPoolAllocator<> > r;
-   std::string tmp;
+   std::string err;
    std::string s_output;
    launch();
 
@@ -168,10 +154,9 @@ int PipeConnector::recv_message(rapidjson::Document &output)
        throw PDNSException("Child closed pipe");
   
       s_output.append(receive);
-      rapidjson::StringStream ss(s_output.c_str());
-      output.ParseStream<0>(ss); 
-      if (output.HasParseError() == false)
-        return s_output.size();
+      // see if it can be parsed
+      output = Json::parse(s_output, err);
+      if (output != nullptr) return s_output.size();
    }
    return 0;
 }
index bd5ea1bfd817156b25d22b8e59a2e86a30fcddd2..1b10a909547db832bc8ba7a3c979cb039f775255 100644 (file)
@@ -3,7 +3,6 @@
 #endif
 #include "remotebackend.hh"
 
-
 static const char *kBackendId = "[RemoteBackend]";
 
 /**
@@ -11,42 +10,32 @@ static const char *kBackendId = "[RemoteBackend]";
  * we need to do some treatment to the value before
  * sending it downwards.
  */
-bool Connector::send(rapidjson::Document &value) {
-    return send_message(value);
+bool Connector::send(Json& value) {
+    return send_message(value)>0;
 }
 
-/** 
+/**
  * Helper for handling receiving of data.
- * Basically what happens here is that we check 
+ * Basically what happens here is that we check
  * that the receiving happened ok, and extract
- * result. Logging is performed here, too. 
+ * result. Logging is performed here, too.
  */
-bool Connector::recv(rapidjson::Document &value) {
+bool Connector::recv(Json& value) {
     if (recv_message(value)>0) {
        bool rv = true;
        // check for error
-       if (!value.HasMember("result")) {
-          return false;
-       }
-       if (!value["result"].IsObject() && getBool(value["result"]) == false) {
-           rv = false;
-        }
-        if (value.HasMember("log")) {
-           rapidjson::Value& messages = value["log"];
-           if (messages.IsArray()) {
-              // log em all
-              for (rapidjson::Value::ValueIterator iter = messages.Begin(); iter != messages.End(); ++iter)
-                 L<<Logger::Info<<"[remotebackend]: "<< getString(*iter) <<std::endl;
-           } else if (messages.IsNull() == false) { // could be just a value
-               L<<Logger::Info<<"[remotebackend]: "<< getString(messages) <<std::endl;
-           }
-        }
-        return rv;
+       if (value["result"] == Json())
+         return false;
+       if (value["result"].is_bool() && boolFromJson(value, "result", false) == false)
+         rv = false;
+       for(const auto& message: value["log"].array_items())
+         L<<Logger::Info<<"[remotebackend]: "<< message.string_value() <<std::endl;
+       return rv;
     }
     return false;
 }
 
-/** 
+/**
  * Standard ctor and dtor
  */
 RemoteBackend::RemoteBackend(const std::string &suffix)
@@ -54,21 +43,20 @@ RemoteBackend::RemoteBackend(const std::string &suffix)
       setArgPrefix("remote"+suffix);
 
       this->d_connstr = getArg("connection-string");
-      this->d_result = NULL;
       this->d_dnssec = mustDo("dnssec");
       this->d_index = -1;
       this->d_trxid = 0;
-    
+
       build();
 }
 
 RemoteBackend::~RemoteBackend() {
-     if (connector != NULL) {
+    if (connector != NULL) {
        delete connector;
      }
 }
 
-bool RemoteBackend::send(rapidjson::Document &value) {
+bool RemoteBackend::send(Json& value) {
    try {
      return connector->send(value);
    } catch (PDNSException &ex) {
@@ -80,7 +68,7 @@ bool RemoteBackend::send(rapidjson::Document &value) {
    return false;
 }
 
-bool RemoteBackend::recv(rapidjson::Document &value) {
+bool RemoteBackend::recv(Json& value) {
    try {
      return connector->recv(value);
    } catch (PDNSException &ex) {
@@ -95,7 +83,7 @@ bool RemoteBackend::recv(rapidjson::Document &value) {
 }
 
 
-/** 
+/**
  * Builds connector based on options
  * Currently supports unix,pipe and http
  */
@@ -156,79 +144,64 @@ int RemoteBackend::build() {
       return -1;
 }
 
-/** 
+/**
  * The functions here are just remote json stubs that send and receive the method call
- * data is mainly left alone, some defaults are assumed. 
+ * data is mainly left alone, some defaults are assumed.
  */
 void RemoteBackend::lookup(const QType &qtype, const DNSName& qdomain, DNSPacket *pkt_p, int zoneId) {
-   rapidjson::Document query;
-   rapidjson::Value parameters;
-
-   if (d_index != -1) 
+   if (d_index != -1)
       throw PDNSException("Attempt to lookup while one running");
 
-   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_DNSNAME(parameters, "qname", qdomain, 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());
-
-   d_result = new rapidjson::Document();
+   Json query = Json::object{
+     { "method", "lookup" },
+     { "parameters", Json::object{
+       { "qtype", qtype.getName() },
+       { "qname", qdomain.toString() },
+       { "remote", remoteIP },
+       { "local", localIP },
+       { "real-remote", realRemote },
+       { "zone-id", zoneId }
+     }}
+   };
 
-   if (this->send(query) == false || this->recv(*d_result) == false) { 
-      delete d_result;
+   if (this->send(query) == false || this->recv(d_result) == false) {
       return;
    }
 
    // OK. we have result parameters in result. do not process empty result.
-   if ((*d_result)["result"].IsArray() == false || (*d_result)["result"].Size() < 1) {
-      delete d_result;
-      return;
-   }
+   if (d_result["result"].is_array() == false || d_result["result"].array_items().size() < 1)
+     return;
 
    d_index = 0;
 }
 
 bool RemoteBackend::list(const DNSName& target, int domain_id, bool include_disabled) {
-   rapidjson::Document query;
-   rapidjson::Value parameters;
-
    if (d_index != -1)
       throw PDNSException("Attempt to lookup while one running");
 
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "list", query.GetAllocator());
-   query["method"] = "list";
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "zonename", target, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "domain-id", domain_id, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
-
-   d_result = new rapidjson::Document();
+   Json query = Json::object{
+     { "method", "list" },
+     { "parameters", Json::object{
+       { "zonename", target.toString() },
+       { "domain-id", domain_id },
+       { "include-disabled", include_disabled }
+     }}
+   };
 
-   if (this->send(query) == false || this->recv(*d_result) == false) {
-     delete d_result;
+   if (this->send(query) == false || this->recv(d_result) == false)
+     return false;
+   if (d_result["result"].is_array() == false || d_result["result"].array_items().size() < 1)
      return false;
-   }
-   if ((*d_result)["result"].IsArray() == false || (*d_result)["result"].Size() < 1) {
-      delete d_result;
-      return false;
-   }
 
    d_index = 0;
    return true;
@@ -237,86 +210,78 @@ bool RemoteBackend::list(const DNSName& target, int domain_id, bool include_disa
 bool RemoteBackend::get(DNSResourceRecord &rr) {
    if (d_index == -1) return false;
 
-   rapidjson::Value value;
-
-   value = "";
-   rr.qtype = getString(JSON_GET((*d_result)["result"][d_index], "qtype", value));
-   rr.qname = DNSName(getString(JSON_GET((*d_result)["result"][d_index], "qname", value)));
+   rr.qtype = stringFromJson(d_result["result"][d_index], "qtype");
+   rr.qname = DNSName(stringFromJson(d_result["result"][d_index], "qname"));
    rr.qclass = QClass::IN;
-   rr.content = getString(JSON_GET((*d_result)["result"][d_index], "content",value));
-   value = -1;
-   rr.ttl = getInt(JSON_GET((*d_result)["result"][d_index], "ttl",value));
-   rr.domain_id = getInt(JSON_GET((*d_result)["result"][d_index],"domain_id",value));
-   value = 1;
-   if (d_dnssec) 
-     rr.auth = getInt(JSON_GET((*d_result)["result"][d_index],"auth", value));
+   rr.content = stringFromJson(d_result["result"][d_index], "content");
+   rr.ttl = intFromJson(d_result["result"][d_index], "ttl", 0);
+   rr.domain_id = intFromJson(d_result["result"][d_index], "domain_id", -1);
+   if (d_dnssec)
+     rr.auth = intFromJson(d_result["result"][d_index], "auth", 1);
    else
      rr.auth = 1;
-   value = 0;
-   rr.scopeMask = getInt(JSON_GET((*d_result)["result"][d_index],"scopeMask", value));
-
+   rr.scopeMask = intFromJson(d_result["result"][d_index], "scopeMask", 0);
    d_index++;
-   
-   // id index is out of bounds, we know the results end here. 
-   if (d_index == static_cast<int>((*d_result)["result"].Size())) {
-     delete d_result;
-     d_result = NULL;
+
+   // id index is out of bounds, we know the results end here.
+   if (d_index == static_cast<int>(d_result["result"].array_items().size())) {
+     d_result = Json();
      d_index = -1;
    }
    return true;
 }
 
 bool RemoteBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, DNSName& unhashed, std::string& before, std::string& after) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
 
-   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());
+   Json query = Json::object{
+     { "method", "getBeforeAndAfterNamesAbsolute" },
+     { "parameters", Json::object {
+       { "id", Json(static_cast<double>(id)) },
+       { "qname", qname }
+     }}
+   };
+   Json answer;
 
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
-   unhashed = DNSName(getString(answer["result"]["unhashed"]));
-   before = getString(answer["result"]["before"]);
-   after = getString(answer["result"]["after"]);
+   unhashed = DNSName(stringFromJson(answer["result"], "unhashed"));
+   before = "";
+   after = "";
+   if (answer["result"]["before"] != Json())
+     before = stringFromJson(answer["result"], "before");
+   if (answer["result"]["after"] != Json())
+     after = stringFromJson(answer["result"], "after");
+
    return true;
 }
 
 bool RemoteBackend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "getAllDomainMetadata", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", name, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "getAllDomainMetadata" },
+     { "parameters", Json::object {
+       { "name", name.toString() }
+     }}
+   };
 
    if (this->send(query) == false)
      return false;
 
    meta.clear();
 
+   Json answer;
    // not mandatory to implement
    if (this->recv(answer) == false)
      return true;
 
-   if (answer["result"].IsObject()) {
-     for (rapidjson::Value::MemberIterator kind = answer["result"].MemberBegin(); kind != answer["result"].MemberEnd(); kind++) {
-       if (kind->value.IsArray()) {
-         for(rapidjson::Value::ValueIterator content = kind->value.Begin(); content != kind->value.End(); content++)
-           meta[kind->name.GetString()].push_back(getString(*content));
-       } else {
-         meta[kind->name.GetString()].push_back(getString(kind->value));
-       }
+   for(const auto& pair: answer["result"].object_items()) {
+     if (pair.second.is_array()) {
+       for(const auto& val: pair.second.array_items())
+         meta[pair.first].push_back(asString(val));
+     } else {
+       meta[pair.first].push_back(asString(pair.second));
      }
    }
 
@@ -324,110 +289,95 @@ bool RemoteBackend::getAllDomainMetadata(const DNSName& name, std::map<std::stri
 }
 
 bool RemoteBackend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "getDomainMetadata", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", name, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "kind", kind.c_str(), query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "getDomainMetadata" },
+     { "parameters", Json::object {
+       { "name", name.toString() },
+       { "kind", kind }
+     }}
+   };
 
    if (this->send(query) == false)
      return false;
 
    meta.clear();
 
+   Json answer;
    // not mandatory to implement
    if (this->recv(answer) == false)
      return true;
 
-   if (answer["result"].IsArray()) {
-      for(rapidjson::Value::ValueIterator iter = answer["result"].Begin(); iter != answer["result"].End(); iter++) {
-         meta.push_back(getString(*iter));
-      }
-   } else if (answer["result"].IsString()) {
-      meta.push_back(answer["result"].GetString());
+   if (answer["result"].is_array()) {
+     for(const auto& row: answer["result"].array_items())
+       meta.push_back(row.string_value());
+   } else if (answer["result"].is_string()) {
+      meta.push_back(answer["result"].string_value());
    }
 
    return true;
 }
 
 bool RemoteBackend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters,val;
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "setDomainMetadata", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", name, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "kind", kind.c_str(), query.GetAllocator());
-   val.SetArray();
-   for(const auto& value: meta) {
-     val.PushBack(value.c_str(), query.GetAllocator());
-   }
-   parameters.AddMember("value", val, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "setDomainMetadata" },
+     { "parameters", Json::object {
+       { "name", name.toString() },
+       { "kind", kind },
+       { "value", meta }
+     }}
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
-   return getBool(answer["result"]);
+   return boolFromJson(answer, "result", false);
 }
 
 
 bool RemoteBackend::getDomainKeys(const DNSName& name, unsigned int kind, std::vector<DNSBackend::KeyData>& keys) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
 
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "getDomainKeys", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", name, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "kind", kind, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "getDomainKeys" },
+     { "parameters", Json::object{
+       { "name", name.toString() },
+       { "kind", static_cast<int>(kind) }
+     }}
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
    keys.clear();
 
-   for(rapidjson::Value::ValueIterator iter = answer["result"].Begin(); iter != answer["result"].End(); iter++) {
-      DNSBackend::KeyData key;
-      if (!(*iter).IsObject())
-        throw PDNSException("Invalid reply to getDomainKeys, expected array of hashes, got something else");
-
-      if (!(*iter).HasMember("id") ||
-          !(*iter).HasMember("flags") ||
-          !(*iter).HasMember("active") ||
-          !(*iter).HasMember("content"))
-        throw PDNSException("Invalid reply to getDomainKeys, missing keys in key hash");
-
-      key.id = getUInt((*iter)["id"]);
-      key.flags = getUInt((*iter)["flags"]);
-      key.active = getBool((*iter)["active"]);
-      key.content = getString((*iter)["content"]);
-      keys.push_back(key);
+   for(const auto& jsonKey: answer["result"].array_items()) {
+     DNSBackend::KeyData key;
+     key.id = intFromJson(jsonKey, "id");
+     key.flags = intFromJson(jsonKey, "flags");
+     key.active = boolFromJson(jsonKey, "active");
+     key.content = stringFromJson(jsonKey, "content");
+     keys.push_back(key);
    }
 
    return true;
 }
 
-bool RemoteBackend::removeDomainKey(const DNSName& name, unsigned int id) { 
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
+bool RemoteBackend::removeDomainKey(const DNSName& name, unsigned int id) {
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
 
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "removeDomainKey", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", name, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "removeDomainKey" },
+     { "parameters", Json::object {
+       { "name", name.toString() },
+       { "id", static_cast<int>(id) }
+     }}
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
@@ -435,42 +385,41 @@ bool RemoteBackend::removeDomainKey(const DNSName& name, unsigned int id) {
 }
 
 int RemoteBackend::addDomainKey(const DNSName& name, const KeyData& key) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters,jkey;
-
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "addDomainKey", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", name, 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());
 
+   Json query = Json::object{
+     { "method", "addDomainKey" },
+     { "parameters", Json::object {
+       { "name", name.toString() },
+       { "key", Json::object {
+         { "flags", static_cast<int>(key.flags) },
+         { "active", key.active },
+         { "content", key.content }
+       }}
+     }}
+    };
+
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
-   return getInt(answer["result"]);
+   return intFromJson(answer,"result",0);
 }
 
 bool RemoteBackend::activateDomainKey(const DNSName& name, unsigned int id) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
 
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "activateDomainKey", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", name, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "activateDomainKey" },
+     { "parameters", Json::object {
+       { "name", name.toString() },
+       { "id", static_cast<int>(id) }
+     }}
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
@@ -478,19 +427,18 @@ bool RemoteBackend::activateDomainKey(const DNSName& name, unsigned int id) {
 }
 
 bool RemoteBackend::deactivateDomainKey(const DNSName& name, unsigned int id) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
 
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "deactivateDomainKey", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", name, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "id", id, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "deactivateDomainKey" },
+     { "parameters", Json::object {
+       { "name", name.toString() },
+       { "id", static_cast<int>(id) }
+     }}
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
@@ -502,44 +450,40 @@ bool RemoteBackend::doesDNSSEC() {
 }
 
 bool RemoteBackend::getTSIGKey(const DNSName& name, DNSName* algorithm, std::string* content) {
-   rapidjson::Document query,answer;
-   rapidjson::Value 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_DNSNAME(parameters, "name", name, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
 
+   Json query = Json::object{
+     { "method", "getTSIGKey" },
+     { "parameters", Json::object {
+       { "name", name.toString() }
+     }}
+   };
+
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
-   if (!answer["result"].IsObject() ||
-       !answer["result"].HasMember("algorithm") ||
-       !answer["result"].HasMember("content")) 
-     throw PDNSException("Invalid response to getTSIGKey, missing field(s)");
+   (*algorithm) = DNSName(stringFromJson(answer["result"], "algorithm"));
+   (*content) = stringFromJson(answer["result"], "content");
 
-   (*algorithm) = DNSName(getString(answer["result"]["algorithm"]));
-   content->assign(getString(answer["result"]["content"]));
-   
    return true;
 }
 
 bool RemoteBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const std::string& content) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "setTSIGKey", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", name, query.GetAllocator());
-   JSON_ADD_MEMBER_DNSNAME(parameters, "algorithm", algorithm, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "content", content.c_str(), query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+
+   Json query = Json::object{
+     { "method", "setTSIGKey" },
+     { "parameters", Json::object {
+       { "name", name.toString() },
+       { "algorithm", algorithm.toString() },
+       { "content", content }
+     }}
+   };
+
+   Json answer;
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
 
@@ -547,16 +491,16 @@ bool RemoteBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, co
 }
 
 bool RemoteBackend::deleteTSIGKey(const DNSName& name) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "deleteTSIGKey", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", name, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "deleteTSIGKey" },
+     { "parameters", Json::object {
+       { "name", name.toString() }
+     }}
+   };
+
+   Json answer;
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
 
@@ -564,78 +508,55 @@ bool RemoteBackend::deleteTSIGKey(const DNSName& name) {
 }
 
 bool RemoteBackend::getTSIGKeys(std::vector<struct TSIGKey>& keys) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-
    // no point doing dnssec if it's not supported
    if (d_dnssec == false) return false;
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "getTSIGKeys", query.GetAllocator());
-   parameters.SetObject();
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "getTSIGKeys" },
+     { "parameters", Json::object {
+     }}
+   };
 
+   Json answer;
    if (connector->send(query) == false || connector->recv(answer) == false)
      return false;
 
-   // expect array
-   if (answer["result"].IsArray()) {
-      for(rapidjson::Value::ValueIterator iter = answer["result"].Begin(); iter != answer["result"].End(); iter++) {
-         struct TSIGKey key;
-         rapidjson::Value value;
-         value = "";
-         key.name = DNSName(getString(JSON_GET((*iter), "name", value)));
-         key.algorithm = DNSName(getString(JSON_GET((*iter), "algorithm", value)));
-         key.key = getString(JSON_GET((*iter), "content", value));
-
-         if (key.name.empty() ||
-             key.algorithm.empty() ||
-             key.key.empty())
-           throw PDNSException("Invalid reply for getTSIGKeys query");
-
-         keys.push_back(key);
-      }
+   for(const auto& jsonKey: answer["result"].array_items()) {
+     struct TSIGKey key;
+     key.name = DNSName(stringFromJson(jsonKey, "name"));
+     key.algorithm = DNSName(stringFromJson(jsonKey, "algorithm"));
+     key.key = stringFromJson(jsonKey, "content");
+     keys.push_back(key);
    }
 
    return true;
 }
 
 bool RemoteBackend::getDomainInfo(const DNSName& domain, DomainInfo &di) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-   rapidjson::Value value;
-   std::string kind;
-
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "getDomainInfo", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", domain, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   if (domain.empty()) return false;
+   Json query = Json::object{
+     { "method", "getDomainInfo" },
+     { "parameters", Json::object {
+       { "name", domain.toString() }
+     }}
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
-   // make sure we got zone & kind
-   if (!answer["result"].IsObject() || !answer["result"].HasMember("zone")) {
-      L<<Logger::Error<<kBackendId<<" Missing zone in getDomainInfo return value"<<endl;
-      throw PDNSException();
-   }
-   value = -1;
-   // parse return value. we need at least zone,serial,kind
-   di.id = getInt(JSON_GET(answer["result"],"id",value));
-   di.zone = DNSName(getString(answer["result"]["zone"]));
-
-   if (answer["result"].HasMember("masters") && answer["result"]["masters"].IsArray()) {
-     rapidjson::Value& value = answer["result"]["masters"];
-     for(rapidjson::Value::ValueIterator i = value.Begin(); i != value.End(); i++) {
-        di.masters.push_back(getString(*i));
-     }
+   di.id = intFromJson(answer["result"], "id", -1);
+   di.zone = DNSName(stringFromJson(answer["result"], "zone"));
+   for(const auto& master: answer["result"]["masters"].array_items())
+     di.masters.push_back(master.string_value());
+
+   di.notified_serial = static_cast<unsigned int>(doubleFromJson(answer["result"], "notified_serial", -1));
+   di.serial = static_cast<unsigned int>(doubleFromJson(answer["result"], "serial", 0));
+   di.last_check = static_cast<time_t>(doubleFromJson(answer["result"], "last_check", 0));
+
+   string kind = "";
+   if (answer["result"]["kind"].is_string()) {
+     kind = stringFromJson(answer["result"], "kind");
    }
-   di.notified_serial = getInt(JSON_GET(answer["result"], "notified_serial", value));
-   value = 0;
-   di.serial = getInt(JSON_GET(answer["result"],"serial", value));
-   di.last_check = getInt(JSON_GET(answer["result"],"last_check", value));
-   value = "native";
-   kind = getString(JSON_GET(answer["result"], "kind", value));
    if (kind == "master") {
       di.kind = DomainInfo::Master;
    } else if (kind == "slave") {
@@ -648,16 +569,15 @@ bool RemoteBackend::getDomainInfo(const DNSName& domain, DomainInfo &di) {
 }
 
 void RemoteBackend::setNotified(uint32_t id, uint32_t serial) {
-   rapidjson::Document query,answer;
-   rapidjson::Value 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", serial, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "setNotified" },
+     { "parameters", Json::object {
+       { "id", static_cast<double>(id) },
+       { "serial", static_cast<double>(serial) }
+     }}
+   };
+
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false) {
       L<<Logger::Error<<kBackendId<<" Failed to execute RPC for RemoteBackend::setNotified("<<id<<","<<serial<<")"<<endl;
    }
@@ -665,15 +585,15 @@ void RemoteBackend::setNotified(uint32_t id, uint32_t serial) {
 
 bool RemoteBackend::isMaster(const DNSName& name, const string &ip)
 {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "isMaster", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "name", name, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "ip", ip.c_str(), query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "isMaster" },
+     { "parameters", Json::object {
+       { "name", name.toString() },
+       { "ip", ip }
+     }}
+   };
+
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
@@ -682,33 +602,31 @@ bool RemoteBackend::isMaster(const DNSName& name, const string &ip)
 
 bool RemoteBackend::superMasterBackend(const string &ip, const DNSName& domain, const vector<DNSResourceRecord>&nsset, string* nameserver, string *account, DNSBackend **ddb)
 {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-   rapidjson::Value rrset;
-
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "superMasterBackend", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER(parameters, "ip", ip.c_str(), query.GetAllocator());
-   JSON_ADD_MEMBER_DNSNAME(parameters, "domain", domain, query.GetAllocator());
-   rrset.SetArray();
-   rrset.Reserve(nsset.size(), query.GetAllocator());
-   for(rapidjson::SizeType i = 0; i < nsset.size(); i++) {
-      rapidjson::Value rr;
-      rr.SetObject();
-      JSON_ADD_MEMBER(rr, "qtype", nsset[i].qtype.getName().c_str(), query.GetAllocator());
-      JSON_ADD_MEMBER_DNSNAME(rr, "qname", nsset[i].qname, query.GetAllocator());
-      JSON_ADD_MEMBER(rr, "qclass", QClass::IN, query.GetAllocator());
-      JSON_ADD_MEMBER(rr, "content", nsset[i].content.c_str(), query.GetAllocator());
-      JSON_ADD_MEMBER(rr, "ttl", nsset[i].ttl, query.GetAllocator());
-      JSON_ADD_MEMBER(rr, "auth", nsset[i].auth, query.GetAllocator());
-      rrset.PushBack(rr, query.GetAllocator());
+   Json::array rrset;
+
+   for(const auto& ns: nsset) {
+      rrset.push_back(Json::object{
+        { "qtype", ns.qtype.getName() },
+        { "qname", ns.qname.toString() },
+        { "qclass", QClass::IN },
+        { "content", ns.content },
+        { "ttl", static_cast<int>(ns.ttl) },
+        { "auth", ns.auth }
+      });
    }
-   parameters.AddMember("nsset", rrset, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+
+   Json query = Json::object{
+     { "method", "superMasterBackend" },
+     { "parameters", Json::object {
+       { "ip", ip },
+       { "domain", domain.toString() },
+       { "nsset", rrset }
+     }}
+   };
 
    *ddb = 0;
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
@@ -716,61 +634,56 @@ bool RemoteBackend::superMasterBackend(const string &ip, const DNSName& domain,
    *ddb = this;
 
    // we allow simple true as well...
-   if (answer["result"].IsObject()) {
-     if (answer["result"].HasMember("account")) 
-       *account = getString(answer["result"]["account"]);
-     if (answer["result"].HasMember("nameserver"))
-       *nameserver = getString(answer["result"]["nameserver"]);
+   if (answer["result"].is_object()) {
+     *account = stringFromJson(answer["result"], "account");
+     *nameserver = stringFromJson(answer["result"], "nameserver");
    }
+
    return true;
 }
 
 bool RemoteBackend::createSlaveDomain(const string &ip, const DNSName& domain, const string& nameserver, const string &account) {
-   rapidjson::Document query,answer; 
-   rapidjson::Value parameters;
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "createSlaveDomain", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER(parameters, "ip", ip.c_str(), query.GetAllocator());
-   JSON_ADD_MEMBER_DNSNAME(parameters, "domain", domain, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "nameserver", nameserver.c_str(), query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "account", account.c_str(), query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "createSlaveDomain" },
+     { "parameters", Json::object {
+       { "ip", ip },
+       { "domain", domain.toString() },
+       { "nameserver", nameserver },
+       { "account", account },
+     }}
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
    return true;
 }
 
 bool RemoteBackend::replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qtype, const vector<DNSResourceRecord>& rrset) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-   rapidjson::Value rj_rrset;
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "replaceRRSet", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER(parameters, "domain_id", domain_id, query.GetAllocator());
-   JSON_ADD_MEMBER_DNSNAME(parameters, "qname", qname, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "qtype", qtype.getName().c_str(), query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "trxid", d_trxid, query.GetAllocator());
-
-   rj_rrset.SetArray();
-   rj_rrset.Reserve(rrset.size(), query.GetAllocator());
-
-   for(rapidjson::SizeType i = 0; i < rrset.size(); i++) {
-      rapidjson::Value rr;
-      rr.SetObject();
-      JSON_ADD_MEMBER(rr, "qtype", rrset[i].qtype.getName().c_str(), query.GetAllocator());
-      JSON_ADD_MEMBER_DNSNAME(rr, "qname", rrset[i].qname, query.GetAllocator());
-      JSON_ADD_MEMBER(rr, "qclass", QClass::IN, query.GetAllocator());
-      JSON_ADD_MEMBER(rr, "content", rrset[i].content.c_str(), query.GetAllocator());
-      JSON_ADD_MEMBER(rr, "ttl", rrset[i].ttl, query.GetAllocator());
-      JSON_ADD_MEMBER(rr, "auth", rrset[i].auth, query.GetAllocator());
-      rj_rrset.PushBack(rr, query.GetAllocator());
+   Json::array json_rrset;
+   for(const auto& rr: rrset) {
+      json_rrset.push_back(Json::object{
+        { "qtype", rr.qtype.getName() },
+        { "qname", rr.qname.toString() },
+        { "qclass", QClass::IN },
+        { "content", rr.content },
+        { "ttl", static_cast<int>(rr.ttl) },
+        { "auth", rr.auth }
+      });
    }
-   parameters.AddMember("rrset", rj_rrset, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
 
+   Json query = Json::object{
+     { "method", "replaceRRSet" },
+     { "parameters", Json::object {
+       { "domain_id", static_cast<double>(domain_id) },
+       { "qname", qname.toString() },
+       { "qtype", qtype.getName() },
+       { "trxid", static_cast<double>(d_trxid) },
+       { "rrset", json_rrset }
+     }}
+   };
+
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
@@ -778,96 +691,93 @@ bool RemoteBackend::replaceRRSet(uint32_t domain_id, const DNSName& qname, const
 }
 
 bool RemoteBackend::feedRecord(const DNSResourceRecord &rr, string *ordername) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters,rj_rr;
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "feedRecord", query.GetAllocator());
-   parameters.SetObject();
-   rj_rr.SetObject();
-   JSON_ADD_MEMBER(rj_rr, "qtype", rr.qtype.getName().c_str(), query.GetAllocator());
-   JSON_ADD_MEMBER_DNSNAME(rj_rr, "qname", rr.qname, query.GetAllocator());
-   JSON_ADD_MEMBER(rj_rr, "qclass", QClass::IN, query.GetAllocator());
-   JSON_ADD_MEMBER(rj_rr, "content", rr.content.c_str(), query.GetAllocator());
-   JSON_ADD_MEMBER(rj_rr, "ttl", rr.ttl, query.GetAllocator());
-   JSON_ADD_MEMBER(rj_rr, "auth", rr.auth, query.GetAllocator());
-   parameters.AddMember("rr", rj_rr, query.GetAllocator());
-
-   JSON_ADD_MEMBER(parameters, "trxid", d_trxid, query.GetAllocator());
-
-   if (ordername) {
-     JSON_ADD_MEMBER(parameters, "ordername", ordername->c_str(), query.GetAllocator());
-   }
-
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "feedRecord" },
+     { "parameters", Json::object{
+        { "rr", Json::object{
+          { "qtype", rr.qtype.getName() },
+          { "qname", rr.qname.toString() },
+          { "qclass", QClass::IN },
+          { "content", rr.content },
+          { "ttl", static_cast<int>(rr.ttl) },
+          { "auth", rr.auth },
+          { "ordername", (ordername==nullptr?Json():*ordername) }
+        }},
+        { "trxid", static_cast<double>(d_trxid) },
+     }}
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
    return true; // XXX FIXME this API should not return 'true' I think -ahu
 }
 
 bool RemoteBackend::feedEnts(int domain_id, map<DNSName,bool>& nonterm) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-   rapidjson::Value nts;
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "feedEnts", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER(parameters, "domain_id", domain_id, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "trxid", d_trxid, query.GetAllocator());
-   nts.SetArray();
-   for(const auto& t: nonterm) {
-      rapidjson::Value value(t.first.toString().c_str(), query.GetAllocator());
-      nts.PushBack(value, query.GetAllocator());
-   }
-   parameters.AddMember("nonterm", nts, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json::array nts;
+
+   for(const auto& t: nonterm)
+     nts.push_back(Json::object{
+       { "nonterm", t.first.toString() },
+       { "auth", t.second }
+     });
+
+   Json query = Json::object{
+     { "method", "feedEnts" },
+     { "parameters", Json::object{
+       { "domain_id",  domain_id },
+       { "trxid", static_cast<double>(d_trxid) },
+       { "nonterm", nts }
+     }},
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
-   return true; 
+   return true;
 }
 
 bool RemoteBackend::feedEnts3(int domain_id, const DNSName& domain, map<DNSName,bool>& nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-   rapidjson::Value nts;
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "feedEnts3", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER(parameters, "domain_id", domain_id, query.GetAllocator());
-   JSON_ADD_MEMBER_DNSNAME(parameters, "domain", domain, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "times", ns3prc.d_iterations, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "salt", ns3prc.d_salt.c_str(), query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "narrow", narrow, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "trxid", d_trxid, query.GetAllocator());
-
-   nts.SetArray();
-   for(const auto& t: nonterm) {
-      rapidjson::Value value(t.first.toString().c_str(), query.GetAllocator());
-      nts.PushBack(value, query.GetAllocator());
-   }
-   parameters.AddMember("nonterm", nts, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json::array nts;
+
+   for(const auto& t: nonterm)
+     nts.push_back(Json::object{
+       { "nonterm", t.first.toString() },
+       { "auth", t.second }
+     });
+
+   Json query = Json::object{
+     { "method", "feedEnts3" },
+     { "parameters", Json::object{
+       { "domain_id",  domain_id },
+       { "domain", domain.toString() },
+       { "times", ns3prc.d_iterations },
+       { "salt", ns3prc.d_salt },
+       { "narrow", narrow },
+       { "trxid", static_cast<double>(d_trxid) },
+       { "nonterm", nts }
+     }},
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
    return true;
 }
 
 bool RemoteBackend::startTransaction(const DNSName& domain, int domain_id) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
    this->d_trxid = time((time_t*)NULL);
 
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "startTransaction", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "domain", domain, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "domain_id", domain_id, query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "trxid", d_trxid, query.GetAllocator());
-
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "startTransaction" },
+     { "parameters", Json::object{
+       { "domain", domain.toString() },
+       { "domain_id", domain_id },
+       { "trxid", static_cast<double>(d_trxid) }
+     }}
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false) {
      d_trxid = -1;
      return false;
@@ -875,122 +785,115 @@ bool RemoteBackend::startTransaction(const DNSName& domain, int domain_id) {
    return true;
 
 }
-bool RemoteBackend::commitTransaction() { 
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
+bool RemoteBackend::commitTransaction() {
+   if (d_trxid == -1) return false;
 
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "commitTransaction", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER(parameters, "trxid", d_trxid, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "commitTransaction" },
+     { "parameters", Json::object{
+       { "trxid", static_cast<double>(d_trxid) }
+     }}
+   };
 
    d_trxid = -1;
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
    return true;
 }
 
-bool RemoteBackend::abortTransaction() { 
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
+bool RemoteBackend::abortTransaction() {
+   if (d_trxid == -1) return false;
 
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "abortTransaction", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER(parameters, "trxid", d_trxid, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "abortTransaction" },
+     { "parameters", Json::object{
+       { "trxid", static_cast<double>(d_trxid) }
+     }}
+   };
 
    d_trxid = -1;
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
    return true;
 }
 
 bool RemoteBackend::calculateSOASerial(const DNSName& domain, const SOAData& sd, time_t& serial) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-   rapidjson::Value soadata;
-
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "calculateSOASerial", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(parameters, "domain", domain, query.GetAllocator());
-   soadata.SetObject();
-   JSON_ADD_MEMBER_DNSNAME(soadata, "qname", sd.qname, query.GetAllocator());
-   JSON_ADD_MEMBER_DNSNAME(soadata, "nameserver", sd.nameserver, query.GetAllocator());
-   JSON_ADD_MEMBER_DNSNAME(soadata, "hostmaster", sd.hostmaster, query.GetAllocator());
-   JSON_ADD_MEMBER(soadata, "ttl", sd.ttl, query.GetAllocator());
-   JSON_ADD_MEMBER(soadata, "serial", sd.serial, query.GetAllocator());
-   JSON_ADD_MEMBER(soadata, "refresh", sd.refresh, query.GetAllocator());
-   JSON_ADD_MEMBER(soadata, "retry", sd.retry, query.GetAllocator());
-   JSON_ADD_MEMBER(soadata, "expire", sd.expire, query.GetAllocator());
-   JSON_ADD_MEMBER(soadata, "default_ttl", sd.default_ttl, query.GetAllocator());
-   JSON_ADD_MEMBER(soadata, "domain_id", sd.domain_id, query.GetAllocator());
-   JSON_ADD_MEMBER(soadata, "scopeMask", sd.scopeMask, query.GetAllocator());
-   parameters.AddMember("sd", soadata, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "calculateSOASerial" },
+     { "parameters", Json::object{
+       { "domain", domain.toString() },
+       { "sd", Json::object{
+         { "qname", sd.qname.toString() },
+         { "nameserver", sd.nameserver.toString() },
+         { "hostmaster", sd.hostmaster.toString() },
+         { "ttl", static_cast<int>(sd.ttl) },
+         { "serial", static_cast<double>(sd.serial) },
+         { "refresh", static_cast<int>(sd.refresh) },
+         { "retry", static_cast<int>(sd.retry) },
+         { "expire", static_cast<int>(sd.expire) },
+         { "default_ttl", static_cast<int>(sd.default_ttl) },
+         { "domain_id", static_cast<int>(sd.domain_id) },
+         { "scopeMask", sd.scopeMask }
+       }}
+     }}
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return false;
 
-   serial = getInt64(answer["result"]);
+   serial = static_cast<unsigned int>(doubleFromJson(answer,"result"));
    return true;
 }
 
 string RemoteBackend::directBackendCmd(const string& querystr) {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "directBackendCmd", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER(parameters, "query", querystr.c_str(), query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
+   Json query = Json::object{
+     { "method", "directBackendCmd" },
+     { "parameters", Json::object{
+       { "query", querystr }
+     }}
+   };
 
+   Json answer;
    if (this->send(query) == false || this->recv(answer) == false)
      return "backend command failed";
 
-   return getString(answer["result"]);
+   return asString(answer["result"]);
 }
 
 bool RemoteBackend::searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result)
 {
-   rapidjson::Document query,answer;
-   rapidjson::Value parameters;
-
-   query.SetObject();
-   JSON_ADD_MEMBER(query, "method", "searchRecords", query.GetAllocator());
-   parameters.SetObject();
-   JSON_ADD_MEMBER(parameters, "pattern", pattern.c_str(), query.GetAllocator());
-   JSON_ADD_MEMBER(parameters, "maxResults", maxResults, query.GetAllocator());
-   query.AddMember("parameters", parameters, query.GetAllocator());
-
-   if (this->send(query) == false || this->recv(answer) == false)
-     return false;
+  Json query = Json::object{
+    { "method", "searchRecords" },
+    { "parameters", Json::object{
+      { "pattern", pattern },
+      { "maxResults", maxResults }
+    }}
+  };
+
+  Json answer;
+  if (this->send(query) == false || this->recv(answer) == false)
+    return false;
 
-   if (answer["result"].IsArray() == false)
-     return false;
+  if (answer["result"].is_array() == false)
+    return false;
 
-   for(rapidjson::SizeType i = 0; i < answer["result"].Size(); i++) {
-     DNSResourceRecord rr;
-     rapidjson::Value value;
-     value = "";
-     rr.qtype = getString(JSON_GET((*d_result)["result"][d_index], "qtype", value));
-     rr.qname = DNSName(getString(JSON_GET((*d_result)["result"][d_index], "qname", value)));
-     rr.qclass = QClass::IN;
-     rr.content = getString(JSON_GET((*d_result)["result"][d_index], "content",value));
-     value = -1;
-     rr.ttl = getInt(JSON_GET((*d_result)["result"][d_index], "ttl",value));
-     rr.domain_id = getInt(JSON_GET((*d_result)["result"][d_index],"domain_id",value));
-     value = 1;
-     if (d_dnssec)
-       rr.auth = getInt(JSON_GET((*d_result)["result"][d_index],"auth", value));
-     else
-       rr.auth = 1;
-     value = 0;
-     rr.scopeMask = getInt(JSON_GET((*d_result)["result"][d_index],"scopeMask", value));
-     result.push_back(rr);
+  for(const auto& row: answer["result"].array_items()) {
+    DNSResourceRecord rr;
+    rr.qtype = stringFromJson(row, "qtype");
+    rr.qname = DNSName(stringFromJson(row, "qname"));
+    rr.qclass = QClass::IN;
+    rr.content = stringFromJson(row, "content");
+    rr.ttl = intFromJson(row, "ttl", 0);
+    rr.domain_id = intFromJson(row, "domain_id", -1);
+    if (d_dnssec)
+      rr.auth = intFromJson(row, "auth", 1);
+    else
+      rr.auth = 1;
+    rr.scopeMask = intFromJson(row, "scopeMask", 0);
+    result.push_back(rr);
   }
 
   return true;
@@ -1002,104 +905,6 @@ bool RemoteBackend::searchComments(const string &pattern, int maxResults, vector
   return false;
 }
 
-
-// some rapidjson helpers 
-bool RemoteBackend::getBool(rapidjson::Value &value) {
-   if (value.IsNull()) return false;
-   if (value.IsBool()) return value.GetBool();
-   if (value.IsInt()) return value.GetInt() != 0; // 0 = false, non-zero true
-   if (value.IsDouble()) return value.GetDouble() != 0; // 0 = false, non-zero true
-   if (value.IsString()) {  // accepts 0, 1, false, true
-     std::string tmp = value.GetString();
-     if (boost::iequals(tmp, "1") || boost::iequals(tmp, "true")) return true;
-     if (boost::iequals(tmp, "0") || boost::iequals(tmp, "false")) return false;
-   }
-   std::cerr << value.GetType() << endl;
-   throw PDNSException("Cannot convert rapidjson value into boolean");
-}
-
-bool Connector::getBool(rapidjson::Value &value) {
-   if (value.IsNull()) return false;
-   if (value.IsBool()) return value.GetBool();
-   if (value.IsInt()) return value.GetInt() != 0; // 0 = false, non-zero true
-   if (value.IsDouble()) return value.GetDouble() != 0; // 0 = false, non-zero true
-   if (value.IsString()) {  // accepts 0, 1, false, true
-     std::string tmp = value.GetString();
-     if (boost::iequals(tmp, "1") || boost::iequals(tmp, "true")) return true;
-     if (boost::iequals(tmp, "0") || boost::iequals(tmp, "false")) return false;
-   }
-
-   // this is specific for Connector!
-   return true;
-}
-
-std::string Connector::getString(rapidjson::Value &value) {
-   if (value.IsString()) return value.GetString();
-   if (value.IsBool()) return (value.GetBool() ? "true" : "false");
-   if (value.IsInt64()) return std::to_string(value.GetInt64());
-   if (value.IsInt()) return std::to_string(value.GetInt());
-   if (value.IsDouble()) return std::to_string(value.GetDouble());
-   return "(unpresentable value)"; // cannot convert into presentation format
-}
-
-int RemoteBackend::getInt(rapidjson::Value &value) {
-   if (value.IsInt()) return value.GetInt();
-   if (value.IsBool()) return (value.GetBool() ? 1 : 0);
-   if (value.IsUint()) return static_cast<int>(value.GetUint());
-   if (value.IsDouble()) return static_cast<int>(value.GetDouble());
-   if (value.IsString()) {  // accepts 0, 1, false, true
-     std::string tmp = value.GetString();
-     return std::stoi(tmp);
-   }
-   throw PDNSException("Cannot convert rapidjson value into integer");
-}
-
-unsigned int RemoteBackend::getUInt(rapidjson::Value &value) {
-   if (value.IsUint()) return value.GetUint();
-   if (value.IsBool()) return (value.GetBool() ? 1 : 0);
-   if (value.IsInt()) return static_cast<unsigned int>(value.GetInt());
-   if (value.IsDouble()) return static_cast<unsigned int>(value.GetDouble());
-   if (value.IsString()) {  // accepts 0, 1, false, true
-     std::string tmp = value.GetString();
-     return pdns_stou(tmp);
-   }
-   throw PDNSException("Cannot convert rapidjson value into integer");
-}
-
-int64_t RemoteBackend::getInt64(rapidjson::Value &value) {
-   if (value.IsInt64()) return value.GetInt64();
-   if (value.IsBool()) return (value.GetBool() ? 1 : 0);
-   if (value.IsInt()) return value.GetInt();
-   if (value.IsDouble()) return static_cast<int64_t>(value.GetDouble());
-   if (value.IsString()) {  // accepts 0, 1, false, true
-     std::string tmp = value.GetString();
-     return std::stoll(tmp);
-   }
-   throw PDNSException("Cannot convert rapidjson value into integer");
-}
-
-std::string RemoteBackend::getString(rapidjson::Value &value) {
-   if (value.IsNull()) return "";
-   if (value.IsString()) return value.GetString();
-   if (value.IsBool()) return (value.GetBool() ? "true" : "false");
-   if (value.IsInt64()) return std::to_string(value.GetInt64());
-   if (value.IsInt()) return std::to_string(value.GetInt());
-   if (value.IsDouble()) return std::to_string(value.GetDouble());
-   throw PDNSException("Cannot convert rapidjson value into std::string");
-}
-
-double RemoteBackend::getDouble(rapidjson::Value &value) {
-   if (value.IsDouble()) return value.GetDouble();
-   if (value.IsBool()) return (value.GetBool() ? 1.0L : 0.0L);
-   if (value.IsInt64()) return static_cast<double>(value.GetInt64());
-   if (value.IsInt()) return static_cast<double>(value.GetInt());
-   if (value.IsString()) {  // accepts 0, 1, false, true
-     std::string tmp = value.GetString();
-     return std::stod(tmp);
-   }
-   throw PDNSException("Cannot convert rapidjson value into double");
-}
-
 DNSBackend *RemoteBackend::maker()
 {
    try {
index a7ccefb0c79506de314536f4cce6da15455bfd1a..b3c745f8d89df8405f832013c9456a7efdd605ad 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef REMOTEBACKEND_REMOTEBACKEND_HH
 
+#include <sys/types.h>
+#include <sys/wait.h>
+
 #include <string>
-#include <sstream>
 #include "pdns/arguments.hh"
 #include "pdns/dns.hh"
 #include "pdns/dnsbackend.hh"
@@ -12,8 +14,8 @@
 #include "pdns/sstuff.hh"
 #include "pdns/ueberbackend.hh"
 #include "pdns/json.hh"
+#include "pdns/lock.hh"
 #include "yahttp/yahttp.hpp"
-#include <sstream>
 
 #ifdef REMOTEBACKEND_ZEROMQ
 #include <zmq.h>
 #define zmq_msg_recv(msg, socket, flags) zmq_recv(socket, msg, flags)
 #endif
 #endif
-#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); }
-#define JSON_ADD_MEMBER_DNSNAME(obj, name, val, alloc) { rapidjson::Value __xval(val.toString().c_str(), alloc); obj.AddMember(name, __xval, alloc); }
+
+using json11::Json;
 
 class Connector {
    public:
     virtual ~Connector() {};
-    bool send(rapidjson::Document &value);
-    bool recv(rapidjson::Document &value);
-    virtual int send_message(const rapidjson::Document &input) = 0;
-    virtual int recv_message(rapidjson::Document &output) = 0;
+    bool send(Json &value);
+    bool recv(Json &value);
+    virtual int send_message(const Json &input) = 0;
+    virtual int recv_message(Json &output) = 0;
    protected:
-    bool getBool(rapidjson::Value &value);
-    std::string getString(rapidjson::Value &value);
+    string asString(const Json& value) {
+      if (value.is_number()) return std::to_string(value.int_value());
+      if (value.is_bool()) return (value.bool_value()?"1":"0");
+      if (value.is_string()) return value.string_value();
+      throw JsonException("Json value not convertible to String");
+    };
 };
 
 // fwd declarations
@@ -45,8 +50,8 @@ class UnixsocketConnector: public Connector {
   public:
     UnixsocketConnector(std::map<std::string,std::string> options);
     virtual ~UnixsocketConnector();
-    virtual int send_message(const rapidjson::Document &input);
-    virtual int recv_message(rapidjson::Document &output);
+    virtual int send_message(const Json &input);
+    virtual int recv_message(Json &output);
   private:
     ssize_t read(std::string &data);
     ssize_t write(const std::string &data);
@@ -64,8 +69,8 @@ class HTTPConnector: public Connector {
   HTTPConnector(std::map<std::string,std::string> options);
   ~HTTPConnector();
 
-  virtual int send_message(const rapidjson::Document &input);
-  virtual int recv_message(rapidjson::Document &output);
+  virtual int send_message(const Json &input);
+  virtual int recv_message(Json &output);
   private:
     std::string d_url;
     std::string d_url_suffix;
@@ -73,10 +78,10 @@ class HTTPConnector: public Connector {
     int timeout;
     bool d_post; 
     bool d_post_json;
-    bool json2string(const rapidjson::Value &input, std::string &output);
-    void restful_requestbuilder(const std::string &method, const rapidjson::Value &parameters, YaHTTP::Request& req);
-    void post_requestbuilder(const rapidjson::Document &input, YaHTTP::Request& req);
-    void addUrlComponent(const rapidjson::Value &parameters, const char *element, std::stringstream& ss);
+    void restful_requestbuilder(const std::string &method, const Json &parameters, YaHTTP::Request& req);
+    void post_requestbuilder(const Json &input, YaHTTP::Request& req);
+    void addUrlComponent(const Json &parameters, const string& element, std::stringstream& ss);
+    std::string buildMemberListArgs(std::string prefix, const Json& args);
     Socket* d_socket;
     ComboAddress d_addr;
 };
@@ -86,8 +91,8 @@ class ZeroMQConnector: public Connector {
    public:
     ZeroMQConnector(std::map<std::string,std::string> options);
     virtual ~ZeroMQConnector();
-    virtual int send_message(const rapidjson::Document &input);
-    virtual int recv_message(rapidjson::Document &output);
+    virtual int send_message(const Json &input);
+    virtual int recv_message(Json &output);
    private:
     void connect();
     std::string d_endpoint;
@@ -105,8 +110,8 @@ class PipeConnector: public Connector {
   PipeConnector(std::map<std::string,std::string> options);
   ~PipeConnector();
 
-  virtual int send_message(const rapidjson::Document &input);
-  virtual int recv_message(rapidjson::Document &output);
+  virtual int send_message(const Json &input);
+  virtual int recv_message(Json &output);
 
   private:
 
@@ -169,19 +174,19 @@ class RemoteBackend : public DNSBackend
     int build();
     Connector *connector;
     bool d_dnssec;
-    rapidjson::Document *d_result;
+    Json d_result;
     int d_index;
     int64_t d_trxid;
     std::string d_connstr;
 
-    bool getBool(rapidjson::Value &value);
-    int getInt(rapidjson::Value &value);
-    unsigned int getUInt(rapidjson::Value &value);
-    int64_t getInt64(rapidjson::Value &value);
-    std::string getString(rapidjson::Value &value);
-    double getDouble(rapidjson::Value &value);
-
-    bool send(rapidjson::Document &value);
-    bool recv(rapidjson::Document &value);
+    bool send(Json &value);
+    bool recv(Json &value);
+    string asString(const Json& value) {
+      if (value.is_number()) return std::to_string(value.int_value());
+      if (value.is_bool()) return (value.bool_value()?"1":"0");
+      if (value.is_string()) return value.string_value();
+      throw JsonException("Json value not convertible to String");
+    };
 };
 #endif
index 884102fc69fa8010ca0233fac7a2c303a8b69bf2..5c5a7216fcfd7b05d3557c11bba293e9a7e33bb8 100644 (file)
@@ -2,11 +2,6 @@
 #include "config.h"
 #endif
 #include "remotebackend.hh"
-#include <sys/socket.h>
-#include <sstream>
-#include "pdns/lock.hh" 
-#include <unistd.h>
-#include <fcntl.h>
 #ifndef UNIX_PATH_MAX 
 #define UNIX_PATH_MAX 108
 #endif
@@ -33,21 +28,17 @@ UnixsocketConnector::~UnixsocketConnector() {
   }
 }
 
-int UnixsocketConnector::send_message(const rapidjson::Document &input) {
-  rapidjson::StringBuffer output;
-  rapidjson::Writer<rapidjson::StringBuffer> w(output);
-  input.Accept(w);
-  auto data = std::string(output.GetString(), output.Size()) + "\n";
+int UnixsocketConnector::send_message(const Json& input) {
+  auto data = input.dump() + "\n";
   int rv = this->write(data);
   if (rv == -1)
     return -1;
   return rv;
 }
 
-int UnixsocketConnector::recv_message(rapidjson::Document &output) {
+int UnixsocketConnector::recv_message(Json& output) {
   int rv,nread;
-  std::string s_output;
-  rapidjson::GenericReader<rapidjson::UTF8<> , rapidjson::MemoryPoolAllocator<> > r;
+  std::string s_output,err;
 
   struct timeval t0,t;
 
@@ -75,10 +66,9 @@ int UnixsocketConnector::recv_message(rapidjson::Document &output) {
     if (rv>0) {
       nread += rv;
       s_output.append(temp);
-      rapidjson::StringStream ss(s_output.c_str());
-      output.ParseStream<0>(ss); 
-      if (output.HasParseError() == false)
-        return s_output.size();
+      // see if it can be parsed
+      output = Json::parse(s_output, err);
+      if (output != nullptr) return s_output.size();
     }
     gettimeofday(&t, NULL);
   }
@@ -133,8 +123,6 @@ ssize_t UnixsocketConnector::write(const std::string &data) {
 
 void UnixsocketConnector::reconnect() {
   struct sockaddr_un sock;
-  rapidjson::Document init,res;
-  rapidjson::Value val;
   int rv;
 
   if (connected) return; // no point reconnecting if connected...
@@ -163,19 +151,15 @@ void UnixsocketConnector::reconnect() {
   }
   // send initialize
 
-  init.SetObject();
-  val = "initialize";
-  init.AddMember("method",val, init.GetAllocator());
-  val.SetObject();
-  init.AddMember("parameters", val, init.GetAllocator());
+  Json::array parameters;
+  Json msg = Json(Json::object{
+    { "method", "initialize" },
+    { "parameters", Json(options) },
+  });
 
-  for(auto 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) {
+  this->send(msg);
+  msg = nullptr;
+  if (this->recv(msg) == false) {
      L<<Logger::Warning << "Failed to initialize backend" << std::endl;
      close(fd);
      this->connected = false;
index aaa17e869224228f37942504adbf11176f8a5d8d..c810d042efbf411a4bc9e251239ef33b0f690ec5 100644 (file)
@@ -4,15 +4,7 @@
 #include "remotebackend.hh"
 #ifdef REMOTEBACKEND_ZEROMQ
 
-#include <sys/socket.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <sstream>
-
 ZeroMQConnector::ZeroMQConnector(std::map<std::string,std::string> options) {
-  rapidjson::Value val;
-  rapidjson::Document init,res;
   int opt=0;
 
   // lookup timeout, target and stuff
@@ -38,20 +30,15 @@ ZeroMQConnector::ZeroMQConnector(std::map<std::string,std::string> options) {
     throw PDNSException("Cannot find 'endpoint' option in connection string");
   }
 
-  init.SetObject();
-  val = "initialize";
+  Json::array parameters;
+  Json msg = Json(Json::object{
+    { "method", "initialize" },
+    { "parameters", Json(options) },
+  });
 
-  init.AddMember("method",val, init.GetAllocator());
-  val.SetObject();
-  init.AddMember("parameters", val, init.GetAllocator());
-
-  for(auto 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) {
+  this->send(msg);
+  msg = nullptr;
+  if (this->recv(msg)==false) {
     L<<Logger::Error<<"Failed to initialize zeromq"<<std::endl;
     throw PDNSException("Failed to initialize zeromq");
   } 
@@ -62,11 +49,8 @@ ZeroMQConnector::~ZeroMQConnector() {
   zmq_term(this->d_ctx);
 };
 
-int ZeroMQConnector::send_message(const rapidjson::Document &input) {
-   rapidjson::StringBuffer output;
-   rapidjson::Writer<rapidjson::StringBuffer> w(output);
-   input.Accept(w);
-   auto line = std::string(output.GetString(), output.Size());
+int ZeroMQConnector::send_message(const Json& input) {
+   auto line = input.dump();
    zmq_msg_t message;
 
    zmq_msg_init_size(&message, line.size()+1);
@@ -96,11 +80,10 @@ int ZeroMQConnector::send_message(const rapidjson::Document &input) {
    return 0;
 }
 
-int ZeroMQConnector::recv_message(rapidjson::Document &output) {
+int ZeroMQConnector::recv_message(Json& output) {
    int rv = 0;
    // try to receive message
    zmq_pollitem_t item;
-   rapidjson::GenericReader<rapidjson::UTF8<> , rapidjson::MemoryPoolAllocator<> > r;
    zmq_msg_t message;
 
    item.socket = d_sock;
@@ -114,25 +97,20 @@ int ZeroMQConnector::recv_message(rapidjson::Document &output) {
        if (zmq_poll(&item, 1, 1)>0) {
          // we have an event
          if ((item.revents & ZMQ_POLLIN) == ZMQ_POLLIN) {
-           char *data;
+           string data;
            size_t msg_size;
            zmq_msg_init(&message);
            // read something
            if(zmq_msg_recv(&message, this->d_sock, ZMQ_NOBLOCK)>0) {
+               string err;
                msg_size = zmq_msg_size(&message);
-               data = new char[msg_size+1];
-               memcpy(data, zmq_msg_data(&message), msg_size);
-               data[msg_size] = '\0';
+               data.assign(reinterpret_cast<const char*>(zmq_msg_data(&message)), msg_size);
                zmq_msg_close(&message);
-
-               rapidjson::StringStream ss(data);
-               output.ParseStream<0>(ss);
-               delete[] data;
-
-               if (output.HasParseError() == false)
+               output = Json::parse(data, err);
+               if (output != nullptr)
                  rv = msg_size;
                else 
-                 L<<Logger::Error<<"Cannot parse JSON reply from " << this->d_endpoint<<std::endl;
+                 L<<Logger::Error<<"Cannot parse JSON reply from " << this->d_endpoint << ": " << err << endl;
                break;
              } else if (errno == EAGAIN) { continue; // try again }
              } else {