diff options
Diffstat (limited to 'src/rpc-server')
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_general.cpp | 59 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 223 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_test.cpp | 81 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmds.h | 77 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_cmd.cpp | 258 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_cmd_api.h | 179 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_cmds_table.cpp | 70 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_cmds_table.h | 79 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_exception_api.h | 42 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp | 202 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_jsonrpc_v2_parser.h | 94 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_req_resp_server.cpp | 146 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_req_resp_server.h | 51 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_server.cpp | 153 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_server_api.h | 165 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_server_mock.cpp | 75 |
16 files changed, 1954 insertions, 0 deletions
diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp new file mode 100644 index 00000000..6b765aca --- /dev/null +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -0,0 +1,59 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include "trex_rpc_cmds.h" +#include <trex_rpc_server_api.h> + +#ifndef TREX_RPC_MOCK_SERVER + #include <../linux_dpdk/version.h> +#endif + +using namespace std; + +/** + * get status + * + */ +trex_rpc_cmd_rc_e +TrexRpcCmdGetStatus::_run(const Json::Value ¶ms, Json::Value &result) { + + Json::Value §ion = result["result"]; + + #ifndef TREX_RPC_MOCK_SERVER + + section["general"]["version"] = VERSION_BUILD_NUM; + section["general"]["build_date"] = get_build_date(); + section["general"]["build_time"] = get_build_time(); + section["general"]["version_user"] = VERSION_USER; + section["general"]["uptime"] = TrexRpcServer::get_server_uptime(); + + #else + + section["general"]["version"] = "v0.0"; + section["general"]["build_date"] = __DATE__; + section["general"]["build_time"] = __TIME__; + section["general"]["version_user"] = "MOCK"; + section["general"]["uptime"] = TrexRpcServer::get_server_uptime(); + + #endif + + return (TREX_RPC_CMD_OK); +} + diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp new file mode 100644 index 00000000..d1dffc44 --- /dev/null +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -0,0 +1,223 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include "trex_rpc_cmds.h" +#include <trex_rpc_server_api.h> +#include <trex_stream_api.h> +#include <trex_stateless_api.h> + +#include <iostream> + +using namespace std; + +/*************************** + * add new stream + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdAddStream::_run(const Json::Value ¶ms, Json::Value &result) { + + const Json::Value §ion = parse_object(params, "stream", result); + + /* get the type of the stream */ + const Json::Value &mode = parse_object(section, "mode", result); + string type = parse_string(mode, "type", result); + + /* allocate a new stream based on the type */ + TrexStream *stream = allocate_new_stream(section, result); + + /* some fields */ + stream->m_enabled = parse_bool(section, "enabled", result); + stream->m_self_start = parse_bool(section, "self_start", result); + + /* inter stream gap */ + stream->m_isg_usec = parse_double(section, "Is", result); + + stream->m_next_stream_id = parse_int(section, "next_stream_id", result); + + const Json::Value &pkt = parse_array(section, "packet", result); + + /* fetch the packet from the message */ + + stream->m_pkt_len = pkt.size(); + stream->m_pkt = new uint8_t[pkt.size()]; + if (!stream->m_pkt) { + generate_internal_err(result, "unable to allocate memory"); + } + + /* parse the packet */ + for (int i = 0; i < pkt.size(); i++) { + stream->m_pkt[i] = parse_byte(pkt, i, result); + } + + /* parse RX info */ + const Json::Value &rx = parse_object(section, "rx_stats", result); + + stream->m_rx_check.m_enable = parse_bool(rx, "enabled", result); + + /* if it is enabled - we need more fields */ + if (stream->m_rx_check.m_enable) { + stream->m_rx_check.m_stream_id = parse_int(rx, "stream_id", result); + stream->m_rx_check.m_seq_enabled = parse_bool(rx, "seq_enabled", result); + stream->m_rx_check.m_latency = parse_bool(rx, "latency", result); + } + + /* make sure this is a valid stream to add */ + validate_stream(stream, result); + + TrexStatelessPort *port = get_trex_stateless()->get_port_by_id(stream->m_port_id); + port->get_stream_table()->add_stream(stream); + + result["result"] = "ACK"; + + return (TREX_RPC_CMD_OK); +} + + + +TrexStream * +TrexRpcCmdAddStream::allocate_new_stream(const Json::Value §ion, Json::Value &result) { + + uint8_t port_id = parse_int(section, "port_id", result); + uint32_t stream_id = parse_int(section, "stream_id", result); + + TrexStream *stream; + + const Json::Value &mode = parse_object(section, "mode", result); + std::string type = parse_string(mode, "type", result); + + if (type == "continuous") { + + uint32_t pps = parse_int(mode, "pps", result); + stream = new TrexStreamContinuous(port_id, stream_id, pps); + + } else if (type == "single_burst") { + + uint32_t total_pkts = parse_int(mode, "total_pkts", result); + uint32_t pps = parse_int(mode, "pps", result); + + stream = new TrexStreamBurst(port_id, stream_id, total_pkts, pps); + + } else if (type == "multi_burst") { + + uint32_t pps = parse_int(mode, "pps", result); + double ibg_usec = parse_double(mode, "ibg", result); + uint32_t num_bursts = parse_int(mode, "number_of_bursts", result); + uint32_t pkts_per_burst = parse_int(mode, "pkts_per_burst", result); + + stream = new TrexStreamMultiBurst(port_id, stream_id, pkts_per_burst, pps, num_bursts, ibg_usec); + + + } else { + generate_parse_err(result, "bad stream type provided: '" + type + "'"); + } + + /* make sure we were able to allocate the memory */ + if (!stream) { + generate_internal_err(result, "unable to allocate memory"); + } + + return (stream); + +} + +void +TrexRpcCmdAddStream::validate_stream(const TrexStream *stream, Json::Value &result) { + + /* check packet size */ + if ( (stream->m_pkt_len < TrexStream::MIN_PKT_SIZE_BYTES) || (stream->m_pkt_len > TrexStream::MAX_PKT_SIZE_BYTES) ) { + std::stringstream ss; + ss << "bad packet size provided: should be between " << TrexStream::MIN_PKT_SIZE_BYTES << " and " << TrexStream::MAX_PKT_SIZE_BYTES; + delete stream; + generate_execute_err(result, ss.str()); + } + + /* port id should be between 0 and count - 1 */ + if (stream->m_port_id >= get_trex_stateless()->get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)get_trex_stateless()->get_port_count() - 1; + delete stream; + generate_execute_err(result, ss.str()); + } + + /* add the stream to the port's stream table */ + TrexStatelessPort * port = get_trex_stateless()->get_port_by_id(stream->m_port_id); + + /* does such a stream exists ? */ + if (port->get_stream_table()->get_stream_by_id(stream->m_stream_id)) { + std::stringstream ss; + ss << "stream " << stream->m_stream_id << " already exists"; + delete stream; + generate_execute_err(result, ss.str()); + } + +} + +/*************************** + * remove stream + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdRemoveStream::_run(const Json::Value ¶ms, Json::Value &result) { + uint8_t port_id = parse_byte(params, "port_id", result); + uint32_t stream_id = parse_int(params, "stream_id", result); + + + if (port_id >= get_trex_stateless()->get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)get_trex_stateless()->get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = get_trex_stateless()->get_port_by_id(port_id); + TrexStream *stream = port->get_stream_table()->get_stream_by_id(stream_id); + + if (!stream) { + std::stringstream ss; + ss << "stream " << stream_id << " does not exists"; + generate_execute_err(result, ss.str()); + } + + port->get_stream_table()->remove_stream(stream); + + result["result"] = "ACK"; +} + +/*************************** + * remove all streams + * for a port + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdRemoveAllStreams::_run(const Json::Value ¶ms, Json::Value &result) { + uint8_t port_id = parse_byte(params, "port_id", result); + + if (port_id >= get_trex_stateless()->get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)get_trex_stateless()->get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = get_trex_stateless()->get_port_by_id(port_id); + port->get_stream_table()->remove_and_delete_all_streams(); + + result["result"] = "ACK"; +} + diff --git a/src/rpc-server/commands/trex_rpc_cmd_test.cpp b/src/rpc-server/commands/trex_rpc_cmd_test.cpp new file mode 100644 index 00000000..3153317e --- /dev/null +++ b/src/rpc-server/commands/trex_rpc_cmd_test.cpp @@ -0,0 +1,81 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include "trex_rpc_cmds.h" +#include <iostream> +#include <sstream> +#include <trex_rpc_cmds_table.h> + +using namespace std; + +/** + * add command + * + */ +trex_rpc_cmd_rc_e +TrexRpcCmdTestAdd::_run(const Json::Value ¶ms, Json::Value &result) { + + result["result"] = parse_int(params, "x", result) + parse_int(params, "y", result); + + return (TREX_RPC_CMD_OK); +} + +/** + * sub command + * + * @author imarom (16-Aug-15) + */ +trex_rpc_cmd_rc_e +TrexRpcCmdTestSub::_run(const Json::Value ¶ms, Json::Value &result) { + + result["result"] = parse_int(params, "x", result) - parse_int(params, "y", result); + + return (TREX_RPC_CMD_OK); +} + +/** + * ping command + */ +trex_rpc_cmd_rc_e +TrexRpcCmdPing::_run(const Json::Value ¶ms, Json::Value &result) { + + result["result"] = "ACK"; + return (TREX_RPC_CMD_OK); +} + +/** + * query command + */ +trex_rpc_cmd_rc_e +TrexRpcCmdGetReg::_run(const Json::Value ¶ms, Json::Value &result) { + vector<string> cmds; + + TrexRpcCommandsTable::get_instance().query(cmds); + + Json::Value test = Json::arrayValue; + for (auto cmd : cmds) { + test.append(cmd); + } + + result["result"] = test; + + return (TREX_RPC_CMD_OK); +} + diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h new file mode 100644 index 00000000..64551fac --- /dev/null +++ b/src/rpc-server/commands/trex_rpc_cmds.h @@ -0,0 +1,77 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __TREX_RPC_CMD_H__ +#define __TREX_RPC_CMD_H__ + +#include <trex_rpc_cmd_api.h> +#include <json/json.h> + +class TrexStream; + +/* all the RPC commands decl. goes here */ + +/******************* test section ************/ + +/** + * syntactic sugar for creating a simple command + */ + +#define TREX_RPC_CMD_DEFINE_EXTENED(class_name, cmd_name, param_count, ext) \ + class class_name : public TrexRpcCommand { \ + public: \ + class_name () : TrexRpcCommand(cmd_name, param_count) {} \ + protected: \ + virtual trex_rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); \ + ext \ + } + +#define TREX_RPC_CMD_DEFINE(class_name, cmd_name, param_count) TREX_RPC_CMD_DEFINE_EXTENED(class_name, cmd_name, param_count, ;) + +/** + * test cmds + */ +TREX_RPC_CMD_DEFINE(TrexRpcCmdTestAdd, "test_add", 2); +TREX_RPC_CMD_DEFINE(TrexRpcCmdTestSub, "test_sub", 2); + +/** + * general cmds + */ +TREX_RPC_CMD_DEFINE(TrexRpcCmdPing, "ping", 0); +TREX_RPC_CMD_DEFINE(TrexRpcCmdGetReg, "get_reg_cmds", 0); +TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStatus, "get_status", 0); + +/** + * stream cmds + */ +TREX_RPC_CMD_DEFINE(TrexRpcCmdRemoveAllStreams, "remove_all_streams", 1); +TREX_RPC_CMD_DEFINE(TrexRpcCmdRemoveStream, "remove_stream", 2); + +TREX_RPC_CMD_DEFINE_EXTENED(TrexRpcCmdAddStream, "add_stream", 1, + +/* extended part */ +TrexStream * allocate_new_stream(const Json::Value §ion, Json::Value &result); +void validate_stream(const TrexStream *stream, Json::Value &result); + +); + + +#endif /* __TREX_RPC_CMD_H__ */ diff --git a/src/rpc-server/trex_rpc_cmd.cpp b/src/rpc-server/trex_rpc_cmd.cpp new file mode 100644 index 00000000..6988cba7 --- /dev/null +++ b/src/rpc-server/trex_rpc_cmd.cpp @@ -0,0 +1,258 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include <trex_rpc_cmd_api.h> + +trex_rpc_cmd_rc_e +TrexRpcCommand::run(const Json::Value ¶ms, Json::Value &result) { + trex_rpc_cmd_rc_e rc; + + /* the internal run can throw a parser error / other error */ + try { + check_param_count(params, m_param_count, result); + rc = _run(params, result); + } catch (TrexRpcCommandException &e) { + return e.get_rc(); + } + + return (rc); +} + +void +TrexRpcCommand::check_param_count(const Json::Value ¶ms, int expected, Json::Value &result) { + + if (params.size() != expected) { + std::stringstream ss; + ss << "method expects '" << expected << "' paramteres, '" << params.size() << "' provided"; + generate_parse_err(result, ss.str()); + } +} + +const char * +TrexRpcCommand::type_to_str(field_type_e type) { + switch (type) { + case FIELD_TYPE_BYTE: + return "byte"; + case FIELD_TYPE_BOOL: + return "bool"; + case FIELD_TYPE_INT: + return "int"; + case FIELD_TYPE_DOUBLE: + return "double"; + case FIELD_TYPE_OBJ: + return "object"; + case FIELD_TYPE_STR: + return "string"; + case FIELD_TYPE_ARRAY: + return "array"; + + default: + return "UNKNOWN"; + } +} + +const char * +TrexRpcCommand::json_type_to_name(const Json::Value &value) { + + switch(value.type()) { + case Json::nullValue: + return "null"; + case Json::intValue: + return "int"; + case Json::uintValue: + return "uint"; + case Json::realValue: + return "real"; + case Json::stringValue: + return "string"; + case Json::booleanValue: + return "boolean"; + case Json::arrayValue: + return "array"; + case Json::objectValue: + return "object"; + + default: + return "UNKNOWN"; + } + +} + +uint8_t +TrexRpcCommand::parse_byte(const Json::Value &parent, const std::string &name, Json::Value &result) { + check_field_type(parent, name, FIELD_TYPE_BYTE, result); + return parent[name].asUInt(); +} + +uint8_t +TrexRpcCommand::parse_byte(const Json::Value &parent, int index, Json::Value &result) { + check_field_type(parent, index, FIELD_TYPE_BYTE, result); + return parent[index].asUInt(); +} + +int +TrexRpcCommand::parse_int(const Json::Value &parent, const std::string &name, Json::Value &result) { + check_field_type(parent, name, FIELD_TYPE_INT, result); + return parent[name].asInt(); +} + +bool +TrexRpcCommand::parse_bool(const Json::Value &parent, const std::string &name, Json::Value &result) { + check_field_type(parent, name, FIELD_TYPE_BOOL, result); + return parent[name].asBool(); +} + +double +TrexRpcCommand::parse_double(const Json::Value &parent, const std::string &name, Json::Value &result) { + check_field_type(parent, name, FIELD_TYPE_DOUBLE, result); + return parent[name].asDouble(); +} + +const std::string +TrexRpcCommand::parse_string(const Json::Value &parent, const std::string &name, Json::Value &result) { + check_field_type(parent, name, FIELD_TYPE_STR, result); + return parent[name].asString(); +} + +const Json::Value & +TrexRpcCommand::parse_object(const Json::Value &parent, const std::string &name, Json::Value &result) { + check_field_type(parent, name, FIELD_TYPE_OBJ, result); + return parent[name]; +} + +const Json::Value & +TrexRpcCommand::parse_array(const Json::Value &parent, const std::string &name, Json::Value &result) { + check_field_type(parent, name, FIELD_TYPE_ARRAY, result); + return parent[name]; +} + +/** + * for index element (array) + */ +void +TrexRpcCommand::check_field_type(const Json::Value &parent, int index, field_type_e type, Json::Value &result) { + + /* should never get here without parent being array */ + if (!parent.isArray()) { + throw TrexRpcException("internal parsing error"); + } + + const Json::Value &field = parent[index]; + + std::stringstream ss; + ss << "array element: " << (index + 1) << " "; + check_field_type_common(field, ss.str(), type, result); +} + +void +TrexRpcCommand::check_field_type(const Json::Value &parent, const std::string &name, field_type_e type, Json::Value &result) { + /* should never get here without parent being object */ + if (!parent.isObject()) { + throw TrexRpcException("internal parsing error"); + } + + const Json::Value &field = parent[name]; + check_field_type_common(field, name, type, result); +} +void +TrexRpcCommand::check_field_type_common(const Json::Value &field, const std::string &name, field_type_e type, Json::Value &result) { + std::stringstream ss; + + /* first check if field exists */ + if (field == Json::Value::null) { + ss << "field '" << name << "' is missing"; + generate_parse_err(result, ss.str()); + } + + bool rc = true; + + switch (type) { + case FIELD_TYPE_BYTE: + if ( (!field.isUInt()) || (field.asInt() > 0xFF)) { + rc = false; + } + break; + + case FIELD_TYPE_BOOL: + if (!field.isBool()) { + rc = false; + } + break; + + case FIELD_TYPE_INT: + if (!field.isInt()) { + rc = false; + } + break; + + case FIELD_TYPE_DOUBLE: + if (!field.isDouble()) { + rc = false; + } + break; + + case FIELD_TYPE_OBJ: + if (!field.isObject()) { + rc = false; + } + break; + + case FIELD_TYPE_STR: + if (!field.isString()) { + rc = false; + } + break; + + case FIELD_TYPE_ARRAY: + if (!field.isArray()) { + rc = false; + } + break; + + default: + throw TrexRpcException("unhandled type"); + break; + + } + if (!rc) { + ss << "error at offset: " << field.getOffsetStart() << " - '" << name << "' is '" << json_type_to_name(field) << "', expecting '" << type_to_str(type) << "'"; + generate_parse_err(result, ss.str()); + } + +} + +void +TrexRpcCommand::generate_parse_err(Json::Value &result, const std::string &msg) { + result["specific_err"] = msg; + throw (TrexRpcCommandException(TREX_RPC_CMD_PARSE_ERR)); +} + +void +TrexRpcCommand::generate_internal_err(Json::Value &result, const std::string &msg) { + result["specific_err"] = msg; + throw (TrexRpcCommandException(TREX_RPC_CMD_INTERNAL_ERR)); +} + +void +TrexRpcCommand::generate_execute_err(Json::Value &result, const std::string &msg) { + result["specific_err"] = msg; + throw (TrexRpcCommandException(TREX_RPC_CMD_EXECUTE_ERR)); +} + diff --git a/src/rpc-server/trex_rpc_cmd_api.h b/src/rpc-server/trex_rpc_cmd_api.h new file mode 100644 index 00000000..da895809 --- /dev/null +++ b/src/rpc-server/trex_rpc_cmd_api.h @@ -0,0 +1,179 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __TREX_RPC_CMD_API_H__ +#define __TREX_RPC_CMD_API_H__ + +#include <string> +#include <vector> +#include <json/json.h> +#include <trex_rpc_exception_api.h> + +/** + * describe different types of rc for run() + */ +typedef enum trex_rpc_cmd_rc_ { + TREX_RPC_CMD_OK, + TREX_RPC_CMD_PARSE_ERR, + TREX_RPC_CMD_EXECUTE_ERR, + TREX_RPC_CMD_INTERNAL_ERR +} trex_rpc_cmd_rc_e; + +/** + * simple exception for RPC command processing + * + * @author imarom (23-Aug-15) + */ +class TrexRpcCommandException : TrexRpcException { +public: + TrexRpcCommandException(trex_rpc_cmd_rc_e rc) : m_rc(rc) { + + } + + trex_rpc_cmd_rc_e get_rc() { + return m_rc; + + } + +protected: + trex_rpc_cmd_rc_e m_rc; +}; + +/** + * interface for RPC command + * + * @author imarom (13-Aug-15) + */ +class TrexRpcCommand { +public: + + /** + * method name and params + */ + TrexRpcCommand(const std::string &method_name, int param_count) : m_name(method_name), m_param_count(param_count) { + + } + + /** + * entry point for executing RPC command + * + */ + trex_rpc_cmd_rc_e run(const Json::Value ¶ms, Json::Value &result); + + const std::string &get_name() { + return m_name; + } + + virtual ~TrexRpcCommand() {} + +protected: + + /** + * different types of fields + */ + enum field_type_e { + FIELD_TYPE_BYTE, + FIELD_TYPE_INT, + FIELD_TYPE_DOUBLE, + FIELD_TYPE_BOOL, + FIELD_TYPE_STR, + FIELD_TYPE_OBJ, + FIELD_TYPE_ARRAY + }; + + /** + * implemented by the dervied class + * + */ + virtual trex_rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result) = 0; + + /** + * check param count + */ + void check_param_count(const Json::Value ¶ms, int expected, Json::Value &result); + + /** + * parse functions + * + */ + uint8_t parse_byte(const Json::Value &parent, const std::string &name, Json::Value &result); + int parse_int(const Json::Value &parent, const std::string &name, Json::Value &result); + double parse_double(const Json::Value &parent, const std::string &name, Json::Value &result); + bool parse_bool(const Json::Value &parent, const std::string &name, Json::Value &result); + const std::string parse_string(const Json::Value &parent, const std::string &name, Json::Value &result); + const Json::Value & parse_object(const Json::Value &parent, const std::string &name, Json::Value &result); + const Json::Value & parse_array(const Json::Value &parent, const std::string &name, Json::Value &result); + + uint8_t parse_byte(const Json::Value &parent, int index, Json::Value &result); + int parse_int(const Json::Value &parent, int index, Json::Value &result); + double parse_double(const Json::Value &parent, int index, Json::Value &result); + bool parse_bool(const Json::Value &parent, int index, Json::Value &result); + const std::string parse_string(const Json::Value &parent, int index, Json::Value &result); + const Json::Value & parse_object(const Json::Value &parent, int index, Json::Value &result); + const Json::Value & parse_array(const Json::Value &parent, int index, Json::Value &result); + + /** + * check field type + * + */ + void check_field_type(const Json::Value &parent, const std::string &name, field_type_e type, Json::Value &result); + void check_field_type(const Json::Value &parent, int index, field_type_e type, Json::Value &result); + void check_field_type_common(const Json::Value &field, const std::string &name, field_type_e type, Json::Value &result); + + /** + * error generating functions + * + */ + void generate_parse_err(Json::Value &result, const std::string &msg); + + + /** + * method execute error + * + */ + void generate_execute_err(Json::Value &result, const std::string &msg); + + /** + * internal error + * + */ + void generate_internal_err(Json::Value &result, const std::string &msg); + + + /** + * translate enum to string + * + */ + const char * type_to_str(field_type_e type); + + /** + * translate JSON values to string + * + */ + const char * json_type_to_name(const Json::Value &value); + + /* RPC command name */ + std::string m_name; + int m_param_count; +}; + +#endif /* __TREX_RPC_CMD_API_H__ */ + diff --git a/src/rpc-server/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp new file mode 100644 index 00000000..7d5d49ae --- /dev/null +++ b/src/rpc-server/trex_rpc_cmds_table.cpp @@ -0,0 +1,70 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include <trex_rpc_cmds_table.h> +#include <iostream> + +#include "commands/trex_rpc_cmds.h" + +using namespace std; + +/************* table related methods ***********/ +TrexRpcCommandsTable::TrexRpcCommandsTable() { + /* add the test command (for gtest) */ + register_command(new TrexRpcCmdTestAdd()); + register_command(new TrexRpcCmdTestSub()); + register_command(new TrexRpcCmdPing()); + register_command(new TrexRpcCmdGetReg()); + register_command(new TrexRpcCmdGetStatus()); + + /* stream commands */ + register_command(new TrexRpcCmdAddStream()); + register_command(new TrexRpcCmdRemoveStream()); + register_command(new TrexRpcCmdRemoveAllStreams()); +} + +TrexRpcCommandsTable::~TrexRpcCommandsTable() { + for (auto cmd : m_rpc_cmd_table) { + delete cmd.second; + } +} + +TrexRpcCommand * TrexRpcCommandsTable::lookup(const string &method_name) { + auto search = m_rpc_cmd_table.find(method_name); + + if (search != m_rpc_cmd_table.end()) { + return search->second; + } else { + return NULL; + } +} + + +void TrexRpcCommandsTable::register_command(TrexRpcCommand *command) { + + m_rpc_cmd_table[command->get_name()] = command; +} + +void TrexRpcCommandsTable::query(vector<string> &cmds) { + for (auto cmd : m_rpc_cmd_table) { + cmds.push_back(cmd.first); + } +} + diff --git a/src/rpc-server/trex_rpc_cmds_table.h b/src/rpc-server/trex_rpc_cmds_table.h new file mode 100644 index 00000000..a41944f1 --- /dev/null +++ b/src/rpc-server/trex_rpc_cmds_table.h @@ -0,0 +1,79 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __TREX_RPC_CMDS_TABLE_H__ +#define __TREX_RPC_CMDS_TABLE_H__ + +#include <unordered_map> +#include <string> +#include <vector> +#include <json/json.h> + +class TrexRpcCommand; + +/** + * holds all the commands registered + * + * @author imarom (13-Aug-15) + */ +class TrexRpcCommandsTable { + +public: + + static TrexRpcCommandsTable& get_instance() { + static TrexRpcCommandsTable instance; + return instance; + } + + /** + * register a new command + * + */ + void register_command(TrexRpcCommand *command); + + /** + * lookup for a command + * + */ + TrexRpcCommand * lookup(const std::string &method_name); + + /** + * query all commands registered + * + */ + void query(std::vector<std::string> &cmds); + +private: + TrexRpcCommandsTable(); + ~TrexRpcCommandsTable(); + + /* c++ 2011 style singleton */ + TrexRpcCommandsTable(TrexRpcCommandsTable const&) = delete; + void operator=(TrexRpcCommandsTable const&) = delete; + + /** + * holds all the registered RPC commands + * + */ + std::unordered_map<std::string, TrexRpcCommand *> m_rpc_cmd_table; +}; + +#endif /* __TREX_RPC_CMDS_TABLE_H__ */ diff --git a/src/rpc-server/trex_rpc_exception_api.h b/src/rpc-server/trex_rpc_exception_api.h new file mode 100644 index 00000000..e349b980 --- /dev/null +++ b/src/rpc-server/trex_rpc_exception_api.h @@ -0,0 +1,42 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __TREX_RPC_EXCEPTION_API_H__ +#define __TREX_RPC_EXCEPTION_API_H__ + +#include <string> +#include <stdexcept> + +/** + * generic exception for RPC errors + * + */ +class TrexRpcException : public std::runtime_error +{ +public: + TrexRpcException() : std::runtime_error("") { + + } + TrexRpcException(const std::string &what) : std::runtime_error(what) { + } +}; + +#endif /* __TREX_RPC_EXCEPTION_API_H__ */ diff --git a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp new file mode 100644 index 00000000..3831bb37 --- /dev/null +++ b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp @@ -0,0 +1,202 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include <trex_rpc_exception_api.h> +#include <trex_rpc_jsonrpc_v2_parser.h> +#include <trex_rpc_cmd_api.h> +#include <trex_rpc_cmds_table.h> + +#include <json/json.h> + +#include <iostream> + +/** + * error as described in the RFC + * http://www.jsonrpc.org/specification + */ +enum { + JSONRPC_V2_ERR_PARSE = -32700, + JSONRPC_V2_ERR_INVALID_REQ = -32600, + JSONRPC_V2_ERR_METHOD_NOT_FOUND = -32601, + JSONRPC_V2_ERR_INVALID_PARAMS = -32602, + JSONRPC_V2_ERR_INTERNAL_ERROR = -32603, + + /* specific server errors */ + JSONRPC_V2_ERR_EXECUTE_ERROR = -32000, +}; + + +/*************** JSON RPC parsed object base type ************/ + +TrexJsonRpcV2ParsedObject::TrexJsonRpcV2ParsedObject(const Json::Value &msg_id, bool force = false) : m_msg_id(msg_id) { + /* if we have msg_id or a force was issued - write resposne */ + m_respond = (msg_id != Json::Value::null) || force; +} + +void TrexJsonRpcV2ParsedObject::execute(Json::Value &response) { + + /* common fields */ + if (m_respond) { + response["jsonrpc"] = "2.0"; + response["id"] = m_msg_id; + _execute(response); + } else { + Json::Value dummy; + _execute(dummy); + } +} + +/****************** valid method return value **************/ +class JsonRpcMethod : public TrexJsonRpcV2ParsedObject { +public: + JsonRpcMethod(const Json::Value &msg_id, TrexRpcCommand *cmd, const Json::Value ¶ms) : TrexJsonRpcV2ParsedObject(msg_id), m_cmd(cmd), m_params(params) { + + } + + virtual void _execute(Json::Value &response) { + Json::Value result; + + trex_rpc_cmd_rc_e rc = m_cmd->run(m_params, result); + + switch (rc) { + case TREX_RPC_CMD_OK: + response["result"] = result["result"]; + break; + + case TREX_RPC_CMD_PARSE_ERR: + response["error"]["code"] = JSONRPC_V2_ERR_INVALID_PARAMS; + response["error"]["message"] = "Bad paramters for method"; + response["error"]["specific_err"] = result["specific_err"]; + break; + + case TREX_RPC_CMD_EXECUTE_ERR: + response["error"]["code"] = JSONRPC_V2_ERR_EXECUTE_ERROR; + response["error"]["message"] = "Failed To Execute Method"; + response["error"]["specific_err"] = result["specific_err"]; + break; + + case TREX_RPC_CMD_INTERNAL_ERR: + response["error"]["code"] = JSONRPC_V2_ERR_INTERNAL_ERROR; + response["error"]["message"] = "Internal Server Error"; + response["error"]["specific_err"] = result["specific_err"]; + break; + } + + } + +private: + TrexRpcCommand *m_cmd; + Json::Value m_params; +}; + +/******************* RPC error **************/ + +/** + * describes the parser error + * + */ +class JsonRpcError : public TrexJsonRpcV2ParsedObject { +public: + + JsonRpcError(const Json::Value &msg_id, int code, const std::string &msg, bool force = false) : TrexJsonRpcV2ParsedObject(msg_id, force), m_code(code), m_msg(msg) { + + } + + virtual void _execute(Json::Value &response) { + response["error"]["code"] = m_code; + response["error"]["message"] = m_msg; + } + +private: + int m_code; + std::string m_msg; +}; + + +/************** JSON RPC V2 parser implementation *************/ + +TrexJsonRpcV2Parser::TrexJsonRpcV2Parser(const std::string &msg) : m_msg(msg) { + +} + +/** + * parse a batch of commands + * + * @author imarom (17-Aug-15) + * + * @param commands + */ +void TrexJsonRpcV2Parser::parse(std::vector<TrexJsonRpcV2ParsedObject *> &commands) { + + Json::Reader reader; + Json::Value request; + + /* basic JSON parsing */ + bool rc = reader.parse(m_msg, request, false); + if (!rc) { + commands.push_back(new JsonRpcError(Json::Value::null, JSONRPC_V2_ERR_PARSE, "Bad JSON Format", true)); + return; + } + + /* request can be an array of requests */ + if (request.isArray()) { + /* handle each command */ + for (auto single_request : request) { + parse_single_request(single_request, commands); + } + } else { + /* handle single command */ + parse_single_request(request, commands); + } + + +} + + +void TrexJsonRpcV2Parser::parse_single_request(Json::Value &request, + std::vector<TrexJsonRpcV2ParsedObject *> &commands) { + + Json::Value msg_id = request["id"]; + + /* check version */ + if (request["jsonrpc"] != "2.0") { + commands.push_back(new JsonRpcError(msg_id, JSONRPC_V2_ERR_INVALID_REQ, "Invalid JSONRPC Version")); + return; + } + + /* check method name */ + std::string method_name = request["method"].asString(); + if (method_name == "") { + commands.push_back(new JsonRpcError(msg_id, JSONRPC_V2_ERR_INVALID_REQ, "Missing Method Name")); + return; + } + + /* lookup the method in the DB */ + TrexRpcCommand * rpc_cmd = TrexRpcCommandsTable::get_instance().lookup(method_name); + if (!rpc_cmd) { + commands.push_back(new JsonRpcError(msg_id, JSONRPC_V2_ERR_METHOD_NOT_FOUND, "Method not registered")); + return; + } + + /* create a method object */ + commands.push_back(new JsonRpcMethod(msg_id, rpc_cmd, request["params"])); +} + diff --git a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h new file mode 100644 index 00000000..3367ad6a --- /dev/null +++ b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h @@ -0,0 +1,94 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __TREX_RPC_JSONRPC_V2_PARSER_H__ +#define __TREX_RPC_JSONRPC_V2_PARSER_H__ + +#include <string> +#include <vector> +#include <json/json.h> + +/** + * JSON RPC V2 parsed object + * + * @author imarom (12-Aug-15) + */ +class TrexJsonRpcV2ParsedObject { +public: + + TrexJsonRpcV2ParsedObject(const Json::Value &msg_id, bool force); + virtual ~TrexJsonRpcV2ParsedObject() {} + + /** + * main function to execute the command + * + */ + void execute(Json::Value &response); + +protected: + + /** + * instance private implementation + */ + virtual void _execute(Json::Value &response) = 0; + + Json::Value m_msg_id; + bool m_respond; +}; + +/** + * JSON RPC V2 parser + * + * @author imarom (12-Aug-15) + */ +class TrexJsonRpcV2Parser { + +public: + + /** + * creates a JSON-RPC object from a string + * + * @author imarom (12-Aug-15) + * + * @param msg + */ + TrexJsonRpcV2Parser(const std::string &msg); + + /** + * parses the string to a executable commands vector + * + * @author imarom (12-Aug-15) + */ + void parse(std::vector<TrexJsonRpcV2ParsedObject *> &commands); + +private: + + /** + * handle a single request + * + */ + void parse_single_request(Json::Value &request, std::vector<TrexJsonRpcV2ParsedObject *> &commands); + + std::string m_msg; +}; + +#endif /* __TREX_RPC_JSONRPC_V2_PARSER_H__ */ + diff --git a/src/rpc-server/trex_rpc_req_resp_server.cpp b/src/rpc-server/trex_rpc_req_resp_server.cpp new file mode 100644 index 00000000..7484758d --- /dev/null +++ b/src/rpc-server/trex_rpc_req_resp_server.cpp @@ -0,0 +1,146 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include <trex_rpc_server_api.h> +#include <trex_rpc_req_resp_server.h> +#include <trex_rpc_jsonrpc_v2_parser.h> + +#include <unistd.h> +#include <sstream> +#include <iostream> + +#include <zmq.h> +#include <json/json.h> + +/** + * ZMQ based request-response server + * + */ +TrexRpcServerReqRes::TrexRpcServerReqRes(const TrexRpcServerConfig &cfg) : TrexRpcServerInterface(cfg, "req resp") { + /* ZMQ is not thread safe - this should be outside */ + m_context = zmq_ctx_new(); +} + +/** + * main entry point for the server + * this function will be created on a different thread + * + * @author imarom (17-Aug-15) + */ +void TrexRpcServerReqRes::_rpc_thread_cb() { + std::stringstream ss; + + /* create a socket based on the configuration */ + + m_socket = zmq_socket (m_context, ZMQ_REP); + + switch (m_cfg.get_protocol()) { + case TrexRpcServerConfig::RPC_PROT_TCP: + ss << "tcp://*:"; + break; + default: + throw TrexRpcException("unknown protocol for RPC"); + } + + ss << m_cfg.get_port(); + + /* bind the scoket */ + int rc = zmq_bind (m_socket, ss.str().c_str()); + if (rc != 0) { + throw TrexRpcException("Unable to start ZMQ server at: " + ss.str()); + } + + /* server main loop */ + while (m_is_running) { + int msg_size = zmq_recv (m_socket, m_msg_buffer, sizeof(m_msg_buffer), 0); + + /* msg_size of -1 is an error - decode it */ + if (msg_size == -1) { + /* normal shutdown and zmq_term was called */ + if (errno == ETERM) { + break; + } else { + throw TrexRpcException("Unhandled error of zmq_recv"); + } + } + + /* transform it to a string */ + std::string request((const char *)m_msg_buffer, msg_size); + + verbose_msg("Server Received: " + request); + + handle_request(request); + } + + /* must be done from the same thread */ + zmq_close(m_socket); +} + +/** + * stops the ZMQ based RPC server + * + */ +void TrexRpcServerReqRes::_stop_rpc_thread() { + /* by calling zmq_term we signal the blocked thread to exit */ + zmq_term(m_context); + +} + +/** + * handles a request given to the server + * respondes to the request + */ +void TrexRpcServerReqRes::handle_request(const std::string &request) { + std::vector<TrexJsonRpcV2ParsedObject *> commands; + Json::FastWriter writer; + Json::Value response; + + /* first parse the request using JSON RPC V2 parser */ + TrexJsonRpcV2Parser rpc_request(request); + rpc_request.parse(commands); + + int index = 0; + + /* for every command parsed - launch it */ + for (auto command : commands) { + Json::Value single_response; + + command->execute(single_response); + delete command; + + response[index++] = single_response; + + } + + /* write the JSON to string and sever on ZMQ */ + std::string response_str; + + if (response.size() == 1) { + response_str = writer.write(response[0]); + } else { + response_str = writer.write(response); + } + + verbose_msg("Server Replied: " + response_str); + + zmq_send(m_socket, response_str.c_str(), response_str.size(), 0); + +} diff --git a/src/rpc-server/trex_rpc_req_resp_server.h b/src/rpc-server/trex_rpc_req_resp_server.h new file mode 100644 index 00000000..f12d0540 --- /dev/null +++ b/src/rpc-server/trex_rpc_req_resp_server.h @@ -0,0 +1,51 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __TREX_RPC_REQ_RESP_API_H__ +#define __TREX_RPC_REQ_RESP_API_H__ + +#include <trex_rpc_server_api.h> + +/** + * request-response RPC server + * + * @author imarom (11-Aug-15) + */ +class TrexRpcServerReqRes : public TrexRpcServerInterface { +public: + + TrexRpcServerReqRes(const TrexRpcServerConfig &cfg); + +protected: + void _rpc_thread_cb(); + void _stop_rpc_thread(); + +private: + void handle_request(const std::string &request); + + static const int RPC_MAX_MSG_SIZE = 2048; + void *m_context; + void *m_socket; + uint8_t m_msg_buffer[RPC_MAX_MSG_SIZE]; +}; + + +#endif /* __TREX_RPC_REQ_RESP_API_H__ */ diff --git a/src/rpc-server/trex_rpc_server.cpp b/src/rpc-server/trex_rpc_server.cpp new file mode 100644 index 00000000..366bfc5b --- /dev/null +++ b/src/rpc-server/trex_rpc_server.cpp @@ -0,0 +1,153 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include <trex_rpc_server_api.h> +#include <trex_rpc_req_resp_server.h> +#include <unistd.h> +#include <zmq.h> +#include <sstream> +#include <iostream> + +/************** RPC server interface ***************/ + +TrexRpcServerInterface::TrexRpcServerInterface(const TrexRpcServerConfig &cfg, const std::string &name) : m_cfg(cfg), m_name(name) { + m_is_running = false; + m_is_verbose = false; +} + +TrexRpcServerInterface::~TrexRpcServerInterface() { + if (m_is_running) { + stop(); + } +} + +void TrexRpcServerInterface::verbose_msg(const std::string &msg) { + if (!m_is_verbose) { + return; + } + + std::cout << "[verbose][" << m_name << "] " << msg << "\n"; +} + +/** + * starts a RPC specific server + * + * @author imarom (17-Aug-15) + */ +void TrexRpcServerInterface::start() { + m_is_running = true; + + verbose_msg("Starting RPC Server"); + + m_thread = new std::thread(&TrexRpcServerInterface::_rpc_thread_cb, this); + if (!m_thread) { + throw TrexRpcException("unable to create RPC thread"); + } +} + +void TrexRpcServerInterface::stop() { + m_is_running = false; + + verbose_msg("Attempting To Stop RPC Server"); + + /* call the dynamic type class stop */ + _stop_rpc_thread(); + + /* hold until thread has joined */ + m_thread->join(); + + verbose_msg("Server Stopped"); + + delete m_thread; +} + +void TrexRpcServerInterface::set_verbose(bool verbose) { + m_is_verbose = verbose; +} + +bool TrexRpcServerInterface::is_verbose() { + return m_is_verbose; +} + +bool TrexRpcServerInterface::is_running() { + return m_is_running; +} + + +/************** RPC server *************/ + +static const std::string +get_current_date_time() { + time_t now = time(0); + struct tm tstruct; + char buf[80]; + tstruct = *localtime(&now); + strftime(buf, sizeof(buf), "%b %d %Y @ %X", &tstruct); + + return buf; +} + +const std::string TrexRpcServer::s_server_uptime = get_current_date_time(); + +TrexRpcServer::TrexRpcServer(const TrexRpcServerConfig &req_resp_cfg) { + + /* add the request response server */ + m_servers.push_back(new TrexRpcServerReqRes(req_resp_cfg)); +} + +TrexRpcServer::~TrexRpcServer() { + + /* make sure they are all stopped */ + stop(); + + for (auto server : m_servers) { + delete server; + } +} + +/** + * start the server array + * + */ +void TrexRpcServer::start() { + for (auto server : m_servers) { + server->start(); + } +} + +/** + * stop the server array + * + */ +void TrexRpcServer::stop() { + for (auto server : m_servers) { + if (server->is_running()) { + server->stop(); + } + } +} + +void TrexRpcServer::set_verbose(bool verbose) { + for (auto server : m_servers) { + server->set_verbose(verbose); + } +} + diff --git a/src/rpc-server/trex_rpc_server_api.h b/src/rpc-server/trex_rpc_server_api.h new file mode 100644 index 00000000..6bb81c73 --- /dev/null +++ b/src/rpc-server/trex_rpc_server_api.h @@ -0,0 +1,165 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __TREX_RPC_SERVER_API_H__ +#define __TREX_RPC_SERVER_API_H__ + +#include <stdint.h> +#include <vector> +#include <thread> +#include <string> +#include <stdexcept> +#include <trex_rpc_exception_api.h> + +class TrexRpcServerInterface; + +/** + * defines a configuration of generic RPC server + * + * @author imarom (17-Aug-15) + */ +class TrexRpcServerConfig { +public: + + enum rpc_prot_e { + RPC_PROT_TCP + }; + + TrexRpcServerConfig(rpc_prot_e protocol, uint16_t port) : m_protocol(protocol), m_port(port) { + + } + + uint16_t get_port() { + return m_port; + } + + rpc_prot_e get_protocol() { + return m_protocol; + } + +private: + rpc_prot_e m_protocol; + uint16_t m_port; +}; + +/** + * generic type RPC server instance + * + * @author imarom (12-Aug-15) + */ +class TrexRpcServerInterface { +public: + + TrexRpcServerInterface(const TrexRpcServerConfig &cfg, const std::string &name); + virtual ~TrexRpcServerInterface(); + + /** + * starts the server + * + */ + void start(); + + /** + * stops the server + * + */ + void stop(); + + /** + * set verbose on or off + * + */ + void set_verbose(bool verbose); + + /** + * return TRUE if server is active + * + */ + bool is_running(); + + /** + * is the server verbose or not + * + */ + bool is_verbose(); + +protected: + /** + * instances implement this + * + */ + virtual void _rpc_thread_cb() = 0; + virtual void _stop_rpc_thread() = 0; + + /** + * prints a verbosed message (if enabled) + * + */ + void verbose_msg(const std::string &msg); + + TrexRpcServerConfig m_cfg; + bool m_is_running; + bool m_is_verbose; + std::thread *m_thread; + std::string m_name; +}; + +/** + * TREX RPC server + * may contain serveral types of RPC servers + * (request response, async and etc.) + * + * @author imarom (12-Aug-15) + */ +class TrexRpcServer { +public: + + /* currently only request response server config is required */ + TrexRpcServer(const TrexRpcServerConfig &req_resp_cfg); + ~TrexRpcServer(); + + /** + * starts the RPC server + * + * @author imarom (19-Aug-15) + */ + void start(); + + /** + * stops the RPC server + * + * @author imarom (19-Aug-15) + */ + void stop(); + + void set_verbose(bool verbose); + + static const std::string &get_server_uptime() { + return s_server_uptime; + } + +private: + std::vector<TrexRpcServerInterface *> m_servers; + bool m_verbose; + static const std::string s_server_uptime; +}; + +#endif /* __TREX_RPC_SERVER_API_H__ */ diff --git a/src/rpc-server/trex_rpc_server_mock.cpp b/src/rpc-server/trex_rpc_server_mock.cpp new file mode 100644 index 00000000..98d1f35d --- /dev/null +++ b/src/rpc-server/trex_rpc_server_mock.cpp @@ -0,0 +1,75 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include <trex_rpc_server_api.h> +#include <iostream> +#include <unistd.h> + +using namespace std; + +/** + * on simulation this is not rebuild every version + * (improved stub) + * + */ +extern "C" const char * get_build_date(void){ + return (__DATE__); +} + +extern "C" const char * get_build_time(void){ + return (__TIME__ ); +} + +int gtest_main(int argc, char **argv); + +int main(int argc, char *argv[]) { + + // gtest ? + if (argc > 1) { + if (string(argv[1]) != "--ut") { + cout << "\n[Usage] " << argv[0] << ": " << " [--ut]\n\n"; + exit(-1); + } + return gtest_main(argc, argv); + } + + cout << "\n-= Starting RPC Server Mock =-\n\n"; + cout << "Listening on tcp://localhost:5050 [ZMQ]\n\n"; + + TrexRpcServerConfig rpc_cfg(TrexRpcServerConfig::RPC_PROT_TCP, 5050); + TrexRpcServer rpc(rpc_cfg); + + /* init the RPC server */ + rpc.start(); + + cout << "Setting Server To Full Verbose\n\n"; + rpc.set_verbose(true); + + cout << "Server Started\n\n"; + + while (true) { + sleep(1); + } + + rpc.stop(); + + +} |