blob: a26b1b1f5510dda7e3798621e27483f70d8440cf [file] [log] [blame]
Eric Newberry4164b8e2015-04-23 17:29:18 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Arizona Board of Regents.
4 *
5 * This file is part of ndn-tools (Named Data Networking Essential Tools).
6 * See AUTHORS.md for complete list of ndn-tools authors and contributors.
7 *
8 * ndn-tools is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * @author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
20 * @author: Eric Newberry <enewberry@email.arizona.edu>
21 */
22
23#include "core/common.hpp"
24#include "core/version.hpp"
25
26#include "ping.hpp"
27#include "statistics-collector.hpp"
28#include "tracer.hpp"
29
30namespace ndn {
31namespace ping {
32namespace client {
33
34static time::milliseconds
Eric Newberrya66c29b2015-05-07 17:35:43 -070035getMinimumPingInterval()
36{
37 return time::milliseconds(1);
38}
39
40static time::milliseconds
41getDefaultPingInterval()
Eric Newberry4164b8e2015-04-23 17:29:18 -070042{
43 return time::milliseconds(1000);
44}
45
46static time::milliseconds
47getDefaultPingTimeoutThreshold()
48{
49 return time::milliseconds(4000);
50}
51
52static void
53usage(const boost::program_options::options_description& options)
54{
55 std::cout << "Usage: ndnping [options] ndn:/name/prefix\n"
56 "\n"
57 "Ping a NDN name prefix using Interests with name ndn:/name/prefix/ping/number.\n"
58 "The numbers in the Interests are randomly generated unless specified.\n"
59 "\n";
60 std::cout << options;
61 exit(2);
62}
63
Eric Newberrydce5a532015-05-06 10:46:52 -070064/**
65 * @brief SIGINT handler: print statistics and exit
66 */
Eric Newberry4164b8e2015-04-23 17:29:18 -070067static void
Eric Newberrydce5a532015-05-06 10:46:52 -070068onSigInt(Face& face, StatisticsCollector& statisticsCollector)
Eric Newberry4164b8e2015-04-23 17:29:18 -070069{
70 face.shutdown();
71 Statistics statistics = statisticsCollector.computeStatistics();
Eric Newberrydce5a532015-05-06 10:46:52 -070072 std::cout << statistics << std::endl;
Eric Newberry4164b8e2015-04-23 17:29:18 -070073
74 if (statistics.nReceived == statistics.nSent) {
75 exit(0);
76 }
77 else {
78 exit(1);
79 }
80}
81
Eric Newberrydce5a532015-05-06 10:46:52 -070082/**
83 * @brief SIGQUIT handler: print statistics summary and continue
84 */
85static void
86onSigQuit(StatisticsCollector& statisticsCollector, boost::asio::signal_set& signalSet)
87{
88 statisticsCollector.computeStatistics().printSummary(std::cout);
89 signalSet.async_wait(bind(&onSigQuit, ref(statisticsCollector), ref(signalSet)));
90}
91
Eric Newberry4164b8e2015-04-23 17:29:18 -070092int
93main(int argc, char* argv[])
94{
95 Options options;
96 options.shouldAllowStaleData = false;
97 options.nPings = -1;
Eric Newberrya66c29b2015-05-07 17:35:43 -070098 options.interval = time::milliseconds(getDefaultPingInterval());
Eric Newberry4164b8e2015-04-23 17:29:18 -070099 options.timeout = time::milliseconds(getDefaultPingTimeoutThreshold());
100 options.startSeq = 0;
101 options.shouldGenerateRandomSeq = true;
102 options.shouldPrintTimestamp = false;
103
104 std::string identifier;
105
106 namespace po = boost::program_options;
107
108 po::options_description visibleOptDesc("Allowed options");
109 visibleOptDesc.add_options()
110 ("help,h", "print this message and exit")
111 ("version,V", "display version and exit")
112 ("interval,i", po::value<int>(),
Eric Newberrya66c29b2015-05-07 17:35:43 -0700113 ("set ping interval in milliseconds (default " +
114 std::to_string(getDefaultPingInterval().count()) + " ms - minimum " +
115 std::to_string(getMinimumPingInterval().count()) + " ms)").c_str())
Eric Newberry4164b8e2015-04-23 17:29:18 -0700116 ("timeout,o", po::value<int>(),
117 ("set ping timeout in milliseconds (default " +
118 std::to_string(getDefaultPingTimeoutThreshold().count()) + " ms)").c_str())
119 ("count,c", po::value<int>(&options.nPings), "set total number of pings")
120 ("start,n", po::value<uint64_t>(&options.startSeq),
121 "set the starting seq number, the number is incremented by 1 after each Interest")
122 ("identifier,p", po::value<std::string>(&identifier),
123 "add identifier to the Interest names before the numbers to avoid conflict")
124 ("cache,a", "allows routers to return stale Data from cache")
125 ("timestamp,t", "print timestamp with messages")
126 ;
127 po::options_description hiddenOptDesc("Hidden options");
128 hiddenOptDesc.add_options()
129 ("prefix", po::value<std::string>(), "prefix to send pings to")
130 ;
131
132 po::options_description optDesc("Allowed options");
133 optDesc.add(visibleOptDesc).add(hiddenOptDesc);
134
135 try {
136 po::positional_options_description optPos;
137 optPos.add("prefix", -1);
138
139 po::variables_map optVm;
140 po::store(po::command_line_parser(argc, argv).options(optDesc).positional(optPos).run(), optVm);
141 po::notify(optVm);
142
143 if (optVm.count("help") > 0) {
144 usage(visibleOptDesc);
145 }
146
147 if (optVm.count("version") > 0) {
148 std::cout << "ndnping " << tools::VERSION << std::endl;
149 exit(0);
150 }
151
152 if (optVm.count("prefix") > 0) {
153 options.prefix = Name(optVm["prefix"].as<std::string>());
154 }
155 else {
156 std::cerr << "ERROR: No prefix specified" << std::endl;
157 usage(visibleOptDesc);
158 }
159
160 if (optVm.count("interval") > 0) {
161 options.interval = time::milliseconds(optVm["interval"].as<int>());
162
Eric Newberrya66c29b2015-05-07 17:35:43 -0700163 if (options.interval.count() < getMinimumPingInterval().count()) {
Eric Newberry4164b8e2015-04-23 17:29:18 -0700164 std::cerr << "ERROR: Specified ping interval is less than the minimum " <<
Eric Newberrya66c29b2015-05-07 17:35:43 -0700165 getMinimumPingInterval() << std::endl;
Eric Newberry4164b8e2015-04-23 17:29:18 -0700166 usage(visibleOptDesc);
167 }
168 }
169
170 if (optVm.count("timeout") > 0) {
171 options.timeout = time::milliseconds(optVm["timeout"].as<int>());
172 }
173
174 if (optVm.count("count") > 0) {
175 if (options.nPings <= 0) {
176 std::cerr << "ERROR: Number of ping must be positive" << std::endl;
177 usage(visibleOptDesc);
178 }
179 }
180
181 if (optVm.count("start") > 0) {
182 options.shouldGenerateRandomSeq = false;
183 }
184
185 if (optVm.count("identifier") > 0) {
186 bool isIdentifierAcceptable = std::all_of(identifier.begin(), identifier.end(), &isalnum);
187 if (identifier.empty() || !isIdentifierAcceptable) {
188 std::cerr << "ERROR: Unacceptable client identifier" << std::endl;
189 usage(visibleOptDesc);
190 }
191
192 options.clientIdentifier = name::Component(identifier);
193 }
194
195 if (optVm.count("cache") > 0) {
196 options.shouldAllowStaleData = true;
197 }
198
199 if (optVm.count("timestamp") > 0) {
200 options.shouldPrintTimestamp = true;
201 }
202 }
203 catch (const po::error& e) {
204 std::cerr << "ERROR: " << e.what() << std::endl;
205 usage(visibleOptDesc);
206 }
207
208 boost::asio::io_service ioService;
209 Face face(ioService);
210 Ping ping(face, options);
211 StatisticsCollector statisticsCollector(ping, options);
212 Tracer tracer(ping, options);
213
Eric Newberrydce5a532015-05-06 10:46:52 -0700214 boost::asio::signal_set signalSetInt(face.getIoService(), SIGINT);
215 signalSetInt.async_wait(bind(&onSigInt, ref(face), ref(statisticsCollector)));
216
217 boost::asio::signal_set signalSetQuit(face.getIoService(), SIGQUIT);
218 signalSetQuit.async_wait(bind(&onSigQuit, ref(statisticsCollector), ref(signalSetQuit)));
Eric Newberry4164b8e2015-04-23 17:29:18 -0700219
220 std::cout << "PING " << options.prefix << std::endl;
221
222 try {
223 ping.run();
224 }
225 catch (std::exception& e) {
226 tracer.onError(e.what());
227 face.getIoService().stop();
228 return 2;
229 }
230
231 Statistics statistics = statisticsCollector.computeStatistics();
232
233 std::cout << statistics << std::endl;
234
235 if (statistics.nReceived == statistics.nSent) {
236 return 0;
237 }
238 else {
239 return 1;
240 }
241}
242
243} // namespace client
244} // namespace ping
245} // namespace ndn
246
247int
248main(int argc, char** argv)
249{
250 return ndn::ping::client::main(argc, argv);
251}