blob: bde57253efd2d2bfa975e829d38fc8f537d05243 [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
22/** \brief base class of NFD ControlCommand
23 * \sa http://redmine.named-data.net/projects/nfd/wiki/ControlCommand
24 */
Junxiao Shi7b6b79d2014-03-26 20:59:35 -070025class ControlCommand : noncopyable
Junxiao Shi5ec80222014-03-25 20:08:05 -070026{
27public:
Yingdi Yue66bf2a2014-04-28 17:07:36 -070028 /** \brief a callback on signing command interest
29 */
30 typedef function<void(Interest&)> Sign;
31
Junxiao Shi5ec80222014-03-25 20:08:05 -070032 /** \brief represents an error in ControlParameters
33 */
34 class ArgumentError : public std::invalid_argument
35 {
36 public:
37 explicit
38 ArgumentError(const std::string& what)
39 : std::invalid_argument(what)
40 {
41 }
42 };
43
44 /** \return Name prefix of this ControlCommand
45 */
46 const Name&
47 getPrefix() const
48 {
49 return m_prefix;
50 }
51
52 /** \brief make a Command Interest from parameters
53 */
54 Interest
55 makeCommandInterest(const ControlParameters& parameters,
Yingdi Yue66bf2a2014-04-28 17:07:36 -070056 const Sign& sign) const
Junxiao Shi5ec80222014-03-25 20:08:05 -070057 {
58 this->validateRequest(parameters);
59
60 Name name = m_prefix;
61 name.append(parameters.wireEncode());
62 Interest commandInterest(name);
Yingdi Yue66bf2a2014-04-28 17:07:36 -070063 sign(commandInterest);
Junxiao Shi5ec80222014-03-25 20:08:05 -070064 return commandInterest;
65 }
66
67 /** \brief validate request parameters
68 * \throw ArgumentError
69 */
70 virtual void
71 validateRequest(const ControlParameters& parameters) const
72 {
73 m_requestValidator.validate(parameters);
74 }
75
76 /** \brief apply default values to missing fields in request
77 */
78 virtual void
79 applyDefaultsToRequest(ControlParameters& parameters) const
80 {
81 }
82
83 /** \brief validate response parameters
84 * \throw ArgumentError
85 */
86 virtual void
87 validateResponse(const ControlParameters& parameters) const
88 {
89 m_responseValidator.validate(parameters);
90 }
91
92 /** \brief apply default values to missing fields in response
93 */
94 virtual void
95 applyDefaultsToResponse(ControlParameters& parameters) const
96 {
97 }
98
99protected:
100 ControlCommand(const std::string& module, const std::string& verb)
101 : m_prefix("ndn:/localhost/nfd")
102 {
103 m_prefix.append(module).append(verb);
104 }
105
106 class FieldValidator
107 {
108 public:
109 FieldValidator()
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700110 : m_required(CONTROL_PARAMETER_UBOUND)
111 , m_optional(CONTROL_PARAMETER_UBOUND)
Junxiao Shi5ec80222014-03-25 20:08:05 -0700112 {
Junxiao Shi5ec80222014-03-25 20:08:05 -0700113 }
114
115 /** \brief declare a required field
116 */
117 FieldValidator&
118 required(ControlParameterField field)
119 {
120 m_required[field] = true;
121 return *this;
122 }
123
124 /** \brief declare an optional field
125 */
126 FieldValidator&
127 optional(ControlParameterField field)
128 {
129 m_optional[field] = true;
130 return *this;
131 }
132
133 /** \brief verify that all required fields are present,
134 * and all present fields are either required or optional
135 * \throw ArgumentError
136 */
137 void
138 validate(const ControlParameters& parameters) const
139 {
140 const std::vector<bool>& presentFields = parameters.getPresentFields();
141
142 for (size_t i = 0; i < CONTROL_PARAMETER_UBOUND; ++i) {
143 bool isPresent = presentFields[i];
144 if (m_required[i]) {
145 if (!isPresent) {
146 throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is required but missing");
147 }
148 }
149 else if (isPresent && !m_optional[i]) {
150 throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is forbidden but present");
151 }
152 }
153 }
154
155 private:
156 std::vector<bool> m_required;
157 std::vector<bool> m_optional;
158 };
159
160protected:
161 /** \brief FieldValidator for request ControlParameters
162 *
163 * Constructor of subclass should populate this validator.
164 */
165 FieldValidator m_requestValidator;
166 /** \brief FieldValidator for response ControlParameters
167 *
168 * Constructor of subclass should populate this validator.
169 */
170 FieldValidator m_responseValidator;
171
172private:
173 Name m_prefix;
174};
175
176
177/** \brief represents a faces/create command
178 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Create-a-face
179 */
180class FaceCreateCommand : public ControlCommand
181{
182public:
183 FaceCreateCommand()
184 : ControlCommand("faces", "create")
185 {
186 m_requestValidator
187 .required(CONTROL_PARAMETER_URI);
188 m_responseValidator
189 .required(CONTROL_PARAMETER_URI)
190 .required(CONTROL_PARAMETER_FACE_ID);
191 }
192
193 virtual void
194 validateResponse(const ControlParameters& parameters) const
195 {
196 this->ControlCommand::validateResponse(parameters);
197
198 if (parameters.getFaceId() == 0) {
199 throw ArgumentError("FaceId must not be zero");
200 }
201 }
202};
203
204
205/** \brief represents a faces/destroy command
206 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Destroy-a-face
207 */
208class FaceDestroyCommand : public ControlCommand
209{
210public:
211 FaceDestroyCommand()
212 : ControlCommand("faces", "destroy")
213 {
214 m_requestValidator
215 .required(CONTROL_PARAMETER_FACE_ID);
216 m_responseValidator = m_requestValidator;
217 }
218
219 virtual void
220 validateRequest(const ControlParameters& parameters) const
221 {
222 this->ControlCommand::validateRequest(parameters);
223
224 if (parameters.getFaceId() == 0) {
225 throw ArgumentError("FaceId must not be zero");
226 }
227 }
228
229 virtual void
230 validateResponse(const ControlParameters& parameters) const
231 {
232 this->validateRequest(parameters);
233 }
234};
235
236
237class FaceLocalControlCommand : public ControlCommand
238{
Junxiao Shi6888bc12014-03-29 23:01:41 -0700239public:
240 virtual void
241 validateRequest(const ControlParameters& parameters) const
242 {
243 this->ControlCommand::validateRequest(parameters);
244
245 switch (parameters.getLocalControlFeature()) {
246 case LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID:
247 case LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID:
248 break;
249 default:
250 throw ArgumentError("LocalControlFeature is invalid");
251 }
252 }
253
254 virtual void
255 validateResponse(const ControlParameters& parameters) const
256 {
257 this->validateRequest(parameters);
258 }
259
Junxiao Shi5ec80222014-03-25 20:08:05 -0700260protected:
261 explicit
262 FaceLocalControlCommand(const std::string& verb)
263 : ControlCommand("faces", verb)
264 {
265 m_requestValidator
266 .required(CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE);
267 m_responseValidator = m_requestValidator;
268 }
269};
270
271
272/** \brief represents a faces/enable-local-control command
273 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Enable-a-LocalControlHeader-feature
274 */
275class FaceEnableLocalControlCommand : public FaceLocalControlCommand
276{
277public:
278 FaceEnableLocalControlCommand()
279 : FaceLocalControlCommand("enable-local-control")
280 {
281 }
282};
283
284
285/** \brief represents a faces/disable-local-control command
286 * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Disable-a-LocalControlHeader-feature
287 */
288class FaceDisableLocalControlCommand : public FaceLocalControlCommand
289{
290public:
291 FaceDisableLocalControlCommand()
292 : FaceLocalControlCommand("disable-local-control")
293 {
294 }
295};
296
297
298/** \brief represents a fib/add-nexthop command
299 * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Add-a-nexthop
300 */
301class FibAddNextHopCommand : public ControlCommand
302{
303public:
304 FibAddNextHopCommand()
305 : ControlCommand("fib", "add-nexthop")
306 {
307 m_requestValidator
308 .required(CONTROL_PARAMETER_NAME)
309 .required(CONTROL_PARAMETER_FACE_ID)
310 .optional(CONTROL_PARAMETER_COST);
311 m_responseValidator
312 .required(CONTROL_PARAMETER_NAME)
313 .required(CONTROL_PARAMETER_FACE_ID)
314 .required(CONTROL_PARAMETER_COST);
315 }
316
317 virtual void
318 applyDefaultsToRequest(ControlParameters& parameters) const
319 {
320 if (!parameters.hasCost()) {
321 parameters.setCost(0);
322 }
323 }
324
325 virtual void
326 validateResponse(const ControlParameters& parameters) const
327 {
328 this->ControlCommand::validateResponse(parameters);
329
330 if (parameters.getFaceId() == 0) {
331 throw ArgumentError("FaceId must not be zero");
332 }
333 }
334};
335
336
337/** \brief represents a fib/remove-nexthop command
338 * \sa http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#Remove-a-nexthop
339 */
340class FibRemoveNextHopCommand : public ControlCommand
341{
342public:
343 FibRemoveNextHopCommand()
344 : ControlCommand("fib", "remove-nexthop")
345 {
346 m_requestValidator
347 .required(CONTROL_PARAMETER_NAME)
348 .required(CONTROL_PARAMETER_FACE_ID);
349 m_responseValidator
350 .required(CONTROL_PARAMETER_NAME)
351 .required(CONTROL_PARAMETER_FACE_ID);
352 }
353
354 virtual void
355 validateResponse(const ControlParameters& parameters) const
356 {
357 this->ControlCommand::validateResponse(parameters);
358
359 if (parameters.getFaceId() == 0) {
360 throw ArgumentError("FaceId must not be zero");
361 }
362 }
363};
364
365
366/** \brief represents a strategy-choice/set command
367 * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Set-the-strategy-for-a-namespace
368 */
369class StrategyChoiceSetCommand : public ControlCommand
370{
371public:
372 StrategyChoiceSetCommand()
373 : ControlCommand("strategy-choice", "set")
374 {
375 m_requestValidator
376 .required(CONTROL_PARAMETER_NAME)
377 .required(CONTROL_PARAMETER_STRATEGY);
378 m_responseValidator = m_requestValidator;
379 }
380};
381
382
383/** \brief represents a strategy-choice/set command
384 * \sa http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#Unset-the-strategy-for-a-namespace
385 */
386class StrategyChoiceUnsetCommand : public ControlCommand
387{
388public:
389 StrategyChoiceUnsetCommand()
390 : ControlCommand("strategy-choice", "unset")
391 {
392 m_requestValidator
393 .required(CONTROL_PARAMETER_NAME);
394 m_responseValidator = m_requestValidator;
395 }
396
397 virtual void
398 validateRequest(const ControlParameters& parameters) const
399 {
400 this->ControlCommand::validateRequest(parameters);
401
402 if (parameters.getName().size() == 0) {
403 throw ArgumentError("Name must not be ndn:/");
404 }
405 }
406
407 virtual void
408 validateResponse(const ControlParameters& parameters) const
409 {
410 this->validateRequest(parameters);
411 }
412};
413
Junxiao Shi5f6c74f2014-04-18 16:29:44 -0700414
415enum {
416 // route origin
417 ROUTE_ORIGIN_APP = 0,
418 ROUTE_ORIGIN_NLSR = 128,
419 ROUTE_ORIGIN_STATIC = 255,
420
421 // route inheritance flags
422 ROUTE_FLAG_CHILD_INHERIT = 1,
423 ROUTE_FLAG_CAPTURE = 2
424};
425
426
427/** \brief represents a rib/register command
428 * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Register-a-route
429 */
430class RibRegisterCommand : public ControlCommand
431{
432public:
433 RibRegisterCommand()
434 : ControlCommand("rib", "register")
435 {
436 m_requestValidator
437 .required(CONTROL_PARAMETER_NAME)
438 .optional(CONTROL_PARAMETER_FACE_ID)
439 .optional(CONTROL_PARAMETER_ORIGIN)
440 .optional(CONTROL_PARAMETER_COST)
441 .optional(CONTROL_PARAMETER_FLAGS)
442 .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD);
443 m_responseValidator
444 .required(CONTROL_PARAMETER_NAME)
445 .required(CONTROL_PARAMETER_FACE_ID)
446 .required(CONTROL_PARAMETER_ORIGIN)
447 .required(CONTROL_PARAMETER_COST)
448 .required(CONTROL_PARAMETER_FLAGS)
449 .required(CONTROL_PARAMETER_EXPIRATION_PERIOD);
450 }
451
452 virtual void
453 applyDefaultsToRequest(ControlParameters& parameters) const
454 {
455 if (!parameters.hasFaceId()) {
456 parameters.setFaceId(0);
457 }
458 if (!parameters.hasOrigin()) {
459 parameters.setOrigin(ROUTE_ORIGIN_APP);
460 }
461 if (!parameters.hasCost()) {
462 parameters.setCost(0);
463 }
464 if (!parameters.hasFlags()) {
465 parameters.setFlags(ROUTE_FLAG_CHILD_INHERIT);
466 }
467 if (!parameters.hasExpirationPeriod()) {
468 if (parameters.getFaceId() == 0) {
469 parameters.setExpirationPeriod(time::milliseconds::max());
470 }
471 else {
472 parameters.setExpirationPeriod(time::hours(1));
473 }
474 }
475 }
476
477 virtual void
478 validateResponse(const ControlParameters& parameters) const
479 {
480 this->ControlCommand::validateResponse(parameters);
481
482 if (parameters.getFaceId() == 0) {
483 throw ArgumentError("FaceId must not be zero");
484 }
485 }
486};
487
488
489/** \brief represents a rib/unregister command
490 * \sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Unregister-a-route
491 */
492class RibUnregisterCommand : public ControlCommand
493{
494public:
495 RibUnregisterCommand()
496 : ControlCommand("rib", "unregister")
497 {
498 m_requestValidator
499 .required(CONTROL_PARAMETER_NAME)
500 .optional(CONTROL_PARAMETER_FACE_ID)
501 .optional(CONTROL_PARAMETER_ORIGIN);
502 m_responseValidator
503 .required(CONTROL_PARAMETER_NAME)
504 .required(CONTROL_PARAMETER_FACE_ID)
505 .required(CONTROL_PARAMETER_ORIGIN);
506 }
507
508 virtual void
509 applyDefaultsToRequest(ControlParameters& parameters) const
510 {
511 if (!parameters.hasFaceId()) {
512 parameters.setFaceId(0);
513 }
514 if (!parameters.hasOrigin()) {
515 parameters.setOrigin(ROUTE_ORIGIN_APP);
516 }
517 }
518
519 virtual void
520 validateResponse(const ControlParameters& parameters) const
521 {
522 this->ControlCommand::validateResponse(parameters);
523
524 if (parameters.getFaceId() == 0) {
525 throw ArgumentError("FaceId must not be zero");
526 }
527 }
528};
529
530
Junxiao Shi5ec80222014-03-25 20:08:05 -0700531} // namespace nfd
532} // namespace ndn
533
534#endif // NDN_MANAGEMENT_NFD_CONTROL_COMMAND_HPP