blob: adba2537a9f7a994db0f1b939c1c4f385a759168 [file] [log] [blame]
Davide Pesavento912d2e82019-01-10 17:04:31 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2014-2019, Arizona Board of Regents.
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -08004 *
Davide Pesaventod0b59982015-02-27 19:15:15 +01005 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080017 *
18 * Author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
19 */
20
Davide Pesavento912d2e82019-01-10 17:04:31 -050021#include "logger.hpp"
Davide Pesavento35185332019-01-14 04:00:15 -050022#include "util.hpp"
23
24#include <ndn-cxx/face.hpp>
25#include <ndn-cxx/name.hpp>
26#include <ndn-cxx/lp/tags.hpp>
27#include <ndn-cxx/util/backports.hpp>
28#include <ndn-cxx/util/random.hpp>
Davide Pesavento912d2e82019-01-10 17:04:31 -050029
Davide Pesaventod0b59982015-02-27 19:15:15 +010030#include <cctype>
Davide Pesavento35185332019-01-14 04:00:15 -050031#include <limits>
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080032#include <vector>
33
Davide Pesavento912d2e82019-01-10 17:04:31 -050034#include <boost/asio/deadline_timer.hpp>
35#include <boost/asio/io_service.hpp>
36#include <boost/asio/signal_set.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070037#include <boost/date_time/posix_time/posix_time.hpp>
Davide Pesavento912d2e82019-01-10 17:04:31 -050038#include <boost/lexical_cast.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050039#include <boost/logic/tribool.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070040#include <boost/noncopyable.hpp>
Davide Pesavento35185332019-01-14 04:00:15 -050041#include <boost/program_options/options_description.hpp>
42#include <boost/program_options/parsers.hpp>
43#include <boost/program_options/variables_map.hpp>
jeraldabraham420dbf02014-04-25 22:58:31 -070044
Davide Pesavento35185332019-01-14 04:00:15 -050045namespace po = boost::program_options;
jeraldabraham420dbf02014-04-25 22:58:31 -070046
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080047namespace ndn {
48
jeraldabraham420dbf02014-04-25 22:58:31 -070049class NdnTrafficClient : boost::noncopyable
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080050{
51public:
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070052 explicit
Davide Pesavento35185332019-01-14 04:00:15 -050053 NdnTrafficClient(const std::string& configFile)
54 : m_signalSet(m_ioService, SIGINT, SIGTERM)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070055 , m_logger("NdnTrafficClient")
Alexander Afanasyev740812e2014-10-30 15:37:45 -070056 , m_face(m_ioService)
Davide Pesavento35185332019-01-14 04:00:15 -050057 , m_configurationFile(configFile)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080058 {
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080059 }
60
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070061 bool
62 hasError() const
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080063 {
jeraldabrahamcc3c6c92014-03-28 02:21:45 -070064 return m_hasError;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080065 }
66
67 void
Davide Pesavento35185332019-01-14 04:00:15 -050068 setMaximumInterests(uint64_t maxInterests)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080069 {
Davide Pesavento35185332019-01-14 04:00:15 -050070 m_nMaximumInterests = maxInterests;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080071 }
72
73 void
Davide Pesavento35185332019-01-14 04:00:15 -050074 setInterestInterval(time::milliseconds interval)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080075 {
Davide Pesavento35185332019-01-14 04:00:15 -050076 BOOST_ASSERT(interval > 0_ms);
77 m_interestInterval = interval;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080078 }
79
80 void
jeraldabraham420dbf02014-04-25 22:58:31 -070081 setQuietLogging()
82 {
Davide Pesavento35185332019-01-14 04:00:15 -050083 m_wantQuiet = true;
jeraldabraham420dbf02014-04-25 22:58:31 -070084 }
85
86 void
Davide Pesavento35185332019-01-14 04:00:15 -050087 run()
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -080088 {
Davide Pesavento35185332019-01-14 04:00:15 -050089 m_logger.initializeLog(to_string(random::generateWord32()));
90 initializeTrafficConfiguration();
Davide Pesaventod0b59982015-02-27 19:15:15 +010091
Davide Pesavento35185332019-01-14 04:00:15 -050092 if (m_nMaximumInterests == 0) {
93 logStatistics();
94 return;
95 }
Davide Pesaventod0b59982015-02-27 19:15:15 +010096
Davide Pesavento35185332019-01-14 04:00:15 -050097 m_signalSet.async_wait([this] (auto&&...) { this->stop(); });
98
99 boost::asio::deadline_timer timer(m_ioService,
100 boost::posix_time::millisec(m_interestInterval.count()));
101 timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
102
103 try {
104 m_face.processEvents();
105 }
106 catch (const std::exception& e) {
107 m_logger.log("ERROR: "s + e.what(), true, true);
108 m_hasError = true;
109 m_ioService.stop();
110 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800111 }
112
Davide Pesavento35185332019-01-14 04:00:15 -0500113private:
114 class InterestTrafficConfiguration
115 {
116 public:
117 void
118 printTrafficConfiguration(Logger& logger) const
119 {
120 std::string detail;
121
122 detail += "TrafficPercentage=" + to_string(m_trafficPercentage) + ", ";
123 if (!m_name.empty())
124 detail += "Name=" + m_name + ", ";
125 if (m_nameAppendBytes)
126 detail += "NameAppendBytes=" + to_string(*m_nameAppendBytes) + ", ";
127 if (m_nameAppendSeqNum)
128 detail += "NameAppendSequenceNumber=" + to_string(*m_nameAppendSeqNum) + ", ";
129 if (!boost::logic::indeterminate(m_mustBeFresh))
130 detail += "MustBeFresh=" + to_string(bool(m_mustBeFresh)) + ", ";
131 if (m_nonceDuplicationPercentage > 0)
132 detail += "NonceDuplicationPercentage=" + to_string(m_nonceDuplicationPercentage) + ", ";
133 if (m_interestLifetime >= 0_ms)
134 detail += "InterestLifetime=" + to_string(m_interestLifetime.count()) + ", ";
135 if (m_nextHopFaceId > 0)
136 detail += "NextHopFaceId=" + to_string(m_nextHopFaceId) + ", ";
137 if (m_expectedContent)
138 detail += "ExpectedContent=" + *m_expectedContent + ", ";
139 if (detail.length() >= 2)
140 detail = detail.substr(0, detail.length() - 2); // Removing suffix ", "
141
142 logger.log(detail, false, false);
143 }
144
145 bool
146 processConfigurationDetail(const std::string& detail, Logger& logger, int lineNumber)
147 {
148 std::string parameter, value;
149 if (parseParameterAndValue(detail, parameter, value)) {
150 if (parameter == "TrafficPercentage")
151 m_trafficPercentage = std::stoul(value);
152 else if (parameter == "Name")
153 m_name = value;
154 else if (parameter == "NameAppendBytes")
155 m_nameAppendBytes = std::stoul(value);
156 else if (parameter == "NameAppendSequenceNumber")
157 m_nameAppendSeqNum = std::stoull(value);
158 else if (parameter == "MustBeFresh")
159 m_mustBeFresh = bool(std::stoul(value));
160 else if (parameter == "NonceDuplicationPercentage")
161 m_nonceDuplicationPercentage = std::stoul(value);
162 else if (parameter == "InterestLifetime")
163 m_interestLifetime = time::milliseconds(std::stoul(value));
164 else if (parameter == "NextHopFaceId")
165 m_nextHopFaceId = std::stoull(value);
166 else if (parameter == "ExpectedContent")
167 m_expectedContent = value;
168 else
169 logger.log("Line " + to_string(lineNumber) +
170 " - Unknown parameter '" + parameter + "'", false, true);
171 }
172 else {
173 logger.log("Line " + to_string(lineNumber) +
174 " - Invalid traffic configuration line: " + detail, false, true);
175 return false;
176 }
177 return true;
178 }
179
180 bool
181 checkTrafficDetailCorrectness() const
182 {
183 return true;
184 }
185
186 public:
187 uint8_t m_trafficPercentage = 0;
188 std::string m_name;
189 optional<std::size_t> m_nameAppendBytes;
190 optional<uint64_t> m_nameAppendSeqNum;
191 boost::logic::tribool m_mustBeFresh = boost::logic::indeterminate;
192 uint8_t m_nonceDuplicationPercentage = 0;
193 time::milliseconds m_interestLifetime = -1_ms;
194 uint64_t m_nextHopFaceId = 0;
195 optional<std::string> m_expectedContent;
196
197 uint64_t m_nInterestsSent = 0;
198 uint64_t m_nInterestsReceived = 0;
199 uint64_t m_nNacks = 0;
200 uint64_t m_nContentInconsistencies = 0;
201
202 // RTT is stored as milliseconds with fractional sub-milliseconds precision
203 double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
204 double m_maximumInterestRoundTripTime = 0;
205 double m_totalInterestRoundTripTime = 0;
206 };
207
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800208 void
209 logStatistics()
210 {
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800211 m_logger.log("\n\n== Interest Traffic Report ==\n", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700212 m_logger.log("Total Traffic Pattern Types = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500213 to_string(m_trafficPatterns.size()), false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700214 m_logger.log("Total Interests Sent = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500215 to_string(m_nInterestsSent), false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700216 m_logger.log("Total Responses Received = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500217 to_string(m_nInterestsReceived), false, true);
Eric Newberry976c2042016-06-19 23:37:35 -0700218 m_logger.log("Total Nacks Received = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500219 to_string(m_nNacks), false, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100220
Davide Pesavento35185332019-01-14 04:00:15 -0500221 double loss = 0.0;
222 if (m_nInterestsSent > 0) {
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700223 loss = (m_nInterestsSent - m_nInterestsReceived) * 100.0 / m_nInterestsSent;
Davide Pesavento35185332019-01-14 04:00:15 -0500224 }
Spencer Lee8e990232015-11-27 03:54:39 -0700225 m_logger.log("Total Interest Loss = " + to_string(loss) + "%", false, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100226
Davide Pesavento35185332019-01-14 04:00:15 -0500227 double average = 0.0;
228 double inconsistency = 0.0;
229 if (m_nInterestsReceived > 0) {
230 average = m_totalInterestRoundTripTime / m_nInterestsReceived;
231 inconsistency = m_nContentInconsistencies * 100.0 / m_nInterestsReceived;
232 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700233 m_logger.log("Total Data Inconsistency = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500234 to_string(inconsistency) + "%", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700235 m_logger.log("Total Round Trip Time = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500236 to_string(m_totalInterestRoundTripTime) + "ms", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700237 m_logger.log("Average Round Trip Time = " +
Davide Pesavento35185332019-01-14 04:00:15 -0500238 to_string(average) + "ms\n", false, true);
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700239
Davide Pesavento35185332019-01-14 04:00:15 -0500240 for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
241 m_logger.log("Traffic Pattern Type #" + to_string(patternId + 1), false, true);
242 m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
243 m_logger.log("Total Interests Sent = " +
244 to_string(m_trafficPatterns[patternId].m_nInterestsSent), false, true);
245 m_logger.log("Total Responses Received = " +
246 to_string(m_trafficPatterns[patternId].m_nInterestsReceived), false, true);
247 m_logger.log("Total Nacks Received = " +
248 to_string(m_trafficPatterns[patternId].m_nNacks), false, true);
249 loss = 0;
250 if (m_trafficPatterns[patternId].m_nInterestsSent > 0) {
251 loss = (m_trafficPatterns[patternId].m_nInterestsSent -
252 m_trafficPatterns[patternId].m_nInterestsReceived);
253 loss *= 100.0;
254 loss /= m_trafficPatterns[patternId].m_nInterestsSent;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800255 }
Davide Pesavento35185332019-01-14 04:00:15 -0500256 m_logger.log("Total Interest Loss = " + to_string(loss) + "%", false, true);
257 average = 0;
258 inconsistency = 0;
259 if (m_trafficPatterns[patternId].m_nInterestsReceived > 0) {
260 average = (m_trafficPatterns[patternId].m_totalInterestRoundTripTime /
261 m_trafficPatterns[patternId].m_nInterestsReceived);
262 inconsistency = m_trafficPatterns[patternId].m_nContentInconsistencies;
263 inconsistency *= 100.0 / m_trafficPatterns[patternId].m_nInterestsReceived;
264 }
265 m_logger.log("Total Data Inconsistency = " + to_string(inconsistency) + "%", false, true);
266 m_logger.log("Total Round Trip Time = " +
267 to_string(m_trafficPatterns[patternId].m_totalInterestRoundTripTime) + "ms", false, true);
268 m_logger.log("Average Round Trip Time = " + to_string(average) + "ms\n", false, true);
269 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800270 }
271
272 bool
Davide Pesavento35185332019-01-14 04:00:15 -0500273 checkTrafficPatternCorrectness() const
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800274 {
275 return true;
276 }
277
278 void
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700279 parseConfigurationFile()
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800280 {
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800281 std::ifstream patternFile;
Davide Pesavento35185332019-01-14 04:00:15 -0500282 m_logger.log("Parsing traffic configuration file: " + m_configurationFile, true, true);
Davide Pesaventod0b59982015-02-27 19:15:15 +0100283
Davide Pesavento35185332019-01-14 04:00:15 -0500284 patternFile.open(m_configurationFile.data());
285 if (patternFile.is_open()) {
286 int lineNumber = 0;
287 std::string patternLine;
288 while (getline(patternFile, patternLine)) {
289 lineNumber++;
290 if (std::isalpha(patternLine[0])) {
291 InterestTrafficConfiguration interestData;
292 bool shouldSkipLine = false;
293 if (interestData.processConfigurationDetail(patternLine, m_logger, lineNumber)) {
294 while (getline(patternFile, patternLine) && std::isalpha(patternLine[0])) {
295 lineNumber++;
296 if (!interestData.processConfigurationDetail(patternLine, m_logger, lineNumber)) {
297 shouldSkipLine = true;
298 break;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800299 }
Davide Pesavento35185332019-01-14 04:00:15 -0500300 }
301 lineNumber++;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800302 }
Davide Pesavento35185332019-01-14 04:00:15 -0500303 else {
304 shouldSkipLine = true;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800305 }
Davide Pesavento35185332019-01-14 04:00:15 -0500306 if (!shouldSkipLine) {
307 if (interestData.checkTrafficDetailCorrectness()) {
308 m_trafficPatterns.push_back(interestData);
309 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800310 }
Davide Pesavento35185332019-01-14 04:00:15 -0500311 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800312 }
Davide Pesavento35185332019-01-14 04:00:15 -0500313 patternFile.close();
314
315 if (!checkTrafficPatternCorrectness()) {
316 m_logger.log("ERROR: Traffic configuration provided is not proper - " +
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700317 m_configurationFile, false, true);
Davide Pesavento35185332019-01-14 04:00:15 -0500318 exit(2);
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800319 }
Davide Pesavento35185332019-01-14 04:00:15 -0500320
321 m_logger.log("Traffic configuration file processing completed.\n", true, false);
322 for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
323 m_logger.log("Traffic Pattern Type #" + to_string(patternId + 1), false, false);
324 m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
325 m_logger.log("", false, false);
326 }
327 }
328 else {
329 m_logger.log("ERROR: Unable to open traffic configuration file: " + m_configurationFile, false, true);
330 exit(2);
331 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800332 }
333
334 void
335 initializeTrafficConfiguration()
336 {
Davide Pesavento35185332019-01-14 04:00:15 -0500337 namespace fs = boost::filesystem;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800338
Davide Pesavento35185332019-01-14 04:00:15 -0500339 fs::path configPath(m_configurationFile);
340 if (fs::exists(configPath)) {
341 if (fs::is_regular_file(configPath)) {
342 parseConfigurationFile();
343 }
344 else {
345 m_logger.log("ERROR: Traffic configuration file is not a regular file: " +
346 m_configurationFile, false, true);
347 exit(2);
348 }
349 }
350 else {
351 m_logger.log("ERROR: Traffic configuration file does not exist: " +
352 m_configurationFile, false, true);
353 exit(2);
354 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800355 }
356
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700357 uint32_t
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800358 getNewNonce()
359 {
Davide Pesavento35185332019-01-14 04:00:15 -0500360 if (m_nonces.size() >= 1000)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700361 m_nonces.clear();
jeraldabraham473ef3d2014-03-06 12:40:35 -0700362
Davide Pesavento35185332019-01-14 04:00:15 -0500363 auto randomNonce = random::generateWord32();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700364 while (std::find(m_nonces.begin(), m_nonces.end(), randomNonce) != m_nonces.end())
Davide Pesavento35185332019-01-14 04:00:15 -0500365 randomNonce = random::generateWord32();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700366
367 m_nonces.push_back(randomNonce);
368 return randomNonce;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800369 }
370
Davide Pesavento35185332019-01-14 04:00:15 -0500371 uint32_t
372 getOldNonce()
373 {
374 if (m_nonces.empty())
375 return getNewNonce();
376
377 std::uniform_int_distribution<std::size_t> dist(0, m_nonces.size() - 1);
378 return m_nonces[dist(random::getRandomNumberEngine())];
379 }
380
Eric Newberry3b284192015-07-06 21:44:46 -0700381 static name::Component
Davide Pesavento912d2e82019-01-10 17:04:31 -0500382 generateRandomNameComponent(std::size_t length)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800383 {
Davide Pesavento35185332019-01-14 04:00:15 -0500384 // per ISO C++ std, cannot instantiate uniform_int_distribution with uint8_t
385 static std::uniform_int_distribution<unsigned short> dist(std::numeric_limits<uint8_t>::min(),
386 std::numeric_limits<uint8_t>::max());
387
388 Buffer buf(length);
Davide Pesavento912d2e82019-01-10 17:04:31 -0500389 for (std::size_t i = 0; i < length; i++) {
Davide Pesavento35185332019-01-14 04:00:15 -0500390 buf[i] = static_cast<uint8_t>(dist(random::getRandomNumberEngine()));
Eric Newberry3b284192015-07-06 21:44:46 -0700391 }
Davide Pesavento35185332019-01-14 04:00:15 -0500392 return name::Component(buf);
393 }
394
395 Interest
396 prepareInterest(std::size_t patternId)
397 {
398 Interest interest;
399 auto& pattern = m_trafficPatterns[patternId];
400
401 Name name(pattern.m_name);
402 if (pattern.m_nameAppendBytes > 0) {
403 name.append(generateRandomNameComponent(*pattern.m_nameAppendBytes));
404 }
405 if (pattern.m_nameAppendSeqNum) {
406 auto seqNum = *pattern.m_nameAppendSeqNum;
407 name.appendSequenceNumber(seqNum);
408 pattern.m_nameAppendSeqNum = seqNum + 1;
409 }
410 interest.setName(name);
411
412 if (pattern.m_mustBeFresh)
413 interest.setMustBeFresh(true);
414 else if (!pattern.m_mustBeFresh)
415 interest.setMustBeFresh(false);
416
417 static std::uniform_int_distribution<> duplicateNonceDist(1, 100);
418 if (duplicateNonceDist(random::getRandomNumberEngine()) <= pattern.m_nonceDuplicationPercentage)
419 interest.setNonce(getOldNonce());
420 else
421 interest.setNonce(getNewNonce());
422
423 if (pattern.m_interestLifetime >= 0_ms)
424 interest.setInterestLifetime(pattern.m_interestLifetime);
425
426 if (pattern.m_nextHopFaceId > 0)
427 interest.setTag(make_shared<lp::NextHopFaceIdTag>(pattern.m_nextHopFaceId));
428
429 return interest;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800430 }
431
432 void
Davide Pesavento35185332019-01-14 04:00:15 -0500433 onData(const Data& data, int globalRef, int localRef, std::size_t patternId,
434 const time::steady_clock::TimePoint& sentTime)
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800435 {
Davide Pesavento35185332019-01-14 04:00:15 -0500436 auto logLine = "Data Received - PatternType=" + to_string(patternId + 1) +
437 ", GlobalID=" + to_string(globalRef) +
438 ", LocalID=" + to_string(localRef) +
439 ", Name=" + data.getName().toUri();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700440
441 m_nInterestsReceived++;
442 m_trafficPatterns[patternId].m_nInterestsReceived++;
Davide Pesavento35185332019-01-14 04:00:15 -0500443
444 if (m_trafficPatterns[patternId].m_expectedContent) {
445 std::string receivedContent(reinterpret_cast<const char*>(data.getContent().value()),
446 data.getContent().value_size());
447 if (receivedContent != *m_trafficPatterns[patternId].m_expectedContent) {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500448 m_nContentInconsistencies++;
449 m_trafficPatterns[patternId].m_nContentInconsistencies++;
450 logLine += ", IsConsistent=No";
jeraldabraham473ef3d2014-03-06 12:40:35 -0700451 }
Davide Pesavento35185332019-01-14 04:00:15 -0500452 else {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500453 logLine += ", IsConsistent=Yes";
Davide Pesavento35185332019-01-14 04:00:15 -0500454 }
Davide Pesavento912d2e82019-01-10 17:04:31 -0500455 }
Davide Pesavento35185332019-01-14 04:00:15 -0500456 else {
jeraldabraham473ef3d2014-03-06 12:40:35 -0700457 logLine += ", IsConsistent=NotChecked";
Davide Pesavento35185332019-01-14 04:00:15 -0500458 }
459 if (!m_wantQuiet) {
jeraldabraham420dbf02014-04-25 22:58:31 -0700460 m_logger.log(logLine, true, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500461 }
462
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700463 double roundTripTime = (time::steady_clock::now() - sentTime).count() / 1000000.0;
464 if (m_minimumInterestRoundTripTime > roundTripTime)
465 m_minimumInterestRoundTripTime = roundTripTime;
466 if (m_maximumInterestRoundTripTime < roundTripTime)
467 m_maximumInterestRoundTripTime = roundTripTime;
468 if (m_trafficPatterns[patternId].m_minimumInterestRoundTripTime > roundTripTime)
469 m_trafficPatterns[patternId].m_minimumInterestRoundTripTime = roundTripTime;
470 if (m_trafficPatterns[patternId].m_maximumInterestRoundTripTime < roundTripTime)
471 m_trafficPatterns[patternId].m_maximumInterestRoundTripTime = roundTripTime;
472 m_totalInterestRoundTripTime += roundTripTime;
473 m_trafficPatterns[patternId].m_totalInterestRoundTripTime += roundTripTime;
Davide Pesavento35185332019-01-14 04:00:15 -0500474
475 if (m_nMaximumInterests == globalRef) {
476 stop();
Davide Pesavento912d2e82019-01-10 17:04:31 -0500477 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700478 }
479
480 void
Davide Pesavento35185332019-01-14 04:00:15 -0500481 onNack(const Interest& interest, const lp::Nack& nack,
482 int globalRef, int localRef, std::size_t patternId)
Eric Newberry976c2042016-06-19 23:37:35 -0700483 {
Davide Pesavento35185332019-01-14 04:00:15 -0500484 auto logLine = "Interest Nack'd - PatternType=" + to_string(patternId + 1) +
485 ", GlobalID=" + to_string(globalRef) +
486 ", LocalID=" + to_string(localRef) +
487 ", Name=" + interest.getName().toUri() +
488 ", NackReason=" + boost::lexical_cast<std::string>(nack.getReason());
Eric Newberry976c2042016-06-19 23:37:35 -0700489 m_logger.log(logLine, true, false);
490
491 m_nNacks++;
492 m_trafficPatterns[patternId].m_nNacks++;
493
Davide Pesavento35185332019-01-14 04:00:15 -0500494 if (m_nMaximumInterests == globalRef) {
495 stop();
Eric Newberry976c2042016-06-19 23:37:35 -0700496 }
497 }
498
499 void
Davide Pesavento35185332019-01-14 04:00:15 -0500500 onTimeout(const Interest& interest, int globalRef, int localRef, int patternId)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700501 {
Davide Pesavento35185332019-01-14 04:00:15 -0500502 auto logLine = "Interest Timed Out - PatternType=" + to_string(patternId + 1) +
503 ", GlobalID=" + to_string(globalRef) +
504 ", LocalID=" + to_string(localRef) +
505 ", Name=" + interest.getName().toUri();
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700506 m_logger.log(logLine, true, false);
Davide Pesavento35185332019-01-14 04:00:15 -0500507
508 if (m_nMaximumInterests == globalRef) {
509 stop();
510 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700511 }
512
513 void
Davide Pesavento35185332019-01-14 04:00:15 -0500514 generateTraffic(boost::asio::deadline_timer& timer)
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700515 {
Davide Pesavento35185332019-01-14 04:00:15 -0500516 if (m_nMaximumInterests && m_nInterestsSent >= *m_nMaximumInterests) {
Davide Pesavento912d2e82019-01-10 17:04:31 -0500517 return;
518 }
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700519
Davide Pesavento35185332019-01-14 04:00:15 -0500520 static std::uniform_int_distribution<> trafficDist(1, 100);
521 int trafficKey = trafficDist(random::getRandomNumberEngine());
Davide Pesaventod0b59982015-02-27 19:15:15 +0100522
Davide Pesavento35185332019-01-14 04:00:15 -0500523 int cumulativePercentage = 0;
524 std::size_t patternId = 0;
525 for (; patternId < m_trafficPatterns.size(); patternId++) {
526 cumulativePercentage += m_trafficPatterns[patternId].m_trafficPercentage;
527 if (trafficKey <= cumulativePercentage) {
528 auto interest = prepareInterest(patternId);
529 try {
530 m_nInterestsSent++;
531 m_trafficPatterns[patternId].m_nInterestsSent++;
532 auto sentTime = time::steady_clock::now();
533 m_face.expressInterest(interest,
534 bind(&NdnTrafficClient::onData, this, _2, m_nInterestsSent,
535 m_trafficPatterns[patternId].m_nInterestsSent, patternId, sentTime),
536 bind(&NdnTrafficClient::onNack, this, _1, _2, m_nInterestsSent,
537 m_trafficPatterns[patternId].m_nInterestsSent, patternId),
538 bind(&NdnTrafficClient::onTimeout, this, _1, m_nInterestsSent,
539 m_trafficPatterns[patternId].m_nInterestsSent, patternId));
540
541 if (!m_wantQuiet) {
542 auto logLine = "Sending Interest - PatternType=" + to_string(patternId + 1) +
543 ", GlobalID=" + to_string(m_nInterestsSent) +
544 ", LocalID=" + to_string(m_trafficPatterns[patternId].m_nInterestsSent) +
545 ", Name=" + interest.getName().toUri();
546 m_logger.log(logLine, true, false);
547 }
548
549 timer.expires_at(timer.expires_at() +
550 boost::posix_time::millisec(m_interestInterval.count()));
551 timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
552 }
553 catch (const std::exception& e) {
554 m_logger.log("ERROR: "s + e.what(), true, true);
555 }
556 break;
557 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800558 }
Davide Pesavento35185332019-01-14 04:00:15 -0500559 if (patternId == m_trafficPatterns.size()) {
560 timer.expires_at(timer.expires_at() +
561 boost::posix_time::millisec(m_interestInterval.count()));
562 timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800563 }
564 }
565
Davide Pesavento35185332019-01-14 04:00:15 -0500566 void
567 stop()
568 {
569 if (m_nContentInconsistencies > 0 || m_nInterestsSent != m_nInterestsReceived) {
570 m_hasError = true;
571 }
572
573 logStatistics();
574 m_face.shutdown();
575 m_ioService.stop();
576 }
577
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800578private:
Alexander Afanasyev976c3972014-05-26 17:03:40 +0300579 boost::asio::io_service m_ioService;
Davide Pesavento35185332019-01-14 04:00:15 -0500580 boost::asio::signal_set m_signalSet;
581 Logger m_logger;
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700582 Face m_face;
Davide Pesavento35185332019-01-14 04:00:15 -0500583
584 std::string m_configurationFile;
585 optional<uint64_t> m_nMaximumInterests;
586 time::milliseconds m_interestInterval = 1_s;
587 bool m_wantQuiet = false;
588
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700589 std::vector<InterestTrafficConfiguration> m_trafficPatterns;
590 std::vector<uint32_t> m_nonces;
Davide Pesavento35185332019-01-14 04:00:15 -0500591 uint64_t m_nInterestsSent = 0;
592 uint64_t m_nInterestsReceived = 0;
593 uint64_t m_nNacks = 0;
594 uint64_t m_nContentInconsistencies = 0;
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700595
Davide Pesavento912d2e82019-01-10 17:04:31 -0500596 // RTT is stored as milliseconds with fractional sub-milliseconds precision
Davide Pesavento35185332019-01-14 04:00:15 -0500597 double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
598 double m_maximumInterestRoundTripTime = 0;
599 double m_totalInterestRoundTripTime = 0;
600
601 bool m_hasError = false;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800602};
603
604} // namespace ndn
605
Davide Pesavento35185332019-01-14 04:00:15 -0500606static void
607usage(std::ostream& os, const std::string& programName, const po::options_description& desc)
608{
609 os << "Usage: " << programName << " [options] <Traffic_Configuration_File>\n"
610 << "\n"
611 << "Generate Interest traffic as per provided Traffic_Configuration_File.\n"
612 << "Interests are continuously generated unless a total number is specified.\n"
613 << "Set the environment variable NDN_TRAFFIC_LOGFOLDER to redirect output to a log file.\n"
614 << "\n"
615 << desc;
616}
617
jeraldabrahamcc3c6c92014-03-28 02:21:45 -0700618int
619main(int argc, char* argv[])
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800620{
Davide Pesavento35185332019-01-14 04:00:15 -0500621 std::string configFile;
Davide Pesaventod0b59982015-02-27 19:15:15 +0100622
Davide Pesavento35185332019-01-14 04:00:15 -0500623 po::options_description visibleOptions("Options");
624 visibleOptions.add_options()
625 ("help,h", "print this help message and exit")
626 ("count,c", po::value<int>(), "total number of Interests to be generated")
627 ("interval,i", po::value<ndn::time::milliseconds::rep>()->default_value(1000),
628 "Interest generation interval in milliseconds")
629 ("quiet,q", po::bool_switch(), "turn off logging of Interest generation/Data reception")
630 ;
631
632 po::options_description hiddenOptions;
633 hiddenOptions.add_options()
634 ("config-file", po::value<std::string>(&configFile))
635 ;
636
637 po::positional_options_description posOptions;
638 posOptions.add("config-file", -1);
639
640 po::options_description allOptions;
641 allOptions.add(visibleOptions).add(hiddenOptions);
642
643 po::variables_map vm;
644 try {
645 po::store(po::command_line_parser(argc, argv).options(allOptions).positional(posOptions).run(), vm);
646 po::notify(vm);
647 }
648 catch (const po::error& e) {
649 std::cerr << "ERROR: " << e.what() << std::endl;
650 return 2;
651 }
652 catch (const boost::bad_any_cast& e) {
653 std::cerr << "ERROR: " << e.what() << std::endl;
654 return 2;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800655 }
656
Davide Pesavento35185332019-01-14 04:00:15 -0500657 if (vm.count("help") > 0) {
658 usage(std::cout, argv[0], visibleOptions);
659 return 0;
660 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800661
Davide Pesavento35185332019-01-14 04:00:15 -0500662 if (configFile.empty()) {
663 usage(std::cerr, argv[0], visibleOptions);
664 return 2;
665 }
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800666
Davide Pesavento35185332019-01-14 04:00:15 -0500667 ndn::NdnTrafficClient client(configFile);
668
669 if (vm.count("count") > 0) {
670 int count = vm["count"].as<int>();
671 if (count < 0) {
672 std::cerr << "ERROR: the argument for option '--count' cannot be negative" << std::endl;
673 return 2;
674 }
675 client.setMaximumInterests(static_cast<uint64_t>(count));
676 }
677
678 if (vm.count("interval") > 0) {
679 ndn::time::milliseconds interval(vm["interval"].as<ndn::time::milliseconds::rep>());
680 if (interval <= ndn::time::milliseconds::zero()) {
681 std::cerr << "ERROR: the argument for option '--interval' must be positive" << std::endl;
682 return 2;
683 }
684 client.setInterestInterval(interval);
685 }
686
687 if (vm["quiet"].as<bool>()) {
688 client.setQuietLogging();
689 }
690
Davide Pesaventod0b59982015-02-27 19:15:15 +0100691 client.run();
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800692
Davide Pesavento35185332019-01-14 04:00:15 -0500693 return client.hasError() ? 1 : 0;
Alexander Afanasyeva8f2a922014-02-26 14:21:56 -0800694}