blob: dcadca5eb0163a4367d78bca8f96787eda4cb9a0 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi5ec80222014-03-25 20:08:05 -07002/**
Alexander Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Junxiao Shi5ec80222014-03-25 20:08:05 -070020 */
21
22#ifndef NDN_MANAGEMENT_NFD_CONTROL_COMMAND_HPP
23#define NDN_MANAGEMENT_NFD_CONTROL_COMMAND_HPP
24
25#include "nfd-control-parameters.hpp"
26#include "../util/command-interest-generator.hpp"
27
28namespace ndn {
29namespace nfd {
30
Alexander Afanasyev4671bf72014-05-19 09:01:37 -040031/**
32 * \ingroup management
33 * \brief base class of NFD ControlCommand
34 * \sa http://redmine.named-data.net/projects/nfd/wiki/ControlCommand
Junxiao Shi5ec80222014-03-25 20:08:05 -070035 */
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070036class ControlCommand : noncopyable
Junxiao Shi5ec80222014-03-25 20:08:05 -070037{
38public:
Yingdi Yue66bf2a2014-04-28 17:07:36 -070039 /** \brief a callback on signing command interest
40 */
41 typedef function<void(Interest&)> Sign;
42
Junxiao Shi5ec80222014-03-25 20:08:05 -070043 /** \brief represents an error in ControlParameters
44 */
45 class ArgumentError : public std::invalid_argument
46 {
47 public:
48 explicit
49 ArgumentError(const std::string& what)
50 : std::invalid_argument(what)
51 {
52 }
53 };
54
55 /** \return Name prefix of this ControlCommand
56 */
57 const Name&
58 getPrefix() const
59 {
60 return m_prefix;
61 }
62
63 /** \brief make a Command Interest from parameters
64 */
65 Interest
66 makeCommandInterest(const ControlParameters& parameters,
Yingdi Yue66bf2a2014-04-28 17:07:36 -070067 const Sign& sign) const
Junxiao Shi5ec80222014-03-25 20:08:05 -070068 {
69 this->validateRequest(parameters);
70
71 Name name = m_prefix;
72 name.append(parameters.wireEncode());
73 Interest commandInterest(name);
Yingdi Yue66bf2a2014-04-28 17:07:36 -070074 sign(commandInterest);
Junxiao Shi5ec80222014-03-25 20:08:05 -070075 return commandInterest;
76 }
77
78 /** \brief validate request parameters
79 * \throw ArgumentError
80 */
81 virtual void
82 validateRequest(const ControlParameters& parameters) const
83 {
84 m_requestValidator.validate(parameters);
85 }
86
87 /** \brief apply default values to missing fields in request
88 */
89 virtual void
90 applyDefaultsToRequest(ControlParameters& parameters) const
91 {
92 }
93
94 /** \brief validate response parameters
95 * \throw ArgumentError
96 */
97 virtual void
98 validateResponse(const ControlParameters& parameters) const
99 {
100 m_responseValidator.validate(parameters);
101 }
102
103 /** \brief apply default values to missing fields in response
104 */
105 virtual void
106 applyDefaultsToResponse(ControlParameters& parameters) const
107 {
108 }
109
110protected:
111 ControlCommand(const std::string& module, const std::string& verb)
112 : m_prefix("ndn:/localhost/nfd")
113 {
114 m_prefix.append(module).append(verb);
115 }
116
117 class FieldValidator
118 {
119 public:
120 FieldValidator()
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700121 : m_required(CONTROL_PARAMETER_UBOUND)
122 , m_optional(CONTROL_PARAMETER_UBOUND)
Junxiao Shi5ec80222014-03-25 20:08:05 -0700123 {
Junxiao Shi5ec80222014-03-25 20:08:05 -0700124 }
125
126 /** \brief declare a required field
127 */
128 FieldValidator&
129 required(ControlParameterField field)
130 {
131 m_required[field] = true;
132 return *this;
133 }
134
135 /** \brief declare an optional field
136 */
137 FieldValidator&
138 optional(ControlParameterField field)
139 {
140 m_optional[field] = true;
141 return *this;
142 }
143
144 /** \brief verify that all required fields are present,
145 * and all present fields are either required or optional
146 * \throw ArgumentError
147 */
148 void
149 validate(const ControlParameters& parameters) const
150 {
151 const std::vector<bool>& presentFields = parameters.getPresentFields();
152
153 for (size_t i = 0; i < CONTROL_PARAMETER_UBOUND; ++i) {
154 bool isPresent = presentFields[i];
155 if (m_required[i]) {
156 if (!isPresent) {
157 throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is required but missing");
158 }
159 }
160 else if (isPresent && !m_optional[i]) {
161 throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is forbidden but present");
162 }
163 }
164 }
165
166 private:
167 std::vector<bool> m_required;
168 std::vector<bool> m_optional;
169 };
170
171protected:
172 /** \brief FieldValidator for request ControlParameters
173 *
174 * Constructor of subclass should populate this validator.
175 */
176 FieldValidator m_requestValidator;
177 /** \brief FieldValidator for response ControlParameters
178 *
179 * Constructor of subclass should populate this validator.
180 */
181 FieldValidator m_responseValidator;
182
183private:
184 Name m_prefix;
185};
186
187
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400188/**
189 * \ingroup management
190 * \brief represents a faces/create command
191 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Create-a-face
Junxiao Shi5ec80222014-03-25 20:08:05 -0700192 */
193class FaceCreateCommand : public ControlCommand
194{
195public:
196 FaceCreateCommand()
197 : ControlCommand("faces", "create")
198 {
199 m_requestValidator
200 .required(CONTROL_PARAMETER_URI);
201 m_responseValidator
202 .required(CONTROL_PARAMETER_URI)
203 .required(CONTROL_PARAMETER_FACE_ID);
204 }
205
206 virtual void
207 validateResponse(const ControlParameters& parameters) const
208 {
209 this->ControlCommand::validateResponse(parameters);
210
211 if (parameters.getFaceId() == 0) {
212 throw ArgumentError("FaceId must not be zero");
213 }
214 }
215};
216
217
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400218/**
219 * \ingroup management
220 * \brief represents a faces/destroy command
221 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Destroy-a-face
Junxiao Shi5ec80222014-03-25 20:08:05 -0700222 */
223class FaceDestroyCommand : public ControlCommand
224{
225public:
226 FaceDestroyCommand()
227 : ControlCommand("faces", "destroy")
228 {
229 m_requestValidator
230 .required(CONTROL_PARAMETER_FACE_ID);
231 m_responseValidator = m_requestValidator;
232 }
233
234 virtual void
235 validateRequest(const ControlParameters& parameters) const
236 {
237 this->ControlCommand::validateRequest(parameters);
238
239 if (parameters.getFaceId() == 0) {
240 throw ArgumentError("FaceId must not be zero");
241 }
242 }
243
244 virtual void
245 validateResponse(const ControlParameters& parameters) const
246 {
247 this->validateRequest(parameters);
248 }
249};
250
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400251/**
252 * \ingroup management
253 * \brief Base class for faces/[*]-local-control commands
254 */
Junxiao Shi5ec80222014-03-25 20:08:05 -0700255class FaceLocalControlCommand : public ControlCommand
256{
Junxiao Shi6888bc12014-03-29 23:01:41 -0700257public:
258 virtual void
259 validateRequest(const ControlParameters& parameters) const
260 {
261 this->ControlCommand::validateRequest(parameters);
262
263 switch (parameters.getLocalControlFeature()) {
264 case LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID:
265 case LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID:
266 break;
267 default:
268 throw ArgumentError("LocalControlFeature is invalid");
269 }
270 }
271
272 virtual void
273 validateResponse(const ControlParameters& parameters) const
274 {
275 this->validateRequest(parameters);
276 }
277
Junxiao Shi5ec80222014-03-25 20:08:05 -0700278protected:
279 explicit
280 FaceLocalControlCommand(const std::string& verb)
281 : ControlCommand("faces", verb)
282 {
283 m_requestValidator
284 .required(CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE);
285 m_responseValidator = m_requestValidator;
286 }
287};
288
289
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400290/**
291 * \ingroup management
292 * \brief represents a faces/enable-local-control command
293 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Enable-a-LocalControlHeader-feature
Junxiao Shi5ec80222014-03-25 20:08:05 -0700294 */
295class FaceEnableLocalControlCommand : public FaceLocalControlCommand
296{
297public:
298 FaceEnableLocalControlCommand()
299 : FaceLocalControlCommand("enable-local-control")
300 {
301 }
302};
303
304
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400305/**
306 * \ingroup management
307 * \brief represents a faces/disable-local-control command
308 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Disable-a-LocalControlHeader-feature
Junxiao Shi5ec80222014-03-25 20:08:05 -0700309 */
310class FaceDisableLocalControlCommand : public FaceLocalControlCommand
311{
312public:
313 FaceDisableLocalControlCommand()
314 : FaceLocalControlCommand("disable-local-control")
315 {
316 }
317};
318
319
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400320/**
321 * \ingroup management
322 * \brief represents a fib/add-nexthop command
323 * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Add-a-nexthop
Junxiao Shi5ec80222014-03-25 20:08:05 -0700324 */
325class FibAddNextHopCommand : public ControlCommand
326{
327public:
328 FibAddNextHopCommand()
329 : ControlCommand("fib", "add-nexthop")
330 {
331 m_requestValidator
332 .required(CONTROL_PARAMETER_NAME)
Junxiao Shicaac54e2014-05-20 15:27:01 -0700333 .optional(CONTROL_PARAMETER_FACE_ID)
Junxiao Shi5ec80222014-03-25 20:08:05 -0700334 .optional(CONTROL_PARAMETER_COST);
335 m_responseValidator
336 .required(CONTROL_PARAMETER_NAME)
337 .required(CONTROL_PARAMETER_FACE_ID)
338 .required(CONTROL_PARAMETER_COST);
339 }
340
341 virtual void
342 applyDefaultsToRequest(ControlParameters& parameters) const
343 {
Junxiao Shicaac54e2014-05-20 15:27:01 -0700344 if (!parameters.hasFaceId()) {
345 parameters.setFaceId(0);
346 }
Junxiao Shi5ec80222014-03-25 20:08:05 -0700347 if (!parameters.hasCost()) {
348 parameters.setCost(0);
349 }
350 }
351
352 virtual void
353 validateResponse(const ControlParameters& parameters) const
354 {
355 this->ControlCommand::validateResponse(parameters);
356
357 if (parameters.getFaceId() == 0) {
358 throw ArgumentError("FaceId must not be zero");
359 }
360 }
361};
362
363
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400364/**
365 * \ingroup management
366 * \brief represents a fib/remove-nexthop command
367 * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Remove-a-nexthop
Junxiao Shi5ec80222014-03-25 20:08:05 -0700368 */
369class FibRemoveNextHopCommand : public ControlCommand
370{
371public:
372 FibRemoveNextHopCommand()
373 : ControlCommand("fib", "remove-nexthop")
374 {
375 m_requestValidator
376 .required(CONTROL_PARAMETER_NAME)
Junxiao Shicaac54e2014-05-20 15:27:01 -0700377 .optional(CONTROL_PARAMETER_FACE_ID);
Junxiao Shi5ec80222014-03-25 20:08:05 -0700378 m_responseValidator
379 .required(CONTROL_PARAMETER_NAME)
380 .required(CONTROL_PARAMETER_FACE_ID);
381 }
382
383 virtual void
Junxiao Shicaac54e2014-05-20 15:27:01 -0700384 applyDefaultsToRequest(ControlParameters& parameters) const
385 {
386 if (!parameters.hasFaceId()) {
387 parameters.setFaceId(0);
388 }
389 }
390
391 virtual void
Junxiao Shi5ec80222014-03-25 20:08:05 -0700392 validateResponse(const ControlParameters& parameters) const
393 {
394 this->ControlCommand::validateResponse(parameters);
395
396 if (parameters.getFaceId() == 0) {
397 throw ArgumentError("FaceId must not be zero");
398 }
399 }
400};
401
402
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400403/**
404 * \ingroup management
405 * \brief represents a strategy-choice/set command
406 * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Set-the-strategy-for-a-namespace
Junxiao Shi5ec80222014-03-25 20:08:05 -0700407 */
408class StrategyChoiceSetCommand : public ControlCommand
409{
410public:
411 StrategyChoiceSetCommand()
412 : ControlCommand("strategy-choice", "set")
413 {
414 m_requestValidator
415 .required(CONTROL_PARAMETER_NAME)
416 .required(CONTROL_PARAMETER_STRATEGY);
417 m_responseValidator = m_requestValidator;
418 }
419};
420
421
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400422/**
423 * \ingroup management
424 * \brief represents a strategy-choice/set command
425 * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Unset-the-strategy-for-a-namespace
Junxiao Shi5ec80222014-03-25 20:08:05 -0700426 */
427class StrategyChoiceUnsetCommand : public ControlCommand
428{
429public:
430 StrategyChoiceUnsetCommand()
431 : ControlCommand("strategy-choice", "unset")
432 {
433 m_requestValidator
434 .required(CONTROL_PARAMETER_NAME);
435 m_responseValidator = m_requestValidator;
436 }
437
438 virtual void
439 validateRequest(const ControlParameters& parameters) const
440 {
441 this->ControlCommand::validateRequest(parameters);
442
443 if (parameters.getName().size() == 0) {
444 throw ArgumentError("Name must not be ndn:/");
445 }
446 }
447
448 virtual void
449 validateResponse(const ControlParameters& parameters) const
450 {
451 this->validateRequest(parameters);
452 }
453};
454
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700455
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400456/**
457 * \ingroup management
458 */
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700459enum {
460 // route origin
461 ROUTE_ORIGIN_APP = 0,
462 ROUTE_ORIGIN_NLSR = 128,
463 ROUTE_ORIGIN_STATIC = 255,
464
465 // route inheritance flags
466 ROUTE_FLAG_CHILD_INHERIT = 1,
467 ROUTE_FLAG_CAPTURE = 2
468};
469
470
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400471/**
472 * \ingroup management
473 * \brief represents a rib/register command
474 * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Register-a-route
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700475 */
476class RibRegisterCommand : public ControlCommand
477{
478public:
479 RibRegisterCommand()
480 : ControlCommand("rib", "register")
481 {
482 m_requestValidator
483 .required(CONTROL_PARAMETER_NAME)
484 .optional(CONTROL_PARAMETER_FACE_ID)
485 .optional(CONTROL_PARAMETER_ORIGIN)
486 .optional(CONTROL_PARAMETER_COST)
487 .optional(CONTROL_PARAMETER_FLAGS)
488 .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD);
489 m_responseValidator
490 .required(CONTROL_PARAMETER_NAME)
491 .required(CONTROL_PARAMETER_FACE_ID)
492 .required(CONTROL_PARAMETER_ORIGIN)
493 .required(CONTROL_PARAMETER_COST)
494 .required(CONTROL_PARAMETER_FLAGS)
495 .required(CONTROL_PARAMETER_EXPIRATION_PERIOD);
496 }
497
498 virtual void
499 applyDefaultsToRequest(ControlParameters& parameters) const
500 {
501 if (!parameters.hasFaceId()) {
502 parameters.setFaceId(0);
503 }
504 if (!parameters.hasOrigin()) {
505 parameters.setOrigin(ROUTE_ORIGIN_APP);
506 }
507 if (!parameters.hasCost()) {
508 parameters.setCost(0);
509 }
510 if (!parameters.hasFlags()) {
511 parameters.setFlags(ROUTE_FLAG_CHILD_INHERIT);
512 }
513 if (!parameters.hasExpirationPeriod()) {
514 if (parameters.getFaceId() == 0) {
515 parameters.setExpirationPeriod(time::milliseconds::max());
516 }
517 else {
518 parameters.setExpirationPeriod(time::hours(1));
519 }
520 }
521 }
522
523 virtual void
524 validateResponse(const ControlParameters& parameters) const
525 {
526 this->ControlCommand::validateResponse(parameters);
527
528 if (parameters.getFaceId() == 0) {
529 throw ArgumentError("FaceId must not be zero");
530 }
531 }
532};
533
534
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400535/**
536 * \ingroup management
537 * \brief represents a rib/unregister command
538 * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Unregister-a-route
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700539 */
540class RibUnregisterCommand : public ControlCommand
541{
542public:
543 RibUnregisterCommand()
544 : ControlCommand("rib", "unregister")
545 {
546 m_requestValidator
547 .required(CONTROL_PARAMETER_NAME)
548 .optional(CONTROL_PARAMETER_FACE_ID)
549 .optional(CONTROL_PARAMETER_ORIGIN);
550 m_responseValidator
551 .required(CONTROL_PARAMETER_NAME)
552 .required(CONTROL_PARAMETER_FACE_ID)
553 .required(CONTROL_PARAMETER_ORIGIN);
554 }
555
556 virtual void
557 applyDefaultsToRequest(ControlParameters& parameters) const
558 {
559 if (!parameters.hasFaceId()) {
560 parameters.setFaceId(0);
561 }
562 if (!parameters.hasOrigin()) {
563 parameters.setOrigin(ROUTE_ORIGIN_APP);
564 }
565 }
566
567 virtual void
568 validateResponse(const ControlParameters& parameters) const
569 {
570 this->ControlCommand::validateResponse(parameters);
571
572 if (parameters.getFaceId() == 0) {
573 throw ArgumentError("FaceId must not be zero");
574 }
575 }
576};
577
578
Junxiao Shi5ec80222014-03-25 20:08:05 -0700579} // namespace nfd
580} // namespace ndn
581
582#endif // NDN_MANAGEMENT_NFD_CONTROL_COMMAND_HPP