ndns-update: load Response from file directly
- also fix the bug that ndns-update segfaults when running without
parameters
Change-Id: I65a741e845d44d14aa29b2814c6616d27dc0a12a
Refs: #2255, #2273
diff --git a/tools/ndns-update.cpp b/tools/ndns-update.cpp
index 6caf991..25fda11 100644
--- a/tools/ndns-update.cpp
+++ b/tools/ndns-update.cpp
@@ -47,50 +47,34 @@
class NdnsUpdate : noncopyable
{
public:
- NdnsUpdate(const Name& hint, const Name& zone, const Name& rrLabel,
- const name::Component& rrType, NdnsType ndnsType, const Name& certName,
- Face& face)
- : m_queryType(rrType == label::CERT_RR_TYPE ?
- label::NDNS_CERT_QUERY : label::NDNS_ITERATIVE_QUERY)
- , m_rrType(rrType)
- , m_hint(hint)
+ NdnsUpdate(const Name& hint, const Name& zone, const shared_ptr<Data>& update, Face& face)
+ : m_hint(hint)
, m_zone(zone)
- , m_certName(certName)
, m_interestLifetime(DEFAULT_INTEREST_LIFETIME)
, m_face(face)
, m_validator(face)
+ , m_update(update)
, m_hasError(false)
{
- m_update.setZone(m_zone);
- m_update.setRrLabel(rrLabel);
- m_update.setQueryType(m_queryType);
- m_update.setRrType(name::Component(rrType));
- m_update.setNdnsType(ndnsType);
}
void
- run()
+ start()
{
- NDNS_LOG_INFO(" =================================== "
+ NDNS_LOG_INFO(" ================ "
<< "start to update RR at Zone = " << this->m_zone
- << " with rrLabel = " << this->m_update.getRrLabel()
- << " and rrType = " << this->m_rrType
- << " =================================== ");
- NDNS_LOG_INFO("certificate to sign the data is: " << m_certName);
+ << " new RR is: " << m_update->getName()
+ <<" =================== ");
+
+ NDNS_LOG_INFO("new RR is signed by: "
+ << m_update->getSignature().getKeyLocator().getName());
Interest interest = this->makeUpdateInterest();
- NDNS_LOG_TRACE("[* <- *] send Update: " << m_update);
+ NDNS_LOG_TRACE("[* <- *] send Update: " << m_update->getName().toUri());
m_face.expressInterest(interest,
bind(&NdnsUpdate::onData, this, _1, _2),
bind(&NdnsUpdate::onTimeout, this, _1) //dynamic binding
);
- try {
- m_face.processEvents();
- }
- catch (std::exception& e) {
- NDNS_LOG_FATAL("Face fails to process events: " << e.what());
- m_hasError = true;
- }
}
void
@@ -151,11 +135,8 @@
Interest
makeUpdateInterest()
{
- shared_ptr<Data> data = m_update.toData();
- m_keyChain.sign(*data, m_certName);
-
Query q(m_hint, m_zone, label::NDNS_ITERATIVE_QUERY);
- q.setRrLabel(Name().append(data->wireEncode()));
+ q.setRrLabel(Name().append(m_update->wireEncode()));
q.setRrType(label::NDNS_UPDATE_LABEL);
q.setInterestLifetime(m_interestLifetime);
@@ -187,17 +168,6 @@
}
public:
- void
- setUpdateAppContent(const Block& block)
- {
- m_update.setAppContent(block);
- }
-
- void
- addUpdateRr(const Block& block)
- {
- m_update.addRr(block);
- }
void
setInterestLifetime(const time::milliseconds& interestLifetime)
@@ -211,26 +181,17 @@
return m_hasError;
}
- const Response&
- getUpdate() const
- {
- return m_update;
- }
-
private:
- name::Component m_queryType; ///< NDNS or KEY
- name::Component m_rrType;
-
Name m_hint;
Name m_zone;
- Name m_certName;
+
time::milliseconds m_interestLifetime;
Face& m_face;
Validator m_validator;
KeyChain m_keyChain;
- Response m_update;
+ shared_ptr<Data> m_update;
bool m_hasError;
};
@@ -254,8 +215,8 @@
Name certName;
std::vector<string> contents;
string contentFile;
- string dstFile;
- ndn::Block block;
+ shared_ptr<Data> update;
+
try {
namespace po = boost::program_options;
po::variables_map vm;
@@ -274,7 +235,7 @@
("content,o", po::value<std::vector<string>>(&contents)->multitoken(),
"set the content of the RR")
("contentFile,f", po::value<string>(&contentFile), "set the path of file which contain"
- " content of the RR in base64 format")
+ " Response packet in base64 format")
;
po::options_description hidden("Hidden Options");
@@ -292,7 +253,11 @@
po::options_description config_file_options;
config_file_options.add(config).add(hidden);
- po::options_description visible("Allowed options");
+ po::options_description visible("Usage: ndns-update zone rrLabel [-t rrType] [-T TTL] "
+ "[-H hint] [-n NdnsType] [-c cert] "
+ "[-f contentFile]|[-o content]\n"
+ "Allowed options");
+
visible.add(generic).add(config);
po::parsed_options parsed =
@@ -302,92 +267,165 @@
po::notify(vm);
if (vm.count("help")) {
- std::cout << "Usage: ndns-update zone rrLabel [-t rrType] [-T TTL] "
- "[-H hint] [-n NdnsType] [-c cert] [-f contentFile]|[-o content]" << std::endl;
std::cout << visible << std::endl;
return 0;
}
- KeyChain keyChain;
- if (certName.empty()) {
- Name name = Name().append(zone).append(rrLabel);
- // choosing the longest match of the identity who also have default certificate
- for (size_t i = name.size() + 1; i > 0; --i) { // i >=0 will present warnning
- Name tmp = name.getPrefix(i - 1);
- if (keyChain.doesIdentityExist(tmp)) {
- try {
- certName = keyChain.getDefaultCertificateNameForIdentity(tmp);
- break;
- }
- catch (std::exception&) {
- // If it cannot get a default certificate from one identity,
- // just ignore this one try next identity.
- ;
- }
- }
- }
- }
- else {
- if (!keyChain.doesCertificateExist(certName)) {
- std::cerr << "certificate: " << certName << " does not exist" << std::endl;
- return 0;
- }
- }
-
- if (certName.empty()) {
- std::cerr << "cannot figure out the certificate automatically. "
- << "please set it with -c CERT_NAEME" << std::endl;
- }
if (vm.count("content") && vm.count("contentFile")) {
- std::cerr << "both content and contentFile are set. Only one is allowed" << std::endl;
- return 0;
+ std::cerr << "both -o content and -f contentFile are set. Only one is allowed" << std::endl;
+ return 1;
}
- if (!contentFile.empty()) {
- shared_ptr<ndn::Data> data = ndn::io::load<ndn::Data>(contentFile);
- block = data->wireEncode();
+ if (!vm.count("contentFile")) {
+ NDNS_LOG_TRACE("content option is set. try to figure out the certificate");
+ if (!vm.count("zone") || !vm.count("rrlabel")) {
+ std::cerr << "-o option must be set together with -z zone and -r rrLabel" << std::endl;
+ return 1;
+ }
+
+ KeyChain keyChain;
+ if (certName.empty()) {
+ Name name = Name().append(zone).append(rrLabel);
+ // choosing the longest match of the identity who also have default certificate
+ for (size_t i = name.size() + 1; i > 0; --i) { // i >=0 will present warnning
+ Name tmp = name.getPrefix(i - 1);
+ if (keyChain.doesIdentityExist(tmp)) {
+ try {
+ certName = keyChain.getDefaultCertificateNameForIdentity(tmp);
+ break;
+ }
+ catch (std::exception&) {
+ // If it cannot get a default certificate from one identity,
+ // just ignore this one try next identity.
+ ;
+ }
+ }
+ } // for
+
+ if (certName.empty()) {
+ std::cerr << "cannot figure out the certificate automatically. "
+ << "please set it with -c CERT_NAEME" << std::endl;
+ return 1;
+ }
+ }
+ else {
+ if (!keyChain.doesCertificateExist(certName)) {
+ std::cerr << "certificate: " << certName << " does not exist" << std::endl;
+ return 1;
+ }
+ }
+
+ NdnsType ndnsType = toNdnsType(ndnsTypeStr);
+
+ if (ndnsType == ndns::NDNS_UNKNOWN) {
+ std::cerr << "unknown NdnsType: " << ndnsTypeStr << std::endl;
+ return 1;
+ }
+
+ Response re;
+ re.setZone(zone);
+ re.setRrLabel(rrLabel);
+ name::Component qType = (rrType == "ID-CERT" ?
+ ndns::label::NDNS_CERT_QUERY : ndns::label::NDNS_ITERATIVE_QUERY);
+
+ re.setQueryType(qType);
+ re.setRrType(name::Component(rrType));
+ re.setNdnsType(ndnsType);
+
+ for (const auto& content : contents) {
+ re.addRr(ndn::dataBlock(ndn::ndns::tlv::RrData, content.c_str(), content.size()));
+
+ // re.addRr(content);
+ }
+
+ update = re.toData();
+ keyChain.sign(*update, certName);
+ }
+ else {
+ try {
+ update = ndn::io::load<ndn::Data>(contentFile);
+ NDNS_LOG_TRACE("load data " << update->getName() << " from content file: " << contentFile);
+ }
+ catch (const std::exception& e) {
+ std::cerr << "Error: load Data packet from file: " << contentFile
+ << ". Due to: " << e.what() << std::endl;
+ return 1;
+ }
+
+ try {
+ // must check the Data is a legal Response with right name
+ shared_ptr<Regex> regex = make_shared<Regex>("(<>*)<KEY>(<>+)<ID-CERT><>*");
+ shared_ptr<Regex> regex2 = make_shared<Regex>("(<>*)<NDNS>(<>+)");
+
+ Name zone2;
+ if (regex->match(update->getName())) {
+ zone2 = regex->expand("\\1");
+ }
+ else if (regex2->match(update->getName())) {
+ zone2 = regex2->expand("\\1");
+ }
+ else {
+ std::cerr << "The loaded Data packet cannot be stored in NDNS "
+ "since its does not have a proper name" << std::endl;
+ return 1;
+ }
+
+ if (vm.count("zone") && zone != zone2) {
+ std::cerr << "The loaded Data packet is supposed to be stored at zone: " << zone2
+ << " instead of zone: " << zone << std::endl;
+ return 1;
+ }
+ else {
+ zone = zone2;
+ }
+
+ Response re;
+ re.fromData(hint, zone, *update);
+
+ if (vm.count("rrlabel") && rrLabel != re.getRrLabel()) {
+ std::cerr << "The loaded Data packet is supposed to have rrLabel: " << re.getRrLabel()
+ << " instead of label: " << rrLabel << std::endl;
+ return 1;
+ }
+
+ if (vm.count("rrtype") && name::Component(rrType) != re.getRrType()) {
+ std::cerr << "The loaded Data packet is supposed to have rrType: " << re.getRrType()
+ << " instead of label: " << rrType << std::endl;
+ return 1;
+ }
+ }
+ catch (const std::exception& e) {
+ std::cerr << "Error: the loaded Data packet cannot parse to a Response stored at zone: "
+ << zone << std::endl;
+ return 1;
+ }
+
}
}
catch (const std::exception& ex) {
std::cerr << "Parameter Error: " << ex.what() << std::endl;
- return 0;
+ return 1;
}
Face face;
- NdnsType ndnsType = toNdnsType(ndnsTypeStr);
+ try {
+ NdnsUpdate updater(hint, zone, update, face);
+ updater.setInterestLifetime(ndn::time::seconds(ttl));
- NdnsUpdate update(hint, zone, rrLabel, ndn::name::Component(rrType),
- ndnsType, certName, face);
- update.setInterestLifetime(ndn::time::seconds(ttl));
-
- if (!contentFile.empty()) {
- if (!block.empty()) {
- if (ndnsType == ndn::ndns::NDNS_RAW)
- update.setUpdateAppContent(block);
- else {
- update.addUpdateRr(block);
- }
- }
- }
- else {
- if (ndnsType == ndn::ndns::NDNS_RAW) {
- // since NDNS_RAW's message tlv type cannot be decided, here we stop this option
- std::cerr << "--content (-o) does not support NDNS-RAW Response" << std::endl;
+ updater.start();
+ face.processEvents();
+ if (updater.hasError())
+ return 1;
+ else
return 0;
- }
- else {
- for (const auto& content : contents) {
- block = ndn::dataBlock(ndn::ndns::tlv::RrData, content.c_str(), content.size());
- update.addUpdateRr(block);
- }
- }
}
-
- update.run();
-
- if (update.hasError())
+ catch (const ndn::ValidatorConfig::Error& e) {
+ std::cerr << "Fail to create the validator: " << e.what() << std::endl;
return 1;
- else
- return 0;
+ }
+ catch (const std::exception& e) {
+ std::cerr << "Error: " << e.what() << std::endl;
+ return 1;
+ }
}