blob: 1b3499ba17d90c3abb9d9c5a272b01f5d0590dec [file] [log] [blame]
hilata198cadb2014-02-15 23:46:19 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -07003 * Copyright (c) 2014 Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology
Obaiddca50792014-04-24 18:38:40 -05009 * The University of Memphis
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 **/
Alexander Afanasyevb47d5382014-05-05 14:35:03 -070025
hilata198cadb2014-02-15 23:46:19 -060026#include "nfdc.hpp"
Alexander Afanasyevb47d5382014-05-05 14:35:03 -070027#include "version.hpp"
28
hilata198cadb2014-02-15 23:46:19 -060029#include <boost/lexical_cast.hpp>
30#include <boost/algorithm/string.hpp>
31#include <boost/algorithm/string/regex_find_format.hpp>
32#include <boost/regex.hpp>
33
34void
35usage(const char* programName)
36{
Alexander Afanasyevb47d5382014-05-05 14:35:03 -070037 std::cout << "Usage:\n" << programName << " [-h] [-V] COMMAND [<Command Options>]\n"
Alexander Afanasyev352e14e2014-03-27 16:02:12 -070038 " -h print usage and exit\n"
Alexander Afanasyevb47d5382014-05-05 14:35:03 -070039 " -V print version and exit\n"
Alexander Afanasyev352e14e2014-03-27 16:02:12 -070040 "\n"
Obaiddca50792014-04-24 18:38:40 -050041 " COMMAND can be one of the following:\n"
Obaiddca50792014-04-24 18:38:40 -050042 " register [-I] [-C] [-c cost] name <faceId | faceUri>\n"
43 " register name to the given faceId or faceUri\n"
44 " -I: unset CHILD_INHERIT flag\n"
45 " -C: set CAPTURE flag\n"
46 " -c: specify cost\n"
47 " unregister name <faceId>\n"
48 " unregister name from the given faceId\n"
49 " create <faceUri> \n"
Alexander Afanasyev352e14e2014-03-27 16:02:12 -070050 " Create a face in one of the following formats:\n"
51 " UDP unicast: udp[4|6]://<remote-IP-or-host>[:<remote-port>]\n"
52 " TCP: tcp[4|6]://<remote-IP-or-host>[:<remote-port>] \n"
Obaiddca50792014-04-24 18:38:40 -050053 " destroy <faceId | faceUri> \n"
Alexander Afanasyev352e14e2014-03-27 16:02:12 -070054 " Destroy a face\n"
55 " set-strategy <name> <strategy> \n"
56 " Set the strategy for a namespace \n"
57 " unset-strategy <name> \n"
58 " Unset the strategy for a namespace \n"
hilata6ee6e072014-04-20 17:10:18 -050059 " add-nexthop [-c <cost>] <name> <faceId | faceUri>\n"
60 " Add a nexthop to a FIB entry\n"
61 " -c: specify cost\n"
62 " remove-nexthop <name> <faceId> \n"
63 " Remove a nexthop from a FIB entry\n"
Alexander Afanasyev352e14e2014-03-27 16:02:12 -070064 << std::endl;
hilata198cadb2014-02-15 23:46:19 -060065}
66
67namespace nfdc {
Alexander Afanasyev352e14e2014-03-27 16:02:12 -070068
69Nfdc::Nfdc(ndn::Face& face)
Obaiddca50792014-04-24 18:38:40 -050070 : m_flags(ROUTE_FLAG_CHILD_INHERIT)
71 , m_cost(0)
72 , m_controller(face)
hilata198cadb2014-02-15 23:46:19 -060073{
74}
Alexander Afanasyev352e14e2014-03-27 16:02:12 -070075
76Nfdc::~Nfdc()
hilata198cadb2014-02-15 23:46:19 -060077{
78}
Alexander Afanasyev352e14e2014-03-27 16:02:12 -070079
hilata198cadb2014-02-15 23:46:19 -060080bool
hilata54e4eaf2014-04-10 23:38:33 -050081Nfdc::dispatch(const std::string& command)
hilata198cadb2014-02-15 23:46:19 -060082{
Obaiddca50792014-04-24 18:38:40 -050083 if (command == "add-nexthop") {
84 if (m_nOptions != 2)
hilata54e4eaf2014-04-10 23:38:33 -050085 return false;
Obaiddca50792014-04-24 18:38:40 -050086 fibAddNextHop();
hilata198cadb2014-02-15 23:46:19 -060087 }
88 else if (command == "remove-nexthop") {
hilata54e4eaf2014-04-10 23:38:33 -050089 if (m_nOptions != 2)
hilata198cadb2014-02-15 23:46:19 -060090 return false;
hilata54e4eaf2014-04-10 23:38:33 -050091 fibRemoveNextHop();
hilata198cadb2014-02-15 23:46:19 -060092 }
Obaiddca50792014-04-24 18:38:40 -050093 else if (command == "register") {
94 if (m_nOptions != 2)
95 return false;
96 ribRegisterPrefix();
97 }
98 else if (command == "unregister") {
99 if (m_nOptions != 2)
100 return false;
101 ribUnregisterPrefix();
102 }
hilata198cadb2014-02-15 23:46:19 -0600103 else if (command == "create") {
hilata54e4eaf2014-04-10 23:38:33 -0500104 if (m_nOptions != 1)
hilata198cadb2014-02-15 23:46:19 -0600105 return false;
hilata54e4eaf2014-04-10 23:38:33 -0500106 faceCreate();
hilata198cadb2014-02-15 23:46:19 -0600107 }
108 else if (command == "destroy") {
hilata54e4eaf2014-04-10 23:38:33 -0500109 if (m_nOptions != 1)
hilata198cadb2014-02-15 23:46:19 -0600110 return false;
hilata54e4eaf2014-04-10 23:38:33 -0500111 faceDestroy();
hilata198cadb2014-02-15 23:46:19 -0600112 }
hilata141eaae2014-03-13 19:54:47 -0500113 else if (command == "set-strategy") {
hilata54e4eaf2014-04-10 23:38:33 -0500114 if (m_nOptions != 2)
hilata141eaae2014-03-13 19:54:47 -0500115 return false;
hilata54e4eaf2014-04-10 23:38:33 -0500116 strategyChoiceSet();
hilata141eaae2014-03-13 19:54:47 -0500117 }
118 else if (command == "unset-strategy") {
hilata54e4eaf2014-04-10 23:38:33 -0500119 if (m_nOptions != 1)
hilata141eaae2014-03-13 19:54:47 -0500120 return false;
hilata54e4eaf2014-04-10 23:38:33 -0500121 strategyChoiceUnset();
hilata141eaae2014-03-13 19:54:47 -0500122 }
hilata198cadb2014-02-15 23:46:19 -0600123 else
124 usage(m_programName);
125
126 return true;
127}
hilata198cadb2014-02-15 23:46:19 -0600128
hilata198cadb2014-02-15 23:46:19 -0600129namespace {
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700130
131inline bool
hilata198cadb2014-02-15 23:46:19 -0600132isValidUri(const std::string& input)
133{
134 // an extended regex to support the validation of uri structure
135 // boost::regex e("^[a-z0-9]+-?+[a-z0-9]+\\:\\/\\/.*");
136 boost::regex e("^[a-z0-9]+\\:.*");
137 return boost::regex_match(input, e);
138}
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700139
hilata198cadb2014-02-15 23:46:19 -0600140} // anonymous namespace
141
142void
Obaiddca50792014-04-24 18:38:40 -0500143Nfdc::fibAddNextHop()
hilata198cadb2014-02-15 23:46:19 -0600144{
Obaiddca50792014-04-24 18:38:40 -0500145 m_name = m_commandLineArguments[0];
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700146 ControlParameters parameters;
147 parameters
Obaiddca50792014-04-24 18:38:40 -0500148 .setName(m_name)
149 .setCost(m_cost);
hilata54e4eaf2014-04-10 23:38:33 -0500150
Obaiddca50792014-04-24 18:38:40 -0500151 if (!isValidUri(m_commandLineArguments[1])) {
152 try { //So the uri is not valid, may be a faceId is provided.
153 m_faceId = boost::lexical_cast<int>(m_commandLineArguments[1]);
154 }
155 catch (const std::exception& e) {
156 std::cerr << "No valid faceUri or faceId is provided"<< std::endl;
157 return;
158 }
159 parameters.setFaceId(m_faceId);
160 fibAddNextHop(parameters);
hilata54e4eaf2014-04-10 23:38:33 -0500161 }
Obaiddca50792014-04-24 18:38:40 -0500162 else {
163 ControlParameters faceParameters;
164 faceParameters.setUri(m_commandLineArguments[1]);
hilata54e4eaf2014-04-10 23:38:33 -0500165
Obaiddca50792014-04-24 18:38:40 -0500166 m_controller.start<FaceCreateCommand>(faceParameters,
167 bind(&Nfdc::fibAddNextHop, this, _1),
168 bind(&Nfdc::onError, this, _1, _2,
169 "Face creation failed"));
170 }
171}
172
173void
174Nfdc::fibAddNextHop(const ControlParameters& faceCreateResult)
175{
176 ControlParameters ribParameters;
177 ribParameters
178 .setName(m_name)
179 .setCost(m_cost)
180 .setFaceId(faceCreateResult.getFaceId());
181
182 m_controller.start<FibAddNextHopCommand>(ribParameters,
183 bind(&Nfdc::onSuccess, this, _1,
184 "Nexthop insertion succeeded"),
185 bind(&Nfdc::onError, this, _1, _2,
186 "Nexthop insertion failed"));
hilata54e4eaf2014-04-10 23:38:33 -0500187}
188
189void
190Nfdc::fibRemoveNextHop()
191{
Obaiddca50792014-04-24 18:38:40 -0500192 m_name = m_commandLineArguments[0];
193 try {
194 m_faceId = boost::lexical_cast<int>(m_commandLineArguments[1]);
195 }
196 catch (const std::exception& e) {
197 std::cerr << "No valid faceUri or faceId is provided"<< std::endl;
198 return;
199 }
hilata54e4eaf2014-04-10 23:38:33 -0500200
201 ControlParameters parameters;
202 parameters
Obaiddca50792014-04-24 18:38:40 -0500203 .setName(m_name)
204 .setFaceId(m_faceId);
hilata54e4eaf2014-04-10 23:38:33 -0500205
Obaiddca50792014-04-24 18:38:40 -0500206 m_controller.start<FibRemoveNextHopCommand>(parameters,
207 bind(&Nfdc::onSuccess, this, _1,
208 "Nexthop removal succeeded"),
209 bind(&Nfdc::onError, this, _1, _2,
210 "Nexthop removal failed"));
211}
212
213void
214Nfdc::ribRegisterPrefix()
215{
216 m_name = m_commandLineArguments[0];
217 ControlParameters parameters;
218 parameters
219 .setName(m_name)
220 .setCost(m_cost)
221 .setFlags(m_flags);
222
223 if (!isValidUri(m_commandLineArguments[1])) {
224 try { //So the uri is not valid, may be a faceId is provided.
225 m_faceId = boost::lexical_cast<int>(m_commandLineArguments[1]);
226 }
227 catch (const std::exception& e) {
228 std::cerr << "No valid faceUri or faceId is provided"<< std::endl;
229 return;
230 }
231 parameters.setFaceId(m_faceId);
232 ribRegisterPrefix(parameters);
233 }
234 else {
235 ControlParameters faceParameters;
236 faceParameters.setUri(m_commandLineArguments[1]);
237
238 m_controller.start<FaceCreateCommand>(faceParameters,
239 bind(&Nfdc::ribRegisterPrefix, this, _1),
240 bind(&Nfdc::onError, this, _1, _2,
241 "Face creation failed"));
242 }
243}
244
245void
246Nfdc::ribRegisterPrefix(const ControlParameters& faceCreateResult)
247{
248 ControlParameters ribParameters;
249 ribParameters
250 .setName(m_name)
251 .setCost(m_cost)
252 .setFlags(m_flags)
253 .setFaceId(faceCreateResult.getFaceId());
254
255 m_controller.start<RibRegisterCommand>(ribParameters,
256 bind(&Nfdc::onSuccess, this, _1,
257 "Successful in name registration"),
258 bind(&Nfdc::onError, this, _1, _2,
259 "Failed in name registration"));
260}
261
262void
263Nfdc::ribUnregisterPrefix()
264{
265 m_name = m_commandLineArguments[0];
266 try {
267 m_faceId = boost::lexical_cast<int>(m_commandLineArguments[1]);
268 }
269 catch (const std::exception& e) {
270 std::cerr << "No valid faceUri or faceId is provided"<< std::endl;
271 return;
272 }
273
274 ControlParameters parameters;
275 parameters
276 .setName(m_name)
277 .setFaceId(m_faceId);
278
279 m_controller.start<RibUnregisterCommand>(parameters,
280 bind(&Nfdc::onSuccess, this, _1,
281 "Successful in unregistering name"),
282 bind(&Nfdc::onError, this, _1, _2,
283 "Failed in unregistering name"));
hilata54e4eaf2014-04-10 23:38:33 -0500284}
285
286void
287Nfdc::faceCreate()
288{
289 if (!isValidUri(m_commandLineArguments[0]))
290 throw Error("invalid uri format");
291
292 ControlParameters parameters;
Obaiddca50792014-04-24 18:38:40 -0500293 parameters.setUri(m_commandLineArguments[0]);
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700294
Obaiddca50792014-04-24 18:38:40 -0500295 m_controller.start<FaceCreateCommand>(parameters,
296 bind(&Nfdc::onSuccess, this, _1,
297 "Face creation succeeded"),
298 bind(&Nfdc::onError, this, _1, _2,
299 "Face creation failed"));
hilata198cadb2014-02-15 23:46:19 -0600300}
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700301
hilata198cadb2014-02-15 23:46:19 -0600302void
hilata54e4eaf2014-04-10 23:38:33 -0500303Nfdc::faceDestroy()
hilata198cadb2014-02-15 23:46:19 -0600304{
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700305 ControlParameters parameters;
Obaiddca50792014-04-24 18:38:40 -0500306 if (!isValidUri(m_commandLineArguments[0])) {
307 try { //So the uri is not valid, may be a faceId is provided.
308 m_faceId = boost::lexical_cast<int>(m_commandLineArguments[0]);
309 }
310 catch (const std::exception& e) {
311 std::cerr << "No valid faceUri or faceId is provided" << std::endl;
312 return;
313 }
314 parameters.setFaceId(m_faceId);
315 faceDestroy(parameters);
316 }
317 else{
318 ControlParameters faceParameters;
319 faceParameters.setUri(m_commandLineArguments[0]);
320 m_controller.start<FaceCreateCommand>(faceParameters,
321 bind(&Nfdc::faceDestroy, this, _1),
322 bind(&Nfdc::onError, this, _1, _2,
323 "Face destroy failed"));
324 }
325}
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700326
Obaiddca50792014-04-24 18:38:40 -0500327void
328Nfdc::faceDestroy(const ControlParameters& faceCreateResult)
329{
330 ControlParameters faceParameters;
331 faceParameters.setFaceId(faceCreateResult.getFaceId());
332
333 m_controller.start<FaceDestroyCommand>(faceParameters,
334 bind(&Nfdc::onSuccess, this, _1,
335 "Face destroy succeeded"),
336 bind(&Nfdc::onError, this, _1, _2,
337 "Face destroy failed"));
hilata198cadb2014-02-15 23:46:19 -0600338}
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700339
hilata141eaae2014-03-13 19:54:47 -0500340void
hilata54e4eaf2014-04-10 23:38:33 -0500341Nfdc::strategyChoiceSet()
hilata141eaae2014-03-13 19:54:47 -0500342{
hilata54e4eaf2014-04-10 23:38:33 -0500343 const std::string& name = m_commandLineArguments[0];
344 const std::string& strategy = m_commandLineArguments[1];
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700345
346 ControlParameters parameters;
347 parameters
348 .setName(name)
349 .setStrategy(strategy);
350
Obaiddca50792014-04-24 18:38:40 -0500351 m_controller.start<StrategyChoiceSetCommand>(parameters,
352 bind(&Nfdc::onSuccess, this, _1,
353 "Successfully set strategy choice"),
354 bind(&Nfdc::onError, this, _1, _2,
355 "Failed to set strategy choice"));
hilata141eaae2014-03-13 19:54:47 -0500356}
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700357
hilata141eaae2014-03-13 19:54:47 -0500358void
hilata54e4eaf2014-04-10 23:38:33 -0500359Nfdc::strategyChoiceUnset()
hilata141eaae2014-03-13 19:54:47 -0500360{
hilata54e4eaf2014-04-10 23:38:33 -0500361 const std::string& name = m_commandLineArguments[0];
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700362
363 ControlParameters parameters;
Obaiddca50792014-04-24 18:38:40 -0500364 parameters.setName(name);
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700365
Obaiddca50792014-04-24 18:38:40 -0500366 m_controller.start<StrategyChoiceUnsetCommand>(parameters,
367 bind(&Nfdc::onSuccess, this, _1,
368 "Successfully unset strategy choice"),
369 bind(&Nfdc::onError, this, _1, _2,
370 "Failed to unset strategy choice"));
hilata141eaae2014-03-13 19:54:47 -0500371}
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700372
hilata198cadb2014-02-15 23:46:19 -0600373void
Obaiddca50792014-04-24 18:38:40 -0500374Nfdc::onSuccess(const ControlParameters& commandSuccessResult, const std::string& message)
hilata198cadb2014-02-15 23:46:19 -0600375{
Obaiddca50792014-04-24 18:38:40 -0500376 std::cout << message << ": " << commandSuccessResult << std::endl;
hilata198cadb2014-02-15 23:46:19 -0600377}
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700378
hilata198cadb2014-02-15 23:46:19 -0600379void
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700380Nfdc::onError(uint32_t code, const std::string& error, const std::string& message)
hilata198cadb2014-02-15 23:46:19 -0600381{
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700382 std::ostringstream os;
383 os << message << ": " << error << " (code: " << code << ")";
384 throw Error(os.str());
hilata141eaae2014-03-13 19:54:47 -0500385}
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700386
Obaiddca50792014-04-24 18:38:40 -0500387
388
hilata141eaae2014-03-13 19:54:47 -0500389} // namespace nfdc
hilata198cadb2014-02-15 23:46:19 -0600390
391int
392main(int argc, char** argv)
393{
394 ndn::Face face;
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700395 nfdc::Nfdc p(face);
Alexander Afanasyev9f935b82014-02-24 15:14:22 -0800396
hilata198cadb2014-02-15 23:46:19 -0600397 p.m_programName = argv[0];
hilata54e4eaf2014-04-10 23:38:33 -0500398
Obaiddca50792014-04-24 18:38:40 -0500399 if (argc < 2) {
400 usage(p.m_programName);
401 return 0;
402 }
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700403
Obaiddca50792014-04-24 18:38:40 -0500404 if (!strcmp(argv[1], "-h")) {
405 usage(p.m_programName);
406 return 0;
407 }
408
Alexander Afanasyevb47d5382014-05-05 14:35:03 -0700409 if (!strcmp(argv[1], "-V")) {
410 std::cout << NFD_VERSION_BUILD_STRING << std::endl;
411 return 0;
412 }
413
Junxiao Shi22295032014-04-29 22:57:40 -0700414 ::optind = 2; //start reading options from 2nd argument i.e. Command
Obaiddca50792014-04-24 18:38:40 -0500415 int opt;
Junxiao Shi22295032014-04-29 22:57:40 -0700416 while ((opt = ::getopt(argc, argv, "ICc:")) != -1) {
Obaiddca50792014-04-24 18:38:40 -0500417 switch (opt) {
418 case 'I':
419 p.m_flags = p.m_flags & ~(nfdc::ROUTE_FLAG_CHILD_INHERIT);
420 break;
421
422 case 'C':
423 p.m_flags = p.m_flags | nfdc::ROUTE_FLAG_CAPTURE;
424 break;
425
426 case 'c':
427 try {
Junxiao Shi22295032014-04-29 22:57:40 -0700428 p.m_cost = boost::lexical_cast<int>(::optarg);
Obaiddca50792014-04-24 18:38:40 -0500429 }
Junxiao Shi22295032014-04-29 22:57:40 -0700430 catch (boost::bad_lexical_cast&) {
Obaiddca50792014-04-24 18:38:40 -0500431 std::cerr << "Error: cost must be in integer format" << std::endl;
hilata198cadb2014-02-15 23:46:19 -0600432 return 1;
Obaiddca50792014-04-24 18:38:40 -0500433 }
434 break;
Junxiao Shi22295032014-04-29 22:57:40 -0700435
Obaiddca50792014-04-24 18:38:40 -0500436 default:
437 usage(p.m_programName);
438 return 1;
hilata198cadb2014-02-15 23:46:19 -0600439 }
440 }
Alexander Afanasyev9f935b82014-02-24 15:14:22 -0800441
Junxiao Shi22295032014-04-29 22:57:40 -0700442 if (argc == ::optind) {
Alexander Afanasyev9f935b82014-02-24 15:14:22 -0800443 usage(p.m_programName);
444 return 1;
445 }
446
hilata198cadb2014-02-15 23:46:19 -0600447 try {
Junxiao Shi22295032014-04-29 22:57:40 -0700448 p.m_commandLineArguments = argv + ::optind;
449 p.m_nOptions = argc - ::optind;
Obaiddca50792014-04-24 18:38:40 -0500450
451 //argv[1] points to the command, so pass it to the dispatch
452 bool isOk = p.dispatch(argv[1]);
Alexander Afanasyev352e14e2014-03-27 16:02:12 -0700453 if (!isOk) {
hilata198cadb2014-02-15 23:46:19 -0600454 usage(p.m_programName);
455 return 1;
456 }
hilata198cadb2014-02-15 23:46:19 -0600457 face.processEvents();
458 }
459 catch (const std::exception& e) {
460 std::cerr << "ERROR: " << e.what() << std::endl;
461 return 2;
462 }
463 return 0;
464}