mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[3793] {create,parse}{Command,Answer} methods updated to new format
createCommand, parseCommand, createAnswer, parseAnswer updated to an new format described here: http://kea.isc.org/wiki/StatsDesign
This commit is contained in:
@@ -17,7 +17,6 @@ lib_LTLIBRARIES = libkea-cc.la
|
|||||||
libkea_cc_la_SOURCES = data.cc data.h
|
libkea_cc_la_SOURCES = data.cc data.h
|
||||||
libkea_cc_la_SOURCES += logger.cc logger.h
|
libkea_cc_la_SOURCES += logger.cc logger.h
|
||||||
nodist_libkea_cc_la_SOURCES = cc_messages.cc cc_messages.h
|
nodist_libkea_cc_la_SOURCES = cc_messages.cc cc_messages.h
|
||||||
libkea_cc_la_SOURCES += proto_defs.cc proto_defs.h
|
|
||||||
libkea_cc_la_LIBADD = $(top_builddir)/src/lib/log/libkea-log.la
|
libkea_cc_la_LIBADD = $(top_builddir)/src/lib/log/libkea-log.la
|
||||||
|
|
||||||
CLEANFILES = *.gcno *.gcda session_config.h cc_messages.cc cc_messages.h \
|
CLEANFILES = *.gcno *.gcda session_config.h cc_messages.cc cc_messages.h \
|
||||||
@@ -32,11 +31,6 @@ s-messages: cc_messages.mes
|
|||||||
$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/cc/cc_messages.mes
|
$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/cc/cc_messages.mes
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
BUILT_SOURCES = session_config.h cc_messages.cc cc_messages.h proto_defs.h
|
BUILT_SOURCES = session_config.h cc_messages.cc cc_messages.h
|
||||||
|
|
||||||
# This rule is here, but we added proto_defs.h to the git repo,
|
|
||||||
# so the script is no longer needed.
|
|
||||||
#proto_defs.h: $(top_srcdir)/src/lib/util/python/const2hdr.py proto_defs.cc
|
|
||||||
# $(PYTHON) $(top_srcdir)/src/lib/util/python/const2hdr.py $(srcdir)/proto_defs.cc $@
|
|
||||||
|
|
||||||
EXTRA_DIST = cc_messages.mes
|
EXTRA_DIST = cc_messages.mes
|
||||||
|
@@ -1,58 +0,0 @@
|
|||||||
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
|
||||||
// copyright notice and this permission notice appear in all copies.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
||||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
||||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
||||||
// PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
#include <cc/proto_defs.h>
|
|
||||||
|
|
||||||
namespace isc {
|
|
||||||
namespace cc {
|
|
||||||
|
|
||||||
// Aside from defining the values for the C++ library, this file is also
|
|
||||||
// used as direct input of the generator of the python counterpart. Please,
|
|
||||||
// keep the syntax here simple and check the generated file
|
|
||||||
// (lib/python/isc/cc/proto_defs.py) is correct and sane.
|
|
||||||
|
|
||||||
// The constants used in the CC protocol
|
|
||||||
// First the header names
|
|
||||||
const char* const CC_HEADER_TYPE = "type";
|
|
||||||
const char* const CC_HEADER_FROM = "from";
|
|
||||||
const char* const CC_HEADER_TO = "to";
|
|
||||||
const char* const CC_HEADER_GROUP = "group";
|
|
||||||
const char* const CC_HEADER_INSTANCE = "instance";
|
|
||||||
const char* const CC_HEADER_SEQ = "seq";
|
|
||||||
const char* const CC_HEADER_WANT_ANSWER = "want_answer";
|
|
||||||
const char* const CC_HEADER_REPLY = "reply";
|
|
||||||
// The commands in the "type" header
|
|
||||||
const char* const CC_COMMAND_SEND = "send";
|
|
||||||
const char* const CC_COMMAND_SUBSCRIBE = "subscribe";
|
|
||||||
const char* const CC_COMMAND_UNSUBSCRIBE = "unsubscribe";
|
|
||||||
const char* const CC_COMMAND_GET_LNAME = "getlname";
|
|
||||||
const char* const CC_COMMAND_PING = "ping";
|
|
||||||
const char* const CC_COMMAND_PONG = "pong";
|
|
||||||
const char* const CC_COMMAND_STOP = "stop";
|
|
||||||
// The wildcards of some headers
|
|
||||||
const char* const CC_TO_WILDCARD = "*";
|
|
||||||
const char* const CC_INSTANCE_WILDCARD = "*";
|
|
||||||
// Prefixes for groups
|
|
||||||
const char* const CC_GROUP_NOTIFICATION_PREFIX = "notifications/";
|
|
||||||
// Reply codes
|
|
||||||
const int CC_REPLY_NO_RECPT = -1;
|
|
||||||
const int CC_REPLY_SUCCESS = 0;
|
|
||||||
// Payload in the message
|
|
||||||
const char *const CC_PAYLOAD_LNAME = "lname";
|
|
||||||
const char *const CC_PAYLOAD_RESULT = "result";
|
|
||||||
const char *const CC_PAYLOAD_COMMAND = "command";
|
|
||||||
const char *const CC_PAYLOAD_NOTIFICATION = "notification";
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,73 +0,0 @@
|
|||||||
// This file is generated from ./proto_defs.cc
|
|
||||||
// by the const2hdr.py script.
|
|
||||||
// Do not edit, all changes will be lost.
|
|
||||||
|
|
||||||
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
|
||||||
// copyright notice and this permission notice appear in all copies.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
|
||||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
||||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
||||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
||||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
||||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
||||||
// PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
#ifndef KEA_COMMON_DEFS_H
|
|
||||||
#define KEA_COMMON_DEFS_H
|
|
||||||
|
|
||||||
// \file proto_defs.h
|
|
||||||
// \brief Common shared constants
|
|
||||||
|
|
||||||
// This file contains common definitions of constasts used across the sources.
|
|
||||||
// It includes, but is not limited to the definitions of messages sent from
|
|
||||||
// one process to another. Since the names should be self-explanatory and
|
|
||||||
// the variables here are used mostly to synchronize the same values across
|
|
||||||
// multiple programs, separate documentation for each variable is not provided.
|
|
||||||
|
|
||||||
namespace isc {
|
|
||||||
namespace cc {
|
|
||||||
|
|
||||||
// Aside from defining the values for the C++ library, this file is also
|
|
||||||
// used as direct input of the generator of the python counterpart. Please,
|
|
||||||
// keep the syntax here simple and check the generated file
|
|
||||||
// (lib/python/isc/cc/proto_defs.py) is correct and sane.
|
|
||||||
|
|
||||||
// The constants used in the CC protocol
|
|
||||||
// First the header names
|
|
||||||
extern const char* const CC_HEADER_TYPE;
|
|
||||||
extern const char* const CC_HEADER_FROM;
|
|
||||||
extern const char* const CC_HEADER_TO;
|
|
||||||
extern const char* const CC_HEADER_GROUP;
|
|
||||||
extern const char* const CC_HEADER_INSTANCE;
|
|
||||||
extern const char* const CC_HEADER_SEQ;
|
|
||||||
extern const char* const CC_HEADER_WANT_ANSWER;
|
|
||||||
extern const char* const CC_HEADER_REPLY;
|
|
||||||
// The commands in the "type" header
|
|
||||||
extern const char* const CC_COMMAND_SEND;
|
|
||||||
extern const char* const CC_COMMAND_SUBSCRIBE;
|
|
||||||
extern const char* const CC_COMMAND_UNSUBSCRIBE;
|
|
||||||
extern const char* const CC_COMMAND_GET_LNAME;
|
|
||||||
extern const char* const CC_COMMAND_PING;
|
|
||||||
extern const char* const CC_COMMAND_PONG;
|
|
||||||
extern const char* const CC_COMMAND_STOP;
|
|
||||||
// The wildcards of some headers
|
|
||||||
extern const char* const CC_TO_WILDCARD;
|
|
||||||
extern const char* const CC_INSTANCE_WILDCARD;
|
|
||||||
// Prefixes for groups
|
|
||||||
extern const char* const CC_GROUP_NOTIFICATION_PREFIX;
|
|
||||||
// Reply codes
|
|
||||||
extern const int CC_REPLY_NO_RECPT;
|
|
||||||
extern const int CC_REPLY_SUCCESS;
|
|
||||||
// Payload in the message
|
|
||||||
extern const char *const CC_PAYLOAD_LNAME;
|
|
||||||
extern const char *const CC_PAYLOAD_RESULT;
|
|
||||||
extern const char *const CC_PAYLOAD_COMMAND;
|
|
||||||
extern const char *const CC_PAYLOAD_NOTIFICATION;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
@@ -53,70 +53,78 @@ using isc::data::JSONError;
|
|||||||
namespace isc {
|
namespace isc {
|
||||||
namespace config {
|
namespace config {
|
||||||
|
|
||||||
/// Creates a standard config/command protocol answer message
|
const char *CONTROL_COMMAND="command";
|
||||||
|
|
||||||
|
const char *CONTROL_RESULT="result";
|
||||||
|
const char *CONTROL_TEXT="text";
|
||||||
|
const char *CONTROL_ARGUMENTS="arguments";
|
||||||
|
|
||||||
|
// Full version, with status, text and arguments
|
||||||
|
ConstElementPtr
|
||||||
|
createAnswer(const int status_code, const std::string& text,
|
||||||
|
const ConstElementPtr& arg) {
|
||||||
|
if (status_code != 0 && text.empty()) {
|
||||||
|
isc_throw(CtrlChannelError, "Text has to be provided for status_code != 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementPtr answer = Element::createMap();
|
||||||
|
ElementPtr result = Element::create(status_code);
|
||||||
|
answer->set(CONTROL_RESULT, result);
|
||||||
|
|
||||||
|
if (!text.empty()) {
|
||||||
|
answer->set(CONTROL_TEXT, Element::create(text));
|
||||||
|
}
|
||||||
|
if (arg) {
|
||||||
|
answer->set(CONTROL_ARGUMENTS, arg);
|
||||||
|
}
|
||||||
|
return (answer);
|
||||||
|
}
|
||||||
|
|
||||||
ConstElementPtr
|
ConstElementPtr
|
||||||
createAnswer() {
|
createAnswer() {
|
||||||
ElementPtr answer = Element::createMap();
|
return (createAnswer(0, string(""), ConstElementPtr()));
|
||||||
ElementPtr answer_content = Element::createList();
|
|
||||||
answer_content->add(Element::create(isc::cc::CC_REPLY_SUCCESS));
|
|
||||||
answer->set(isc::cc::CC_PAYLOAD_RESULT, answer_content);
|
|
||||||
|
|
||||||
return (answer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstElementPtr
|
ConstElementPtr
|
||||||
createAnswer(const int rcode, ConstElementPtr arg) {
|
createAnswer(const int status_code, const std::string& text) {
|
||||||
if (rcode != 0 && (!arg || arg->getType() != Element::string)) {
|
return (createAnswer(status_code, text, ElementPtr()));
|
||||||
isc_throw(CCSessionError, "Bad or no argument for rcode != 0");
|
|
||||||
}
|
|
||||||
ElementPtr answer = Element::createMap();
|
|
||||||
ElementPtr answer_content = Element::createList();
|
|
||||||
answer_content->add(Element::create(rcode));
|
|
||||||
answer_content->add(arg);
|
|
||||||
answer->set(isc::cc::CC_PAYLOAD_RESULT, answer_content);
|
|
||||||
|
|
||||||
return (answer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstElementPtr
|
ConstElementPtr
|
||||||
createAnswer(const int rcode, const std::string& arg) {
|
createAnswer(const int status_code, const ConstElementPtr& arg) {
|
||||||
ElementPtr answer = Element::createMap();
|
return (createAnswer(status_code, "", arg));
|
||||||
ElementPtr answer_content = Element::createList();
|
|
||||||
answer_content->add(Element::create(rcode));
|
|
||||||
answer_content->add(Element::create(arg));
|
|
||||||
answer->set(isc::cc::CC_PAYLOAD_RESULT, answer_content);
|
|
||||||
|
|
||||||
return (answer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstElementPtr
|
ConstElementPtr
|
||||||
parseAnswer(int &rcode, ConstElementPtr msg) {
|
parseAnswer(int &rcode, const ConstElementPtr& msg) {
|
||||||
if (msg &&
|
if (!msg) {
|
||||||
msg->getType() == Element::map &&
|
isc_throw(CtrlChannelError, "No answer specified");
|
||||||
msg->contains(isc::cc::CC_PAYLOAD_RESULT)) {
|
|
||||||
ConstElementPtr result = msg->get(isc::cc::CC_PAYLOAD_RESULT);
|
|
||||||
if (result->getType() != Element::list) {
|
|
||||||
isc_throw(CCSessionError, "Result element in answer message is not a list");
|
|
||||||
} else if (result->get(0)->getType() != Element::integer) {
|
|
||||||
isc_throw(CCSessionError, "First element of result is not an rcode in answer message");
|
|
||||||
}
|
}
|
||||||
rcode = result->get(0)->intValue();
|
if (msg->getType() != Element::map) {
|
||||||
if (result->size() > 1) {
|
isc_throw(CtrlChannelError,
|
||||||
if (rcode == 0 || result->get(1)->getType() == Element::string) {
|
"Invalid answer Element specified, expected map");
|
||||||
return (result->get(1));
|
|
||||||
} else {
|
|
||||||
isc_throw(CCSessionError, "Error description in result with rcode != 0 is not a string");
|
|
||||||
}
|
}
|
||||||
} else {
|
if (!msg->contains(CONTROL_RESULT)) {
|
||||||
if (rcode == 0) {
|
isc_throw(CtrlChannelError,
|
||||||
return (ElementPtr());
|
"Invalid answer specified, does not contain mandatory 'result'");
|
||||||
} else {
|
|
||||||
isc_throw(CCSessionError, "Result with rcode != 0 does not have an error description");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConstElementPtr result = msg->get(CONTROL_RESULT);
|
||||||
|
if (result->getType() != Element::integer) {
|
||||||
|
isc_throw(CtrlChannelError,
|
||||||
|
"Result element in answer message is not a string");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
isc_throw(CCSessionError, "No result part in answer message");
|
rcode = result->intValue();
|
||||||
|
|
||||||
|
// If there are arguments, return them.
|
||||||
|
ConstElementPtr args = msg->get(CONTROL_ARGUMENTS);
|
||||||
|
if (args) {
|
||||||
|
return (args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There are no arguments, let's try to return just the text status
|
||||||
|
return (msg->get(CONTROL_TEXT));
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstElementPtr
|
ConstElementPtr
|
||||||
@@ -126,37 +134,37 @@ createCommand(const std::string& command) {
|
|||||||
|
|
||||||
ConstElementPtr
|
ConstElementPtr
|
||||||
createCommand(const std::string& command, ConstElementPtr arg) {
|
createCommand(const std::string& command, ConstElementPtr arg) {
|
||||||
ElementPtr cmd = Element::createMap();
|
ElementPtr query = Element::createMap();
|
||||||
ElementPtr cmd_parts = Element::createList();
|
ElementPtr cmd = Element::create(command);
|
||||||
cmd_parts->add(Element::create(command));
|
query->set(CONTROL_COMMAND, cmd);
|
||||||
if (arg) {
|
if (arg) {
|
||||||
cmd_parts->add(arg);
|
query->set(CONTROL_ARGUMENTS, arg);
|
||||||
}
|
}
|
||||||
cmd->set(isc::cc::CC_PAYLOAD_COMMAND, cmd_parts);
|
return (query);
|
||||||
return (cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
parseCommand(ConstElementPtr& arg, ConstElementPtr command) {
|
parseCommand(ConstElementPtr& arg, ConstElementPtr command) {
|
||||||
if (command &&
|
if (!command) {
|
||||||
command->getType() == Element::map &&
|
isc_throw(CtrlChannelError, "No command specified");
|
||||||
command->contains(isc::cc::CC_PAYLOAD_COMMAND)) {
|
|
||||||
ConstElementPtr cmd = command->get(isc::cc::CC_PAYLOAD_COMMAND);
|
|
||||||
if (cmd->getType() == Element::list &&
|
|
||||||
!cmd->empty() &&
|
|
||||||
cmd->get(0)->getType() == Element::string) {
|
|
||||||
if (cmd->size() > 1) {
|
|
||||||
arg = cmd->get(1);
|
|
||||||
} else {
|
|
||||||
arg = Element::createMap();
|
|
||||||
}
|
}
|
||||||
return (cmd->get(0)->stringValue());
|
if (command->getType() != Element::map) {
|
||||||
} else {
|
isc_throw(CtrlChannelError, "Invalid command Element specified, expected map");
|
||||||
isc_throw(CCSessionError, "Command part in command message missing, empty, or not a list");
|
|
||||||
}
|
}
|
||||||
} else {
|
if (!command->contains(CONTROL_COMMAND)) {
|
||||||
isc_throw(CCSessionError, "Command Element empty or not a map with \"command\"");
|
isc_throw(CtrlChannelError,
|
||||||
|
"Invalid answer specified, does not contain mandatory 'command'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConstElementPtr cmd = command->get(CONTROL_COMMAND);
|
||||||
|
if (cmd->getType() != Element::string) {
|
||||||
|
isc_throw(CtrlChannelError,
|
||||||
|
"'command' element in command message is not a string");
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = command->get(CONTROL_ARGUMENTS);
|
||||||
|
|
||||||
|
return (cmd->stringValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@@ -19,7 +19,6 @@
|
|||||||
#include <config/module_spec.h>
|
#include <config/module_spec.h>
|
||||||
|
|
||||||
#include <cc/data.h>
|
#include <cc/data.h>
|
||||||
#include <cc/proto_defs.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
@@ -28,112 +27,97 @@
|
|||||||
namespace isc {
|
namespace isc {
|
||||||
namespace config {
|
namespace config {
|
||||||
|
|
||||||
///
|
extern const char *CONTROL_COMMAND;
|
||||||
/// \brief Creates a standard config/command level success answer message
|
|
||||||
/// (i.e. of the form { "result": [ 0 ] }
|
extern const char *CONTROL_RESULT;
|
||||||
/// \return Standard command/config success answer message
|
extern const char *CONTROL_TEXT;
|
||||||
|
extern const char *CONTROL_ARGUMENTS;
|
||||||
|
|
||||||
|
const int CONTROL_RESULT_SUCCESS = 0;
|
||||||
|
const int CONTROL_RESULT_ERROR = 1;
|
||||||
|
|
||||||
|
/// @brief Creates a standard config/command level success answer message
|
||||||
|
/// (i.e. of the form { "result": 0 }
|
||||||
|
/// @return Standard command/config success answer message
|
||||||
isc::data::ConstElementPtr createAnswer();
|
isc::data::ConstElementPtr createAnswer();
|
||||||
|
|
||||||
|
/// @brief Creates a standard config/command level answer message
|
||||||
|
/// (i.e. of the form { "result": 1, "text": "Invalid command received" }
|
||||||
///
|
///
|
||||||
/// \brief Creates a standard config/command level answer message
|
/// @param status_code The return code (0 for success)
|
||||||
/// (i.e. of the form { "result": [ rcode, arg ] }
|
/// @param status_text A string to put into the "text" argument
|
||||||
|
/// @return Standard command/config answer message
|
||||||
|
isc::data::ConstElementPtr createAnswer(const int status_code,
|
||||||
|
const std::string& status_text);
|
||||||
|
|
||||||
|
/// @brief Creates a standard config/command level answer message
|
||||||
|
/// (i.e. of the form { "result": status_code, "arguments": arg }
|
||||||
|
///
|
||||||
|
/// @param status_code The return code (0 for success)
|
||||||
|
/// @param status_text A string to put into the "text" argument
|
||||||
|
/// @return Standard command/config answer message
|
||||||
|
isc::data::ConstElementPtr createAnswer(const int status_code,
|
||||||
|
const isc::data::ConstElementPtr& arg);
|
||||||
|
|
||||||
|
/// @brief Creates a standard config/command level answer message
|
||||||
|
/// (i.e. of the form { "result": X, "[ rcode, arg ] }
|
||||||
/// If rcode != 0, arg must be a StringElement
|
/// If rcode != 0, arg must be a StringElement
|
||||||
///
|
///
|
||||||
/// \param rcode The return code (0 for success)
|
/// @param status_code The return code (0 for success)
|
||||||
/// \param arg For rcode == 0, this is an optional argument of any
|
/// @param arg For status_code == 0, this is an optional argument of any
|
||||||
/// Element type. For rcode == 1, this argument is mandatory,
|
/// Element type. For status_code == 1, this argument is mandatory,
|
||||||
/// and must be a StringElement containing an error description
|
/// and may be any type of ElementPtr.
|
||||||
/// \return Standard command/config answer message
|
/// @return Standard command/config answer message
|
||||||
isc::data::ConstElementPtr createAnswer(const int rcode,
|
isc::data::ConstElementPtr createAnswer(const int status_code,
|
||||||
isc::data::ConstElementPtr arg);
|
const std::string& status,
|
||||||
|
const isc::data::ConstElementPtr& arg);
|
||||||
|
|
||||||
|
/// @brief Parses a standard config/command level answer message.
|
||||||
///
|
///
|
||||||
/// \brief Creates a standard config/command level answer message
|
/// @param status_code This value will be set to the return code contained in
|
||||||
/// (i.e. of the form { "result": [ rcode, arg ] }
|
|
||||||
///
|
|
||||||
/// \param rcode The return code (0 for success)
|
|
||||||
/// \param arg A string to put into the StringElement argument
|
|
||||||
/// \return Standard command/config answer message
|
|
||||||
isc::data::ConstElementPtr createAnswer(const int rcode,
|
|
||||||
const std::string& arg);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Parses a standard config/command level answer message
|
|
||||||
///
|
|
||||||
/// \param rcode This value will be set to the return code contained in
|
|
||||||
/// the message
|
/// the message
|
||||||
/// \param msg The message to parse
|
/// @param msg The message to parse
|
||||||
/// \return The optional argument in the message, or an empty ElementPtr
|
/// @return The optional argument in the message, or an empty ElementPtr
|
||||||
/// if there was no argument. If rcode != 0, this contains a
|
/// if there was no argument. If rcode != 0, this contains a
|
||||||
/// StringElement with the error description.
|
/// StringElement with the error description.
|
||||||
isc::data::ConstElementPtr parseAnswer(int &rcode,
|
isc::data::ConstElementPtr parseAnswer(int &status_code,
|
||||||
isc::data::ConstElementPtr msg);
|
const isc::data::ConstElementPtr& msg);
|
||||||
|
|
||||||
|
/// @brief Creates a standard config/command command message with no
|
||||||
|
/// argument (of the form { "command": "my_command" }
|
||||||
///
|
///
|
||||||
/// \brief Creates a standard config/command command message with no
|
/// @param command The command string
|
||||||
/// argument (of the form { "command": [ "my_command" ] }
|
/// @return The created message
|
||||||
///
|
|
||||||
/// \param command The command string
|
|
||||||
/// \return The created message
|
|
||||||
isc::data::ConstElementPtr createCommand(const std::string& command);
|
isc::data::ConstElementPtr createCommand(const std::string& command);
|
||||||
|
|
||||||
|
/// @brief Creates a standard config/command command message with the
|
||||||
|
/// given argument (of the form { "command": "my_command", "arguments": arg }
|
||||||
///
|
///
|
||||||
/// \brief Creates a standard config/command command message with the
|
/// @param command The command string
|
||||||
/// given argument (of the form { "command": [ "my_command", arg ] }
|
/// @param arg The optional argument for the command. This can be of
|
||||||
///
|
|
||||||
/// \param command The command string
|
|
||||||
/// \param arg The optional argument for the command. This can be of
|
|
||||||
/// any Element type, but it should conform to the .spec file.
|
/// any Element type, but it should conform to the .spec file.
|
||||||
/// \return The created message
|
/// @return The created message
|
||||||
isc::data::ConstElementPtr createCommand(const std::string& command,
|
isc::data::ConstElementPtr createCommand(const std::string& command,
|
||||||
isc::data::ConstElementPtr arg);
|
isc::data::ConstElementPtr arg);
|
||||||
|
|
||||||
///
|
/// @brief Parses the given command into a string containing the actual
|
||||||
/// \brief Parses the given command into a string containing the actual
|
|
||||||
/// command and an ElementPtr containing the optional argument.
|
/// command and an ElementPtr containing the optional argument.
|
||||||
///
|
///
|
||||||
/// Raises a CCSessionError if this is not a well-formed command
|
/// @throw Raises a CtrlChannelError if this is not a well-formed command
|
||||||
///
|
///
|
||||||
/// Example code: (command_message is a ConstElementPtr that is
|
/// @param arg This value will be set to the ElementPtr pointing to
|
||||||
/// passed here)
|
|
||||||
/// \code
|
|
||||||
/// ElementPtr command_message = Element::fromJSON("{ \"command\": [\"foo\", { \"bar\": 123 } ] }");
|
|
||||||
/// try {
|
|
||||||
/// ConstElementPtr args;
|
|
||||||
/// std::string command_str = parseCommand(args, command_message);
|
|
||||||
/// if (command_str == "foo") {
|
|
||||||
/// std::cout << "The command 'foo' was given" << std::endl;
|
|
||||||
/// if (args->contains("bar")) {
|
|
||||||
/// std::cout << "It had argument name 'bar' set, which has"
|
|
||||||
/// << "value "
|
|
||||||
/// << args->get("bar")->intValue();
|
|
||||||
/// }
|
|
||||||
/// } else {
|
|
||||||
/// std::cout << "Unknown command '" << command_str << std::endl;
|
|
||||||
/// }
|
|
||||||
/// } catch (CCSessionError cse) {
|
|
||||||
/// std::cerr << "Bad command in CC Session: "
|
|
||||||
/// << cse.what() << std::endl;
|
|
||||||
/// }
|
|
||||||
/// \endcode
|
|
||||||
///
|
|
||||||
/// \param arg This value will be set to the ElementPtr pointing to
|
|
||||||
/// the argument, or to an empty Map (ElementPtr) if there was none.
|
/// the argument, or to an empty Map (ElementPtr) if there was none.
|
||||||
/// \param command The command message containing the command (as made
|
/// @param command The command message containing the command (as made
|
||||||
/// by createCommand()
|
/// by createCommand()
|
||||||
/// \return The command name
|
/// \return The command name
|
||||||
std::string parseCommand(isc::data::ConstElementPtr& arg,
|
std::string parseCommand(isc::data::ConstElementPtr& arg,
|
||||||
isc::data::ConstElementPtr command);
|
isc::data::ConstElementPtr command);
|
||||||
|
|
||||||
|
/// @brief A standard control channel exception that is thrown if a function
|
||||||
///
|
|
||||||
/// \brief A standard cc session exception that is thrown if a function
|
|
||||||
/// is there is a problem with one of the messages
|
/// is there is a problem with one of the messages
|
||||||
///
|
class CtrlChannelError : public isc::Exception {
|
||||||
// todo: include types and called function in the exception
|
|
||||||
class CCSessionError : public isc::Exception {
|
|
||||||
public:
|
public:
|
||||||
CCSessionError(const char* file, size_t line, const char* what) :
|
CtrlChannelError(const char* file, size_t line, const char* what) :
|
||||||
isc::Exception(file, line, what) {}
|
isc::Exception(file, line, what) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
using namespace isc::data;
|
using namespace isc::data;
|
||||||
using namespace isc::config;
|
using namespace isc::config;
|
||||||
using namespace isc::cc;
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -50,16 +49,17 @@ protected:
|
|||||||
TEST_F(CCSessionTest, createAnswer) {
|
TEST_F(CCSessionTest, createAnswer) {
|
||||||
ConstElementPtr answer;
|
ConstElementPtr answer;
|
||||||
answer = createAnswer();
|
answer = createAnswer();
|
||||||
EXPECT_EQ("{ \"result\": [ 0 ] }", answer->str());
|
EXPECT_EQ("{ \"result\": 0 }", answer->str());
|
||||||
answer = createAnswer(1, "error");
|
answer = createAnswer(1, "error");
|
||||||
EXPECT_EQ("{ \"result\": [ 1, \"error\" ] }", answer->str());
|
EXPECT_EQ("{ \"result\": 1, \"text\": \"error\" }", answer->str());
|
||||||
|
|
||||||
EXPECT_THROW(createAnswer(1, ElementPtr()), CCSessionError);
|
EXPECT_THROW(createAnswer(1, ElementPtr()), CtrlChannelError);
|
||||||
EXPECT_THROW(createAnswer(1, Element::create(1)), CCSessionError);
|
EXPECT_THROW(createAnswer(1, Element::create(1)), CtrlChannelError);
|
||||||
|
|
||||||
ConstElementPtr arg = el("[ \"just\", \"some\", \"data\" ]");
|
ConstElementPtr arg = el("[ \"just\", \"some\", \"data\" ]");
|
||||||
answer = createAnswer(0, arg);
|
answer = createAnswer(0, arg);
|
||||||
EXPECT_EQ("{ \"result\": [ 0, [ \"just\", \"some\", \"data\" ] ] }", answer->str());
|
EXPECT_EQ("{ \"arguments\": [ \"just\", \"some\", \"data\" ], \"result\": 0 }",
|
||||||
|
answer->str());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CCSessionTest, parseAnswer) {
|
TEST_F(CCSessionTest, parseAnswer) {
|
||||||
@@ -67,27 +67,26 @@ TEST_F(CCSessionTest, parseAnswer) {
|
|||||||
ConstElementPtr arg;
|
ConstElementPtr arg;
|
||||||
int rcode;
|
int rcode;
|
||||||
|
|
||||||
EXPECT_THROW(parseAnswer(rcode, ElementPtr()), CCSessionError);
|
EXPECT_THROW(parseAnswer(rcode, ElementPtr()), CtrlChannelError);
|
||||||
EXPECT_THROW(parseAnswer(rcode, el("1")), CCSessionError);
|
EXPECT_THROW(parseAnswer(rcode, el("1")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseAnswer(rcode, el("[]")), CCSessionError);
|
EXPECT_THROW(parseAnswer(rcode, el("[]")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseAnswer(rcode, el("{ }")), CCSessionError);
|
EXPECT_THROW(parseAnswer(rcode, el("{ }")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseAnswer(rcode, el("{ \"something\": 1 }")), CCSessionError);
|
EXPECT_THROW(parseAnswer(rcode, el("{ \"something\": 1 }")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": 0 }")), CCSessionError);
|
EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 0 ] }")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": 1 }")), CCSessionError);
|
EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1 ] }")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1 ] }")), CCSessionError);
|
EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1, 1 ] }")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1, 1 ] }")), CCSessionError);
|
|
||||||
|
|
||||||
answer = el("{ \"result\": [ 0 ] }");
|
answer = el("{ \"result\": 0 }");
|
||||||
arg = parseAnswer(rcode, answer);
|
arg = parseAnswer(rcode, answer);
|
||||||
EXPECT_EQ(0, rcode);
|
EXPECT_EQ(0, rcode);
|
||||||
EXPECT_TRUE(isNull(arg));
|
EXPECT_TRUE(isNull(arg));
|
||||||
|
|
||||||
answer = el("{ \"result\": [ 1, \"error\"] }");
|
answer = el("{ \"result\": 1, \"text\": \"error\" }");
|
||||||
arg = parseAnswer(rcode, answer);
|
arg = parseAnswer(rcode, answer);
|
||||||
EXPECT_EQ(1, rcode);
|
EXPECT_EQ(1, rcode);
|
||||||
EXPECT_EQ("error", arg->stringValue());
|
EXPECT_EQ("error", arg->stringValue());
|
||||||
|
|
||||||
answer = el("{ \"result\": [ 0, [ \"just\", \"some\", \"data\" ] ] }");
|
answer = el("{ \"result\": 0, \"arguments\": [ \"just\", \"some\", \"data\" ] }");
|
||||||
arg = parseAnswer(rcode, answer);
|
arg = parseAnswer(rcode, answer);
|
||||||
EXPECT_EQ(0, rcode);
|
EXPECT_EQ(0, rcode);
|
||||||
EXPECT_EQ("[ \"just\", \"some\", \"data\" ]", arg->str());
|
EXPECT_EQ("[ \"just\", \"some\", \"data\" ]", arg->str());
|
||||||
@@ -98,19 +97,22 @@ TEST_F(CCSessionTest, createCommand) {
|
|||||||
ConstElementPtr arg;
|
ConstElementPtr arg;
|
||||||
|
|
||||||
command = createCommand("my_command");
|
command = createCommand("my_command");
|
||||||
ASSERT_EQ("{ \"command\": [ \"my_command\" ] }", command->str());
|
ASSERT_EQ("{ \"command\": \"my_command\" }", command->str());
|
||||||
|
|
||||||
arg = el("1");
|
arg = el("1");
|
||||||
command = createCommand("my_command", arg);
|
command = createCommand("my_command", arg);
|
||||||
ASSERT_EQ("{ \"command\": [ \"my_command\", 1 ] }", command->str());
|
ASSERT_EQ("{ \"arguments\": 1, \"command\": \"my_command\" }",
|
||||||
|
command->str());
|
||||||
|
|
||||||
arg = el("[ \"a\", \"b\" ]");
|
arg = el("[ \"a\", \"b\" ]");
|
||||||
command = createCommand("my_cmd", arg);
|
command = createCommand("my_cmd", arg);
|
||||||
ASSERT_EQ("{ \"command\": [ \"my_cmd\", [ \"a\", \"b\" ] ] }", command->str());
|
ASSERT_EQ("{ \"arguments\": [ \"a\", \"b\" ], \"command\": \"my_cmd\" }",
|
||||||
|
command->str());
|
||||||
|
|
||||||
arg = el("{ \"a\": \"map\" }");
|
arg = el("{ \"a\": \"map\" }");
|
||||||
command = createCommand("foo", arg);
|
command = createCommand("foo", arg);
|
||||||
ASSERT_EQ("{ \"command\": [ \"foo\", { \"a\": \"map\" } ] }", command->str());
|
ASSERT_EQ("{ \"arguments\": { \"a\": \"map\" }, \"command\": \"foo\" }",
|
||||||
|
command->str());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CCSessionTest, parseCommand) {
|
TEST_F(CCSessionTest, parseCommand) {
|
||||||
@@ -118,24 +120,26 @@ TEST_F(CCSessionTest, parseCommand) {
|
|||||||
std::string cmd;
|
std::string cmd;
|
||||||
|
|
||||||
// should throw
|
// should throw
|
||||||
EXPECT_THROW(parseCommand(arg, ElementPtr()), CCSessionError);
|
EXPECT_THROW(parseCommand(arg, ElementPtr()), CtrlChannelError);
|
||||||
EXPECT_THROW(parseCommand(arg, el("1")), CCSessionError);
|
EXPECT_THROW(parseCommand(arg, el("1")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseCommand(arg, el("{ }")), CCSessionError);
|
EXPECT_THROW(parseCommand(arg, el("{ }")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseCommand(arg, el("{ \"not a command\": 1 }")), CCSessionError);
|
EXPECT_THROW(parseCommand(arg, el("{ \"not a command\": 1 }")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseCommand(arg, el("{ \"command\": 1 }")), CCSessionError);
|
EXPECT_THROW(parseCommand(arg, el("{ \"command\": 1 }")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseCommand(arg, el("{ \"command\": [] }")), CCSessionError);
|
EXPECT_THROW(parseCommand(arg, el("{ \"command\": [] }")), CtrlChannelError);
|
||||||
EXPECT_THROW(parseCommand(arg, el("{ \"command\": [ 1 ] }")), CCSessionError);
|
EXPECT_THROW(parseCommand(arg, el("{ \"command\": [ 1 ] }")), CtrlChannelError);
|
||||||
|
|
||||||
cmd = parseCommand(arg, el("{ \"command\": [ \"my_command\" ] }"));
|
cmd = parseCommand(arg, el("{ \"command\": \"my_command\" }"));
|
||||||
EXPECT_EQ("my_command", cmd);
|
EXPECT_EQ("my_command", cmd);
|
||||||
EXPECT_EQ(*arg, *Element::createMap());
|
EXPECT_FALSE(arg);
|
||||||
|
|
||||||
cmd = parseCommand(arg, el("{ \"command\": [ \"my_command\", 1 ] }"));
|
cmd = parseCommand(arg, el("{ \"command\": \"my_command\", \"arguments\": 1 }"));
|
||||||
|
ASSERT_TRUE(arg);
|
||||||
EXPECT_EQ("my_command", cmd);
|
EXPECT_EQ("my_command", cmd);
|
||||||
EXPECT_EQ("1", arg->str());
|
EXPECT_EQ("1", arg->str());
|
||||||
|
|
||||||
parseCommand(arg, el("{ \"command\": [ \"my_command\", [ \"some\", \"argument\", \"list\" ] ] }"));
|
parseCommand(arg, el("{ \"command\": \"my_command\", \"arguments\": [ \"some\", \"argument\", \"list\" ] }"));
|
||||||
EXPECT_EQ("my_command", cmd);
|
EXPECT_EQ("my_command", cmd);
|
||||||
|
ASSERT_TRUE(arg);
|
||||||
EXPECT_EQ("[ \"some\", \"argument\", \"list\" ]", arg->str());
|
EXPECT_EQ("[ \"some\", \"argument\", \"list\" ]", arg->str());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
// PERFORMANCE OF THIS SOFTWARE.
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
#include <cc/proto_defs.h>
|
#include <config/ccsession.h>
|
||||||
#include <dhcpsrv/testutils/config_result_check.h>
|
#include <dhcpsrv/testutils/config_result_check.h>
|
||||||
#include <boost/algorithm/string/classification.hpp>
|
#include <boost/algorithm/string/classification.hpp>
|
||||||
#include <boost/algorithm/string/constants.hpp>
|
#include <boost/algorithm/string/constants.hpp>
|
||||||
@@ -28,15 +28,16 @@ using namespace isc::data;
|
|||||||
|
|
||||||
bool errorContainsPosition(ConstElementPtr error_element,
|
bool errorContainsPosition(ConstElementPtr error_element,
|
||||||
const std::string& file_name) {
|
const std::string& file_name) {
|
||||||
if (error_element->contains(isc::cc::CC_PAYLOAD_RESULT)) {
|
if (error_element->contains(isc::config::CONTROL_RESULT)) {
|
||||||
ConstElementPtr result = error_element->get(isc::cc::CC_PAYLOAD_RESULT);
|
ConstElementPtr result = error_element->get(isc::config::CONTROL_RESULT);
|
||||||
if ((result->getType() != Element::list) || (result->size() < 2) ||
|
ConstElementPtr text = error_element->get(isc::config::CONTROL_TEXT);
|
||||||
(result->get(1)->getType() != Element::string)) {
|
if (!result || (result->getType() != Element::integer) || !text
|
||||||
|
|| (text->getType() != Element::string)) {
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the error message in the textual format.
|
// Get the error message in the textual format.
|
||||||
std::string error_string = result->get(1)->stringValue();
|
std::string error_string = text->stringValue();
|
||||||
|
|
||||||
// The position of the data element causing an error has the following
|
// The position of the data element causing an error has the following
|
||||||
// format: <filename>:<linenum>:<pos>. The <filename> has been specified
|
// format: <filename>:<linenum>:<pos>. The <filename> has been specified
|
||||||
|
Reference in New Issue
Block a user