summaryrefslogtreecommitdiffstats
path: root/src/rpc-server
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc-server')
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_general.cpp59
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp223
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_test.cpp81
-rw-r--r--src/rpc-server/commands/trex_rpc_cmds.h77
-rw-r--r--src/rpc-server/trex_rpc_cmd.cpp258
-rw-r--r--src/rpc-server/trex_rpc_cmd_api.h179
-rw-r--r--src/rpc-server/trex_rpc_cmds_table.cpp70
-rw-r--r--src/rpc-server/trex_rpc_cmds_table.h79
-rw-r--r--src/rpc-server/trex_rpc_exception_api.h42
-rw-r--r--src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp202
-rw-r--r--src/rpc-server/trex_rpc_jsonrpc_v2_parser.h94
-rw-r--r--src/rpc-server/trex_rpc_req_resp_server.cpp146
-rw-r--r--src/rpc-server/trex_rpc_req_resp_server.h51
-rw-r--r--src/rpc-server/trex_rpc_server.cpp153
-rw-r--r--src/rpc-server/trex_rpc_server_api.h165
-rw-r--r--src/rpc-server/trex_rpc_server_mock.cpp75
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 &params, Json::Value &result) {
+
+ Json::Value &section = 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 &params, Json::Value &result) {
+
+ const Json::Value &section = 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 &section, 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 &params, 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 &params, 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 &params, 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 &params, 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 &params, Json::Value &result) {
+
+ result["result"] = "ACK";
+ return (TREX_RPC_CMD_OK);
+}
+
+/**
+ * query command
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdGetReg::_run(const Json::Value &params, 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 &params, 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 &section, 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 &params, 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 &params, 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 &params, 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 &params, Json::Value &result) = 0;
+
+ /**
+ * check param count
+ */
+ void check_param_count(const Json::Value &params, 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 &params) : 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();
+
+
+}