blob: 6a16a1fcb7da871871d1e3bc5aebb2b73d390ab0 [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)
Junxiao Shicaac54e2014-05-20 15:27:01 -0700324 .optional(CONTROL_PARAMETER_FACE_ID)
Junxiao Shi5ec80222014-03-25 20:08:05 -0700325 .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 {
Junxiao Shicaac54e2014-05-20 15:27:01 -0700335 if (!parameters.hasFaceId()) {
336 parameters.setFaceId(0);
337 }
Junxiao Shi5ec80222014-03-25 20:08:05 -0700338 if (!parameters.hasCost()) {
339 parameters.setCost(0);
340 }
341 }
342
343 virtual void
344 validateResponse(const ControlParameters& parameters) const
345 {
346 this->ControlCommand::validateResponse(parameters);
347
348 if (parameters.getFaceId() == 0) {
349 throw ArgumentError("FaceId must not be zero");
350 }
351 }
352};
353
354
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400355/**
356 * \ingroup management
357 * \brief represents a fib/remove-nexthop command
358 * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Remove-a-nexthop
Junxiao Shi5ec80222014-03-25 20:08:05 -0700359 */
360class FibRemoveNextHopCommand : public ControlCommand
361{
362public:
363 FibRemoveNextHopCommand()
364 : ControlCommand("fib", "remove-nexthop")
365 {
366 m_requestValidator
367 .required(CONTROL_PARAMETER_NAME)
Junxiao Shicaac54e2014-05-20 15:27:01 -0700368 .optional(CONTROL_PARAMETER_FACE_ID);
Junxiao Shi5ec80222014-03-25 20:08:05 -0700369 m_responseValidator
370 .required(CONTROL_PARAMETER_NAME)
371 .required(CONTROL_PARAMETER_FACE_ID);
372 }
373
374 virtual void
Junxiao Shicaac54e2014-05-20 15:27:01 -0700375 applyDefaultsToRequest(ControlParameters& parameters) const
376 {
377 if (!parameters.hasFaceId()) {
378 parameters.setFaceId(0);
379 }
380 }
381
382 virtual void
Junxiao Shi5ec80222014-03-25 20:08:05 -0700383 validateResponse(const ControlParameters& parameters) const
384 {
385 this->ControlCommand::validateResponse(parameters);
386
387 if (parameters.getFaceId() == 0) {
388 throw ArgumentError("FaceId must not be zero");
389 }
390 }
391};
392
393
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400394/**
395 * \ingroup management
396 * \brief represents a strategy-choice/set command
397 * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Set-the-strategy-for-a-namespace
Junxiao Shi5ec80222014-03-25 20:08:05 -0700398 */
399class StrategyChoiceSetCommand : public ControlCommand
400{
401public:
402 StrategyChoiceSetCommand()
403 : ControlCommand("strategy-choice", "set")
404 {
405 m_requestValidator
406 .required(CONTROL_PARAMETER_NAME)
407 .required(CONTROL_PARAMETER_STRATEGY);
408 m_responseValidator = m_requestValidator;
409 }
410};
411
412
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400413/**
414 * \ingroup management
415 * \brief represents a strategy-choice/set command
416 * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Unset-the-strategy-for-a-namespace
Junxiao Shi5ec80222014-03-25 20:08:05 -0700417 */
418class StrategyChoiceUnsetCommand : public ControlCommand
419{
420public:
421 StrategyChoiceUnsetCommand()
422 : ControlCommand("strategy-choice", "unset")
423 {
424 m_requestValidator
425 .required(CONTROL_PARAMETER_NAME);
426 m_responseValidator = m_requestValidator;
427 }
428
429 virtual void
430 validateRequest(const ControlParameters& parameters) const
431 {
432 this->ControlCommand::validateRequest(parameters);
433
434 if (parameters.getName().size() == 0) {
435 throw ArgumentError("Name must not be ndn:/");
436 }
437 }
438
439 virtual void
440 validateResponse(const ControlParameters& parameters) const
441 {
442 this->validateRequest(parameters);
443 }
444};
445
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700446
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400447/**
448 * \ingroup management
449 */
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700450enum {
451 // route origin
452 ROUTE_ORIGIN_APP = 0,
453 ROUTE_ORIGIN_NLSR = 128,
454 ROUTE_ORIGIN_STATIC = 255,
455
456 // route inheritance flags
457 ROUTE_FLAG_CHILD_INHERIT = 1,
458 ROUTE_FLAG_CAPTURE = 2
459};
460
461
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400462/**
463 * \ingroup management
464 * \brief represents a rib/register command
465 * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Register-a-route
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700466 */
467class RibRegisterCommand : public ControlCommand
468{
469public:
470 RibRegisterCommand()
471 : ControlCommand("rib", "register")
472 {
473 m_requestValidator
474 .required(CONTROL_PARAMETER_NAME)
475 .optional(CONTROL_PARAMETER_FACE_ID)
476 .optional(CONTROL_PARAMETER_ORIGIN)
477 .optional(CONTROL_PARAMETER_COST)
478 .optional(CONTROL_PARAMETER_FLAGS)
479 .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD);
480 m_responseValidator
481 .required(CONTROL_PARAMETER_NAME)
482 .required(CONTROL_PARAMETER_FACE_ID)
483 .required(CONTROL_PARAMETER_ORIGIN)
484 .required(CONTROL_PARAMETER_COST)
485 .required(CONTROL_PARAMETER_FLAGS)
486 .required(CONTROL_PARAMETER_EXPIRATION_PERIOD);
487 }
488
489 virtual void
490 applyDefaultsToRequest(ControlParameters& parameters) const
491 {
492 if (!parameters.hasFaceId()) {
493 parameters.setFaceId(0);
494 }
495 if (!parameters.hasOrigin()) {
496 parameters.setOrigin(ROUTE_ORIGIN_APP);
497 }
498 if (!parameters.hasCost()) {
499 parameters.setCost(0);
500 }
501 if (!parameters.hasFlags()) {
502 parameters.setFlags(ROUTE_FLAG_CHILD_INHERIT);
503 }
504 if (!parameters.hasExpirationPeriod()) {
505 if (parameters.getFaceId() == 0) {
506 parameters.setExpirationPeriod(time::milliseconds::max());
507 }
508 else {
509 parameters.setExpirationPeriod(time::hours(1));
510 }
511 }
512 }
513
514 virtual void
515 validateResponse(const ControlParameters& parameters) const
516 {
517 this->ControlCommand::validateResponse(parameters);
518
519 if (parameters.getFaceId() == 0) {
520 throw ArgumentError("FaceId must not be zero");
521 }
522 }
523};
524
525
Alexander Afanasyev4671bf72014-05-19 09:01:37 -0400526/**
527 * \ingroup management
528 * \brief represents a rib/unregister command
529 * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Unregister-a-route
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700530 */
531class RibUnregisterCommand : public ControlCommand
532{
533public:
534 RibUnregisterCommand()
535 : ControlCommand("rib", "unregister")
536 {
537 m_requestValidator
538 .required(CONTROL_PARAMETER_NAME)
539 .optional(CONTROL_PARAMETER_FACE_ID)
540 .optional(CONTROL_PARAMETER_ORIGIN);
541 m_responseValidator
542 .required(CONTROL_PARAMETER_NAME)
543 .required(CONTROL_PARAMETER_FACE_ID)
544 .required(CONTROL_PARAMETER_ORIGIN);
545 }
546
547 virtual void
548 applyDefaultsToRequest(ControlParameters& parameters) const
549 {
550 if (!parameters.hasFaceId()) {
551 parameters.setFaceId(0);
552 }
553 if (!parameters.hasOrigin()) {
554 parameters.setOrigin(ROUTE_ORIGIN_APP);
555 }
556 }
557
558 virtual void
559 validateResponse(const ControlParameters& parameters) const
560 {
561 this->ControlCommand::validateResponse(parameters);
562
563 if (parameters.getFaceId() == 0) {
564 throw ArgumentError("FaceId must not be zero");
565 }
566 }
567};
568
569
Junxiao Shi5ec80222014-03-25 20:08:05 -0700570} // namespace nfd
571} // namespace ndn
572
573#endif // NDN_MANAGEMENT_NFD_CONTROL_COMMAND_HPP