From: Bert Hubert Date: Thu, 6 Dec 2012 20:14:04 +0000 (+0000) Subject: aki tuomi ported the remotebackend to rapidjson and made use of libcurl optional... X-Git-Tag: auth-3.2-rc2~28 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=72ffdde4b16f6dbec417956aba3a213158e75bfb;p=thirdparty%2Fpdns.git aki tuomi ported the remotebackend to rapidjson and made use of libcurl optional (but no httpbackend w/o it!) git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@2973 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- diff --git a/configure.ac b/configure.ac index 6e51bd5098..93c58e70e3 100644 --- a/configure.ac +++ b/configure.ac @@ -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, diff --git a/modules/remotebackend/Makefile.am b/modules/remotebackend/Makefile.am index 72d96c0f45..a47f8bbae6 100644 --- a/modules/remotebackend/Makefile.am +++ b/modules/remotebackend/Makefile.am @@ -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) diff --git a/modules/remotebackend/OBJECTLIBS b/modules/remotebackend/OBJECTLIBS index cb251b2025..e69de29bb2 100644 --- a/modules/remotebackend/OBJECTLIBS +++ b/modules/remotebackend/OBJECTLIBS @@ -1 +0,0 @@ --ljsoncpp -lcurl diff --git a/modules/remotebackend/httpconnector.cc b/modules/remotebackend/httpconnector.cc index 6bfd0fe4e4..6e62940711 100644 --- a/modules/remotebackend/httpconnector.cc +++ b/modules/remotebackend/httpconnector.cc @@ -10,6 +10,7 @@ #define UNIX_PATH_MAX 108 #endif +#ifdef REMOTEBACKEND_HTTP HTTPConnector::HTTPConnector(std::map 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(input.asUInt()); - else if (input.isInt()) output = lexical_cast(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(input.GetUint()); + else if (input.IsInt()) output = lexical_cast(input.GetInt()); else output = "inconvertible value"; } +void HTTPConnector::addUrlComponent(const rapidjson::Value ¶meters, 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 ¶meters, struct curl_slist **slist) +void HTTPConnector::requestbuilder(const std::string &method, const rapidjson::Value ¶meters, struct curl_slist **slist) { std::stringstream ss; - Json::Value param; std::string sparam; char *tmpstr; - // check for certain elements - std::vector 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 diff --git a/modules/remotebackend/pipeconnector.cc b/modules/remotebackend/pipeconnector.cc index 133e36e425..b2cd5777ee 100644 --- a/modules/remotebackend/pipeconnector.cc +++ b/modules/remotebackend/pipeconnector.cc @@ -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::iterator i = options.begin(); i != options.end(); i++) - init["parameters"][i->first] = i->second; + for(std::map::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::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<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<GetString() <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(d_result.size())) { - d_result = Json::Value(); + if (d_index == static_cast(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& 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& 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& 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<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< +#include #include "pdns/namespaces.hh" #include #include @@ -10,17 +11,22 @@ #include #include #include -#include +#include +#include #include "../pipebackend/coprocess.hh" #include +#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 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 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 ¶meters, struct curl_slist **slist); + void json2string(const rapidjson::Value &input, std::string &output); + void requestbuilder(const std::string &method, const rapidjson::Value ¶meters, struct curl_slist **slist); + void addUrlComponent(const rapidjson::Value ¶meters, const char *element, std::stringstream& ss); }; +#endif class PipeConnector: public Connector { public: @@ -65,8 +73,8 @@ class PipeConnector: public Connector { PipeConnector(std::map 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 diff --git a/modules/remotebackend/unixconnector.cc b/modules/remotebackend/unixconnector.cc index 8f7d14d2c4..560f1da131 100644 --- a/modules/remotebackend/unixconnector.cc +++ b/modules/remotebackend/unixconnector.cc @@ -4,7 +4,6 @@ #include #include #include - #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::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::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::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) { diff --git a/pdns/Makefile.am b/pdns/Makefile.am index 1baeb8bced..65efb189a2 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -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