enable published data validation
add flag to indicate the last component for autocompletion
Change-Id: Ice97969b2043dd0e15d00576e605d19a7528f21d
diff --git a/catalog.conf.sample.in b/catalog.conf.sample.in
index fc32347..b119aab 100644
--- a/catalog.conf.sample.in
+++ b/catalog.conf.sample.in
@@ -6,7 +6,7 @@
; "ndn:/cmip5/catalog/query" and "ndn:/cmip5/catalog/query-results",
; PublishAdapter has the prefix "ndn:/cmip5/catalog/publish"
- prefix /catalog/myUniqueName
+ prefix /cmip5
; Set name components for the scientific data, for example, the climate data
; contains name fields like activity, ..., time
@@ -32,8 +32,8 @@
{
dbServer 127.0.0.1 ; Specify the database server
dbName testdb ; Specify the database name
- dbUser testuser1 ; Specify the database user name
- dbPasswd test123 ; Specify the associated password for the dbUser
+ dbUser testuser ; Specify the database user name
+ dbPasswd test623 ; Specify the associated password for the dbUser
}
}
@@ -46,31 +46,115 @@
; The security section contains the rules for the adapter to verify the
; published files indeed come from a valid publisher.
- ; security
- ; {
- ; rule
- ; {
- ; id "NDN Hierarchy Test Rule"
- ; for data ; rule for Data (to validate NDN certificates)
- ; filter
- ; {
- ; type name ; condition on data name
- ; regex ^(<>*)$
- ; }
- ; checker
- ; {
- ; type hierarchical ; the certificate name of the signing key and
- ; ; the data name must follow the hierarchical model
- ; sig-type rsa-sha256 ; data must have a rsa-sha256 signature
- ; }
- ; }
- ; trust-anchor
- ; {
- ; type file
- ; file-name /directory/to/the/root.ndncert ; the file name, by default this file should be
- ; ; in same folder as this config file.
- ; }
- ; }
+ security
+ {
+ rule
+ {
+ id "Publishing data is signed by the Datapublisher's dsk"
+ for data ; rule for Data (to validate NDN certificates)
+ filter
+ {
+ type name
+ regex ^<><><><>$ ; condition on data name
+ }
+ checker
+ {
+ type customized
+ sig-type rsa-sha256
+ key-locator
+ {
+ type name
+ hyper-relation
+ {
+ k-regex ^([^<DataPublisher><KEY>]*)<DataPublisher><KEY><dsk-.*><ID-CERT>$
+ k-expand \\1
+ h-relation equal
+ p-regex ^(<>)<>(<>)<>$
+ p-expand \\1\\2
+ }
+ }
+ }
+ }
+
+ rule
+ {
+ id "Datapublisher's dsk is signed by its ksk"
+ for data
+ filter
+ {
+ type name
+ regex ^[^<DataPublisher><KEY>]*<DataPublisher><KEY><dsk-.*><ID-CERT><>$
+ }
+ checker
+ {
+ type customized
+ sig-type rsa-sha256
+ key-locator
+ {
+ type name
+ hyper-relation
+ {
+ k-regex ^([^<DataPublisher><KEY>]*)<DataPublisher><KEY><ksk-.*><ID-CERT>$
+ k-expand \\1
+ h-relation equal
+ p-regex ^([^<DataPublisher><KEY>]*)<DataPublisher><KEY><dsk-.*><ID-CERT><>$
+ p-expand \\1
+ }
+ }
+ }
+ }
+
+ rule
+ {
+ id "DataPublisher's ksk signed by the site's ksk"
+ for data
+ filter
+ {
+ type name
+ regex ^[^<DataPublisher><KEY>]*<DataPublisher><KEY><ksk-.*><ID-CERT><>$
+ }
+ checker
+ {
+ type customized
+ sig-type rsa-sha256
+ key-locator
+ {
+ type name
+ hyper-relation
+ {
+ k-regex ^([^<KEY>]*)<KEY><ksk-.*><ID-CERT>$
+ k-expand \\1
+ h-relation equal
+ p-regex ^([^<DataPublisher><KEY>]*)<DataPublisher><KEY><ksk-.*><ID-CERT><>$
+ p-expand \\1
+ }
+ }
+ }
+ }
+
+ rule
+ {
+ id "publishing Hierarchical Rule"
+ for data
+ filter
+ {
+ type name
+ regex ^[^<KEY>]*<KEY><ksk-.*><ID-CERT><>$
+ }
+ checker
+ {
+ type hierarchical
+ sig-type rsa-sha256
+ }
+ }
+
+ trust-anchor
+ {
+ type file
+ file-name /usr/local/etc/ndn/nlsr/keys/cmip5_root.cert ; the file name of trust-anchor
+ }
+
+ }
; The database section contains settings of database
; The user in publishAdapter may differ from the one in queryAdapter, to provide different
@@ -79,8 +163,8 @@
{
dbServer 127.0.0.1 ; Specify the database server
dbName testdb ; Specify the database name
- dbUser testuser2 ; Specify the database user name
- dbPasswd test123 ; Specify the associated password for the dbUser
+ dbUser testuser ; Specify the database user name
+ dbPasswd test623 ; Specify the associated password for the dbUser
}
; The sync section contains settings of ChronoSync
diff --git a/catalog/src/publish/publish-adapter.hpp b/catalog/src/publish/publish-adapter.hpp
index 1d6f91f..c331bf7 100644
--- a/catalog/src/publish/publish-adapter.hpp
+++ b/catalog/src/publish/publish-adapter.hpp
@@ -215,8 +215,11 @@
onFetchUpdateDataTimeout(const ndn::Interest& interest);
void
- onUpdateValidationFailed(const std::shared_ptr<const ndn::Data>& data,
- const std::string& failureInfo);
+ onValidationFailed(const std::shared_ptr<const ndn::Data>& data,
+ const std::string& failureInfo);
+
+ void
+ validatePublishedDataPaylod(const std::shared_ptr<const ndn::Data>& data);
protected:
typedef std::unordered_map<ndn::Name, const ndn::RegisteredPrefixId*> RegisteredPrefixList;
@@ -496,9 +499,9 @@
retrieveInterest->setInterestLifetime(ndn::time::milliseconds(4000));
retrieveInterest->setMustBeFresh(m_mustBeFresh);
m_face->expressInterest(*retrieveInterest,
- bind(&publish::PublishAdapter<DatabaseHandler>::onPublishedData,
+ bind(&PublishAdapter<DatabaseHandler>::onPublishedData,
this,_1, _2),
- bind(&publish::PublishAdapter<DatabaseHandler>::onTimeout, this, _1));
+ bind(&PublishAdapter<DatabaseHandler>::onTimeout, this, _1));
std::cout << "Expressing Interest for: " << retrieveInterest->toUri() << std::endl;
}
@@ -511,6 +514,14 @@
template <typename DatabaseHandler>
void
+PublishAdapter<DatabaseHandler>::onValidationFailed(const std::shared_ptr<const ndn::Data>& data,
+ const std::string& failureInfo)
+{
+ std::cout << "Validation failed: " << data->getName() << failureInfo << std::endl;
+}
+
+template <typename DatabaseHandler>
+void
PublishAdapter<DatabaseHandler>::onPublishedData(const ndn::Interest& interest,
const ndn::Data& data)
{
@@ -518,38 +529,46 @@
if (data.getContent().empty()) {
return;
}
+ m_publishValidator->validate(data,
+ bind(&PublishAdapter<DatabaseHandler>::validatePublishedDataPaylod, this, _1),
+ bind(&PublishAdapter<DatabaseHandler>::onValidationFailed, this, _1, _2));
+}
- std::shared_ptr<ndn::Data> dataPtr = std::make_shared<ndn::Data>(data);
+template <typename DatabaseHandler>
+void
+PublishAdapter<DatabaseHandler>::validatePublishedDataPaylod(const ndn::shared_ptr<const ndn::Data>& data)
+{
// validate published data payload, if failed, return
- if (!validatePublicationChanges(dataPtr)) {
- std::cout << "data validation failed : " << dataPtr->getName() << std::endl;
+ if (!validatePublicationChanges(data)) {
+ std::cout << "data validation failed : " << data->getName() << std::endl;
#ifndef NDEBUG
- const std::string payload(reinterpret_cast<const char*>(dataPtr->getContent().value()),
- dataPtr->getContent().value_size());
+ const std::string payload(reinterpret_cast<const char*>(data->getContent().value()),
+ data->getContent().value_size());
std::cout << payload << std::endl;
#endif
return;
}
// todo: return value to indicate if the insertion succeeds
- processUpdateData(dataPtr);
+ processUpdateData(data);
// ideally, data should not be stale?
- m_socket->publishData(data.getContent(), ndn::time::seconds(3600));
+ m_socket->publishData(data->getContent(), ndn::time::seconds(3600));
// if this is not the final block, continue to fetch the next one
- const ndn::name::Component& finalBlockId = data.getMetaInfo().getFinalBlockId();
- if (finalBlockId == data.getName()[-1]) {
+ const ndn::name::Component& finalBlockId = data->getMetaInfo().getFinalBlockId();
+ if (finalBlockId == data->getName()[-1]) {
m_isFinished = true;
}
//else, get the next segment
if (!m_isFinished) {
- ndn::Name nextInterestName = data.getName().getPrefix(-1);
- uint64_t incomingSegment = data.getName()[-1].toSegment();
- std::cout << " Next Interest Name " << nextInterestName << " Segment " << incomingSegment++
+ ndn::Name nextInterestName = data->getName().getPrefix(-1);
+ uint64_t incomingSegment = data->getName()[-1].toSegment();
+ incomingSegment++;
+ std::cout << " Next Interest Name " << nextInterestName << " Segment " << incomingSegment
<< std::endl;
std::shared_ptr<ndn::Interest> nextInterest =
- std::make_shared<ndn::Interest>(nextInterestName.appendSegment(incomingSegment++));
+ std::make_shared<ndn::Interest>(nextInterestName.appendSegment(incomingSegment));
nextInterest->setInterestLifetime(ndn::time::milliseconds(4000));
nextInterest->setMustBeFresh(m_mustBeFresh);
m_face->expressInterest(*nextInterest,
@@ -697,15 +716,6 @@
template <typename DatabaseHandler>
void
-PublishAdapter<DatabaseHandler>::onUpdateValidationFailed(const
- std::shared_ptr<const ndn::Data>& data,
- const std::string& failureInfo)
-{
- std::cout << "failed to validate Data" << data->getName() << " : " << failureInfo << std::endl;
-}
-
-template <typename DatabaseHandler>
-void
PublishAdapter<DatabaseHandler>::processSyncUpdate(const std::vector<chronosync::MissingDataInfo>&
updates)
{
@@ -725,7 +735,7 @@
if (seq > localSeqNo) {
m_socket->fetchData(updates[i].session, seq,
bind(&PublishAdapter<DatabaseHandler>::processUpdateData,this, _1),
- bind(&PublishAdapter<DatabaseHandler>::onUpdateValidationFailed,
+ bind(&PublishAdapter<DatabaseHandler>::onValidationFailed,
this, _1, _2),
bind(&PublishAdapter<DatabaseHandler>::onFetchUpdateDataTimeout,
this, _1),
diff --git a/catalog/src/query/query-adapter.hpp b/catalog/src/query/query-adapter.hpp
index 2b85da5..0a5ae0b 100644
--- a/catalog/src/query/query-adapter.hpp
+++ b/catalog/src/query/query-adapter.hpp
@@ -144,6 +144,8 @@
* @param resultCount: the number of records in the query results
* @param viewStart: the start index of the record in the query results payload
* @param viewEnd: the end index of the record in the query results payload
+ * @param lastComponent: flag to indicate the content contains the last component for
+ autocompletion query
*/
std::shared_ptr<ndn::Data>
makeReplyData(const ndn::Name& segmentPrefix,
@@ -153,7 +155,8 @@
bool isAutocomplete,
uint64_t resultCount,
uint64_t viewStart,
- uint64_t viewEnd);
+ uint64_t viewEnd,
+ bool lastComponent);
/**
* Helper function that generates query results from a Json query carried in the Interest
@@ -202,7 +205,8 @@
virtual void
prepareSegments(const ndn::Name& segmentPrefix,
const std::string& sqlString,
- bool autocomplete);
+ bool autocomplete,
+ bool lastComponent);
/**
* Helper function to set the DatabaseHandler
@@ -221,12 +225,14 @@
/**
* Helper function that generates the sqlQuery string for autocomplete query
- * @param sqlQuery: stringstream to save the sqlQuery string
- * @param jsonValue: Json value that contains the query information
+ * @param sqlQuery: stringstream to save the sqlQuery string
+ * @param jsonValue: Json value that contains the query information
+ * @param lastComponent: Flag to mark the last component query
*/
bool
json2AutocompletionSql(std::stringstream& sqlQuery,
- Json::Value& jsonValue);
+ Json::Value& jsonValue,
+ bool& lastComponent);
bool
json2PrefixBasedSearchSql(std::stringstream& sqlQuery,
@@ -738,7 +744,8 @@
template <typename DatabaseHandler>
bool
QueryAdapter<DatabaseHandler>::json2AutocompletionSql(std::stringstream& sqlQuery,
- Json::Value& jsonValue)
+ Json::Value& jsonValue,
+ bool& lastComponent)
{
#ifndef NDEBUG
std::cout << "jsonValue in json2AutocompletionSql: " << jsonValue.toStyledString() << std::endl;
@@ -797,6 +804,9 @@
// 2. generate the sql string (append what appears in the typed string, like activity='xxx'),
// return true
+ if (count == m_nameFields.size() - 1)
+ lastComponent = true; // indicate this query is to query the last component
+
bool more = false;
sqlQuery << "SELECT DISTINCT " << m_nameFields[count] << " FROM " << m_databaseTable;
for (std::map<std::string, std::string>::iterator it = typedComponents.begin();
@@ -967,7 +977,7 @@
m_mutex.unlock();
// 3) Convert the JSON Query into a MySQL one
- bool autocomplete = false;
+ bool autocomplete = false, lastComponent = false;
std::stringstream sqlQuery;
ndn::Name segmentPrefix(getQueryResultsName(interest, version));
@@ -977,7 +987,7 @@
// if JSON::Value contains ? as key, is autocompletion
if (parsedFromString.get("?", tmp) != tmp) {
autocomplete = true;
- if (!json2AutocompletionSql(sqlQuery, parsedFromString)) {
+ if (!json2AutocompletionSql(sqlQuery, parsedFromString, lastComponent)) {
sendNack(segmentPrefix);
return;
}
@@ -996,14 +1006,15 @@
}
// 4) Run the Query
- prepareSegments(segmentPrefix, sqlQuery.str(), autocomplete);
+ prepareSegments(segmentPrefix, sqlQuery.str(), autocomplete, lastComponent);
}
template <typename DatabaseHandler>
void
QueryAdapter<DatabaseHandler>::prepareSegments(const ndn::Name& segmentPrefix,
const std::string& sqlString,
- bool autocomplete)
+ bool autocomplete,
+ bool lastComponent)
{
// empty
}
@@ -1013,7 +1024,8 @@
void
QueryAdapter<MYSQL>::prepareSegments(const ndn::Name& segmentPrefix,
const std::string& sqlString,
- bool autocomplete)
+ bool autocomplete,
+ bool lastComponent)
{
#ifndef NDEBUG
std::cout << "prepareSegments() executes sql : " << sqlString << std::endl;
@@ -1057,7 +1069,7 @@
if (tmpString.length() > PAYLOAD_LIMIT) {
std::shared_ptr<ndn::Data> data
= makeReplyData(segmentPrefix, resultJson, segmentNo, false,
- autocomplete, resultCount, viewStart, viewEnd);
+ autocomplete, resultCount, viewStart, viewEnd, lastComponent);
m_mutex.lock();
m_cache.insert(*data);
m_mutex.unlock();
@@ -1072,7 +1084,7 @@
std::shared_ptr<ndn::Data> data
= makeReplyData(segmentPrefix, resultJson, segmentNo, true,
- autocomplete, resultCount, viewStart, viewEnd);
+ autocomplete, resultCount, viewStart, viewEnd, lastComponent);
m_mutex.lock();
m_cache.insert(*data);
m_mutex.unlock();
@@ -1087,7 +1099,8 @@
bool isAutocomplete,
uint64_t resultCount,
uint64_t viewStart,
- uint64_t viewEnd)
+ uint64_t viewEnd,
+ bool lastComponent)
{
Json::Value entry;
Json::FastWriter fastWriter;
@@ -1096,6 +1109,9 @@
entry["viewStart"] = Json::UInt64(viewStart);
entry["viewEnd"] = Json::UInt64(viewEnd);
+ if (lastComponent)
+ entry["lastComponent"] = Json::Value(true);
+
#ifndef NDEBUG
std::cout << "resultCount " << resultCount
<< "; viewStart " << viewStart
diff --git a/catalog/tests/unit-tests/query/test-query-adapter.cpp b/catalog/tests/unit-tests/query/test-query-adapter.cpp
index b49ea03..8b210b7 100644
--- a/catalog/tests/unit-tests/query/test-query-adapter.cpp
+++ b/catalog/tests/unit-tests/query/test-query-adapter.cpp
@@ -101,7 +101,7 @@
uint64_t viewEnd)
{
return makeReplyData(segmentPrefix, value, segmentNo, isFinalBlock,
- isAutocomplete, resultCount, viewStart, viewEnd);
+ isAutocomplete, resultCount, viewStart, viewEnd, false);
}
void
@@ -113,7 +113,8 @@
void
prepareSegments(const ndn::Name& segmentPrefix,
const std::string& sqlString,
- bool autocomplete)
+ bool autocomplete,
+ bool lastComponent)
{
BOOST_CHECK_EQUAL(sqlString, "SELECT name FROM cmip5 WHERE name=\'test\';");
Json::Value fileList;
@@ -122,7 +123,8 @@
fileList.append("/ndn/test3");
std::shared_ptr<ndn::Data> data = makeReplyData(segmentPrefix,
- fileList, 0, true, false, 3, 0, 2);
+ fileList, 0, true, false,
+ 3, 0, 2, lastComponent);
m_mutex.lock();
m_cache.insert(*data);
m_mutex.unlock();
@@ -158,9 +160,10 @@
bool
json2AutocompletionSqlTest(std::stringstream& sqlQuery,
- Json::Value& jsonValue)
+ Json::Value& jsonValue,
+ bool& lastComponent)
{
- return json2AutocompletionSql(sqlQuery, jsonValue);
+ return json2AutocompletionSql(sqlQuery, jsonValue, lastComponent);
}
bool
@@ -505,22 +508,29 @@
std::stringstream ss;
Json::Value testJson;
+ bool lastComponent = false;
testJson["?"] = "/";
- BOOST_CHECK_EQUAL(true, queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson));
+ BOOST_CHECK_EQUAL(true,
+ queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson, lastComponent));
+ BOOST_CHECK_EQUAL(lastComponent, false);
BOOST_CHECK_EQUAL("SELECT DISTINCT activity FROM cmip5;", ss.str());
ss.str("");
ss.clear();
testJson.clear();
testJson["?"] = "/Activity/";
- BOOST_CHECK_EQUAL(true, queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson));
+ BOOST_CHECK_EQUAL(true,
+ queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson, lastComponent));
+ BOOST_CHECK_EQUAL(lastComponent, false);
BOOST_CHECK_EQUAL("SELECT DISTINCT product FROM cmip5 WHERE activity='Activity';", ss.str());
ss.str("");
ss.clear();
testJson.clear();
testJson["?"] = "/Activity/Product/Organization/Model/Experiment/";
- BOOST_CHECK_EQUAL(true, queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson));
+ BOOST_CHECK_EQUAL(true,
+ queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson, lastComponent));
+ BOOST_CHECK_EQUAL(lastComponent, false);
BOOST_CHECK_EQUAL("SELECT DISTINCT frequency FROM cmip5 WHERE activity='Activity' AND \
experiment='Experiment' AND model='Model' AND organization='Organization' AND product='Product';",
ss.str());
@@ -530,7 +540,9 @@
testJson.clear();
testJson["?"] = "/Activity/Product/Organization/Model/Experiment/Frequency/Modeling/\
Variable/Ensemble/";
- BOOST_CHECK_EQUAL(true, queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson));
+ BOOST_CHECK_EQUAL(true,
+ queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson, lastComponent));
+ BOOST_CHECK_EQUAL(lastComponent, true);
BOOST_CHECK_EQUAL("SELECT DISTINCT time FROM cmip5 WHERE activity='Activity' AND ensemble=\
'Ensemble' AND experiment='Experiment' AND frequency='Frequency' AND model='Model' AND \
modeling_realm='Modeling' AND organization='Organization' AND product='Product' AND variable_name=\
@@ -543,26 +555,31 @@
std::stringstream ss;
Json::Value testJson;
+ bool lastComponent = false;
testJson["?"] = "serchTest";
- BOOST_CHECK_EQUAL(false, queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson));
+ BOOST_CHECK_EQUAL(false,
+ queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson, lastComponent));
ss.str("");
ss.clear();
testJson.clear();
testJson["?"] = "/cmip5";
- BOOST_CHECK_EQUAL(false, queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson));
+ BOOST_CHECK_EQUAL(false,
+ queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson, lastComponent));
ss.str("");
ss.clear();
Json::Value testJson2; //simply clear does not work
testJson2[0] = "test";
- BOOST_CHECK_EQUAL(false, queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson2));
+ BOOST_CHECK_EQUAL(false,
+ queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson2, lastComponent));
ss.str("");
ss.clear();
Json::Value testJson3;
testJson3 = Json::Value(Json::arrayValue);
- BOOST_CHECK_EQUAL(false, queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson3));
+ BOOST_CHECK_EQUAL(false,
+ queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson3, lastComponent));
ss.str("");
ss.clear();
@@ -570,7 +587,8 @@
Json::Value param;
param[0] = "test";
testJson4["name"] = param;
- BOOST_CHECK_EQUAL(false, queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson4));
+ BOOST_CHECK_EQUAL(false,
+ queryAdapterTest2.json2AutocompletionSqlTest(ss, testJson4, lastComponent));
}
BOOST_AUTO_TEST_CASE(QueryAdapterPrefixBasedSearchSuccessTest)
diff --git a/tools/cxx-producer.cpp b/tools/cxx-producer.cpp
index c0f028f..31e3679 100644
--- a/tools/cxx-producer.cpp
+++ b/tools/cxx-producer.cpp
@@ -33,6 +33,7 @@
" [-c catalogPrefix] - set the catalog prefix\n"
" [-f name list file] - set the file that contains name list\n"
" [-n namespace] - set the publisher namespace\n"
+ " [-i signingId] - set the publisher signing ID\n"
" [-h] - print help and exit\n"
"\n";
}
@@ -90,11 +91,15 @@
data->setContent(reinterpret_cast<const uint8_t*>(payload), payLoadLength);
// Sign Data packet with default identity
- m_keyChain.sign(*data);
+ if (m_signingId.empty())
+ m_keyChain.sign(*data);
+ else
+ m_keyChain.signByIdentity(*data, m_signingId);
+
+ std::cout << ">> D: " << *data << std::endl;
// Return Data packet to the requester
- std::cout << ">> D: " << *data << std::endl;
- m_face.put(*data);
+ m_face.put(*data);
m_face.shutdown();
}
@@ -139,6 +144,7 @@
std::string m_jsonFile;
std::string m_namespace;
std::string m_catalogPrefix;
+ ndn::Name m_signingId;
private:
Face m_face;
@@ -158,16 +164,19 @@
return 0;
}
- while ((option = getopt(argc, argv, "c:f:n:h")) != -1) {
+ while ((option = getopt(argc, argv, "c:f:n:i:h")) != -1) {
switch (option) {
case 'c':
- producer.m_catalogPrefix.assign(optarg);
+ producer.m_catalogPrefix = optarg;
break;
case 'f':
- producer.m_jsonFile.assign(optarg);
+ producer.m_jsonFile = optarg;
break;
case 'n':
- producer.m_namespace.assign(optarg);
+ producer.m_namespace = optarg;
+ break;
+ case 'i':
+ producer.m_signingId = ndn::Name(optarg);
break;
case 'h':
default: