blob: 1bf0c0c40ba81dc681af30dea69b7d5fe3ccd87f [file] [log] [blame]
Junxiao Shi5ec80222014-03-25 20:08:05 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07003 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
Junxiao Shi5ec80222014-03-25 20:08:05 -070011 */
12
13#ifndef NDN_MANAGEMENT_NFD_CONTROL_COMMAND_HPP
14#define NDN_MANAGEMENT_NFD_CONTROL_COMMAND_HPP
15
16#include "nfd-control-parameters.hpp"
17#include "../util/command-interest-generator.hpp"
18
19namespace ndn {
20namespace nfd {
21
Alexander Afanasyev4671bf72014-05-19 09:01:37 -040022/**
23 * \ingroup management
24 * \brief base class of NFD ControlCommand
25 * \sa http://redmine.named-data.net/projects/nfd/wiki/ControlCommand
Junxiao Shi5ec80222014-03-25 20:08:05 -070026 */
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070027class ControlCommand : noncopyable
Junxiao Shi5ec80222014-03-25 20:08:05 -070028{
29public:
Yingdi Yue66bf2a2014-04-28 17:07:36 -070030 /** \brief a callback on signing command interest
31 */
32 typedef function<void(Interest&)> Sign;
33
Junxiao Shi5ec80222014-03-25 20:08:05 -070034 /** \brief represents an error in ControlParameters
35 */
36 class ArgumentError : public std::invalid_argument
37 {
38 public:
39 explicit
40 ArgumentError(const std::string& what)
41 : std::invalid_argument(what)
42 {
43 }
44 };
45
46 /** \return Name prefix of this ControlCommand
47 */
48 const Name&
49 getPrefix() const
50 {
51 return m_prefix;
52 }
53
54 /** \brief make a Command Interest from parameters
55 */
56 Interest
57 makeCommandInterest(const ControlParameters& parameters,
Yingdi Yue66bf2a2014-04-28 17:07:36 -070058 const Sign& sign) const
Junxiao Shi5ec80222014-03-25 20:08:05 -070059 {
60 this->validateRequest(parameters);
61
62 Name name = m_prefix;
63 name.append(parameters.wireEncode());
64 Interest commandInterest(name);
Yingdi Yue66bf2a2014-04-28 17:07:36 -070065 sign(commandInterest);
Junxiao Shi5ec80222014-03-25 20:08:05 -070066 return commandInterest;
67 }
68
69 /** \brief validate request parameters
70 * \throw ArgumentError
71 */
72 virtual void
73 validateRequest(const ControlParameters& parameters) const
74 {
75 m_requestValidator.validate(parameters);
76 }
77
78 /** \brief apply default values to missing fields in request
79 */
80 virtual void
81 applyDefaultsToRequest(ControlParameters& parameters) const
82 {
83 }
84
85 /** \brief validate response parameters
86 * \throw ArgumentError
87 */
88 virtual void
89 validateResponse(const ControlParameters& parameters) const
90 {
91 m_responseValidator.validate(parameters);
92 }
93
94 /** \brief apply default values to missing fields in response
95 */
96 virtual void
97 applyDefaultsToResponse(ControlParameters& parameters) const
98 {
99 }
100
101protected:
102 ControlCommand(const std::string& module, const std::string& verb)
103 : m_prefix("ndn:/localhost/nfd")
104 {
105 m_prefix.append(module).append(verb);
106 }
107
108 class FieldValidator
109 {
110 public:
111 FieldValidator()
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700112 : m_required(CONTROL_PARAMETER_UBOUND)
113 , m_optional(CONTROL_PARAMETER_UBOUND)
Junxiao Shi5ec80222014-03-25 20:08:05 -0700114 {
Junxiao Shi5ec80222014-03-25 20:08:05 -0700115 }
116
117 /** \brief declare a required field
118 */
119 FieldValidator&
120 required(ControlParameterField field)
121 {
122 m_required[field] = true;
123 return *this;
124 }
125
126 /** \brief declare an optional field
127 */
128 FieldValidator&
129 optional(ControlParameterField field)
130 {
131 m_optional[field] = true;
132 return *this;
133 }
134
135 /** \brief verify that all required fields are present,
136 * and all present fields are either required or optional
137 * \throw ArgumentError
138 */
139 void
140 validate(const ControlParameters& parameters) const
141 {
142 const std::vector<bool>& presentFields = parameters.getPresentFields();
143
144 for (size_t i = 0; i < CONTROL_PARAMETER_UBOUND; ++i) {
145 bool isPresent = presentFields[i];
146 if (m_required[i]) {
147 if (!isPresent) {
148 throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is required but missing");
149 }
150 }
151 else if (isPresent && !m_optional[i]) {
152 throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is forbidden but present");
153 }
154 }
155 }
156
157 private:
158 std::vector<bool> m_required;
159 std::vector<bool> m_optional;
160 };
161
162protected:
163 /** \brief FieldValidator for request ControlParameters
164 *
165 * Constructor of subclass should populate this validator.
166 */
167 FieldValidator m_requestValidator;
168 /** \brief FieldValidator for response ControlParameters
169 *
170 * Constructor of subclass should populate this validator.
171 */
172 FieldValidator m_responseValidator;
173
174private:
175 Name m_prefix;
176};
177
178
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400179/**
180 * \ingroup management
181 * \brief represents a faces/create command
182 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Create-a-face
Junxiao Shi5ec80222014-03-25 20:08:05 -0700183 */
184class FaceCreateCommand : public ControlCommand
185{
186public:
187 FaceCreateCommand()
188 : ControlCommand("faces", "create")
189 {
190 m_requestValidator
191 .required(CONTROL_PARAMETER_URI);
192 m_responseValidator
193 .required(CONTROL_PARAMETER_URI)
194 .required(CONTROL_PARAMETER_FACE_ID);
195 }
196
197 virtual void
198 validateResponse(const ControlParameters& parameters) const
199 {
200 this->ControlCommand::validateResponse(parameters);
201
202 if (parameters.getFaceId() == 0) {
203 throw ArgumentError("FaceId must not be zero");
204 }
205 }
206};
207
208
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400209/**
210 * \ingroup management
211 * \brief represents a faces/destroy command
212 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Destroy-a-face
Junxiao Shi5ec80222014-03-25 20:08:05 -0700213 */
214class FaceDestroyCommand : public ControlCommand
215{
216public:
217 FaceDestroyCommand()
218 : ControlCommand("faces", "destroy")
219 {
220 m_requestValidator
221 .required(CONTROL_PARAMETER_FACE_ID);
222 m_responseValidator = m_requestValidator;
223 }
224
225 virtual void
226 validateRequest(const ControlParameters& parameters) const
227 {
228 this->ControlCommand::validateRequest(parameters);
229
230 if (parameters.getFaceId() == 0) {
231 throw ArgumentError("FaceId must not be zero");
232 }
233 }
234
235 virtual void
236 validateResponse(const ControlParameters& parameters) const
237 {
238 this->validateRequest(parameters);
239 }
240};
241
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400242/**
243 * \ingroup management
244 * \brief Base class for faces/[*]-local-control commands
245 */
Junxiao Shi5ec80222014-03-25 20:08:05 -0700246class FaceLocalControlCommand : public ControlCommand
247{
Junxiao Shi6888bc12014-03-29 23:01:41 -0700248public:
249 virtual void
250 validateRequest(const ControlParameters& parameters) const
251 {
252 this->ControlCommand::validateRequest(parameters);
253
254 switch (parameters.getLocalControlFeature()) {
255 case LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID:
256 case LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID:
257 break;
258 default:
259 throw ArgumentError("LocalControlFeature is invalid");
260 }
261 }
262
263 virtual void
264 validateResponse(const ControlParameters& parameters) const
265 {
266 this->validateRequest(parameters);
267 }
268
Junxiao Shi5ec80222014-03-25 20:08:05 -0700269protected:
270 explicit
271 FaceLocalControlCommand(const std::string& verb)
272 : ControlCommand("faces", verb)
273 {
274 m_requestValidator
275 .required(CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE);
276 m_responseValidator = m_requestValidator;
277 }
278};
279
280
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400281/**
282 * \ingroup management
283 * \brief represents a faces/enable-local-control command
284 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Enable-a-LocalControlHeader-feature
Junxiao Shi5ec80222014-03-25 20:08:05 -0700285 */
286class FaceEnableLocalControlCommand : public FaceLocalControlCommand
287{
288public:
289 FaceEnableLocalControlCommand()
290 : FaceLocalControlCommand("enable-local-control")
291 {
292 }
293};
294
295
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400296/**
297 * \ingroup management
298 * \brief represents a faces/disable-local-control command
299 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Disable-a-LocalControlHeader-feature
Junxiao Shi5ec80222014-03-25 20:08:05 -0700300 */
301class FaceDisableLocalControlCommand : public FaceLocalControlCommand
302{
303public:
304 FaceDisableLocalControlCommand()
305 : FaceLocalControlCommand("disable-local-control")
306 {
307 }
308};
309
310
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400311/**
312 * \ingroup management
313 * \brief represents a fib/add-nexthop command
314 * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Add-a-nexthop
Junxiao Shi5ec80222014-03-25 20:08:05 -0700315 */
316class FibAddNextHopCommand : public ControlCommand
317{
318public:
319 FibAddNextHopCommand()
320 : ControlCommand("fib", "add-nexthop")
321 {
322 m_requestValidator
323 .required(CONTROL_PARAMETER_NAME)
324 .required(CONTROL_PARAMETER_FACE_ID)
325 .optional(CONTROL_PARAMETER_COST);
326 m_responseValidator
327 .required(CONTROL_PARAMETER_NAME)
328 .required(CONTROL_PARAMETER_FACE_ID)
329 .required(CONTROL_PARAMETER_COST);
330 }
331
332 virtual void
333 applyDefaultsToRequest(ControlParameters& parameters) const
334 {
335 if (!parameters.hasCost()) {
336 parameters.setCost(0);
337 }
338 }
339
340 virtual void
341 validateResponse(const ControlParameters& parameters) const
342 {
343 this->ControlCommand::validateResponse(parameters);
344
345 if (parameters.getFaceId() == 0) {
346 throw ArgumentError("FaceId must not be zero");
347 }
348 }
349};
350
351
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400352/**
353 * \ingroup management
354 * \brief represents a fib/remove-nexthop command
355 * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Remove-a-nexthop
Junxiao Shi5ec80222014-03-25 20:08:05 -0700356 */
357class FibRemoveNextHopCommand : public ControlCommand
358{
359public:
360 FibRemoveNextHopCommand()
361 : ControlCommand("fib", "remove-nexthop")
362 {
363 m_requestValidator
364 .required(CONTROL_PARAMETER_NAME)
365 .required(CONTROL_PARAMETER_FACE_ID);
366 m_responseValidator
367 .required(CONTROL_PARAMETER_NAME)
368 .required(CONTROL_PARAMETER_FACE_ID);
369 }
370
371 virtual void
372 validateResponse(const ControlParameters& parameters) const
373 {
374 this->ControlCommand::validateResponse(parameters);
375
376 if (parameters.getFaceId() == 0) {
377 throw ArgumentError("FaceId must not be zero");
378 }
379 }
380};
381
382
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400383/**
384 * \ingroup management
385 * \brief represents a strategy-choice/set command
386 * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Set-the-strategy-for-a-namespace
Junxiao Shi5ec80222014-03-25 20:08:05 -0700387 */
388class StrategyChoiceSetCommand : public ControlCommand
389{
390public:
391 StrategyChoiceSetCommand()
392 : ControlCommand("strategy-choice", "set")
393 {
394 m_requestValidator
395 .required(CONTROL_PARAMETER_NAME)
396 .required(CONTROL_PARAMETER_STRATEGY);
397 m_responseValidator = m_requestValidator;
398 }
399};
400
401
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400402/**
403 * \ingroup management
404 * \brief represents a strategy-choice/set command
405 * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Unset-the-strategy-for-a-namespace
Junxiao Shi5ec80222014-03-25 20:08:05 -0700406 */
407class StrategyChoiceUnsetCommand : public ControlCommand
408{
409public:
410 StrategyChoiceUnsetCommand()
411 : ControlCommand("strategy-choice", "unset")
412 {
413 m_requestValidator
414 .required(CONTROL_PARAMETER_NAME);
415 m_responseValidator = m_requestValidator;
416 }
417
418 virtual void
419 validateRequest(const ControlParameters& parameters) const
420 {
421 this->ControlCommand::validateRequest(parameters);
422
423 if (parameters.getName().size() == 0) {
424 throw ArgumentError("Name must not be ndn:/");
425 }
426 }
427
428 virtual void
429 validateResponse(const ControlParameters& parameters) const
430 {
431 this->validateRequest(parameters);
432 }
433};
434
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700435
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400436/**
437 * \ingroup management
438 */
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700439enum {
440 // route origin
441 ROUTE_ORIGIN_APP = 0,
442 ROUTE_ORIGIN_NLSR = 128,
443 ROUTE_ORIGIN_STATIC = 255,
444
445 // route inheritance flags
446 ROUTE_FLAG_CHILD_INHERIT = 1,
447 ROUTE_FLAG_CAPTURE = 2
448};
449
450
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400451/**
452 * \ingroup management
453 * \brief represents a rib/register command
454 * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Register-a-route
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700455 */
456class RibRegisterCommand : public ControlCommand
457{
458public:
459 RibRegisterCommand()
460 : ControlCommand("rib", "register")
461 {
462 m_requestValidator
463 .required(CONTROL_PARAMETER_NAME)
464 .optional(CONTROL_PARAMETER_FACE_ID)
465 .optional(CONTROL_PARAMETER_ORIGIN)
466 .optional(CONTROL_PARAMETER_COST)
467 .optional(CONTROL_PARAMETER_FLAGS)
468 .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD);
469 m_responseValidator
470 .required(CONTROL_PARAMETER_NAME)
471 .required(CONTROL_PARAMETER_FACE_ID)
472 .required(CONTROL_PARAMETER_ORIGIN)
473 .required(CONTROL_PARAMETER_COST)
474 .required(CONTROL_PARAMETER_FLAGS)
475 .required(CONTROL_PARAMETER_EXPIRATION_PERIOD);
476 }
477
478 virtual void
479 applyDefaultsToRequest(ControlParameters& parameters) const
480 {
481 if (!parameters.hasFaceId()) {
482 parameters.setFaceId(0);
483 }
484 if (!parameters.hasOrigin()) {
485 parameters.setOrigin(ROUTE_ORIGIN_APP);
486 }
487 if (!parameters.hasCost()) {
488 parameters.setCost(0);
489 }
490 if (!parameters.hasFlags()) {
491 parameters.setFlags(ROUTE_FLAG_CHILD_INHERIT);
492 }
493 if (!parameters.hasExpirationPeriod()) {
494 if (parameters.getFaceId() == 0) {
495 parameters.setExpirationPeriod(time::milliseconds::max());
496 }
497 else {
498 parameters.setExpirationPeriod(time::hours(1));
499 }
500 }
501 }
502
503 virtual void
504 validateResponse(const ControlParameters& parameters) const
505 {
506 this->ControlCommand::validateResponse(parameters);
507
508 if (parameters.getFaceId() == 0) {
509 throw ArgumentError("FaceId must not be zero");
510 }
511 }
512};
513
514
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400515/**
516 * \ingroup management
517 * \brief represents a rib/unregister command
518 * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Unregister-a-route
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700519 */
520class RibUnregisterCommand : public ControlCommand
521{
522public:
523 RibUnregisterCommand()
524 : ControlCommand("rib", "unregister")
525 {
526 m_requestValidator
527 .required(CONTROL_PARAMETER_NAME)
528 .optional(CONTROL_PARAMETER_FACE_ID)
529 .optional(CONTROL_PARAMETER_ORIGIN);
530 m_responseValidator
531 .required(CONTROL_PARAMETER_NAME)
532 .required(CONTROL_PARAMETER_FACE_ID)
533 .required(CONTROL_PARAMETER_ORIGIN);
534 }
535
536 virtual void
537 applyDefaultsToRequest(ControlParameters& parameters) const
538 {
539 if (!parameters.hasFaceId()) {
540 parameters.setFaceId(0);
541 }
542 if (!parameters.hasOrigin()) {
543 parameters.setOrigin(ROUTE_ORIGIN_APP);
544 }
545 }
546
547 virtual void
548 validateResponse(const ControlParameters& parameters) const
549 {
550 this->ControlCommand::validateResponse(parameters);
551
552 if (parameters.getFaceId() == 0) {
553 throw ArgumentError("FaceId must not be zero");
554 }
555 }
556};
557
558
Junxiao Shi5ec80222014-03-25 20:08:05 -0700559} // namespace nfd
560} // namespace ndn
561
562#endif // NDN_MANAGEMENT_NFD_CONTROL_COMMAND_HPP