Commit 6d39c2ed authored by Matthieu Kermagoret's avatar Matthieu Kermagoret
Browse files

Connector SSH: added orders::parser class.

parent 592402a1
......@@ -128,6 +128,7 @@ add_library("${CONNECTORLIB}"
# "${SRC_DIR}/credentials.cc"
"${SRC_DIR}/multiplexer.cc"
"${SRC_DIR}/orders/listener.cc"
"${SRC_DIR}/orders/parser.cc"
# "${SRC_DIR}/session.cc"
# "${SRC_DIR}/sessions.cc"
# "${SRC_DIR}/socket_handle.cc"
......@@ -139,6 +140,7 @@ add_library("${CONNECTORLIB}"
"${INC_DIR}/multiplexer.hh"
"${INC_DIR}/namespace.hh"
"${INC_DIR}/orders/listener.hh"
"${INC_DIR}/orders/parser.hh"
# "${INC_DIR}/session.hh"
# "${INC_DIR}/sessions.hh"
# "${INC_DIR}/socket_handle.hh"
......@@ -168,6 +170,7 @@ if (WITH_TESTING)
# Enable testing.
enable_testing()
set(BUILD_UNIT_TEST "Yes")
include_directories("${PROJECT_SOURCE_DIR}")
# check_result tests.
# Default constructor.
......@@ -219,6 +222,62 @@ if (WITH_TESTING)
target_link_libraries("${TEST_NAME}" "${CONNECTORLIB}")
add_test("${TEST_NAME}" "${TEST_NAME}")
#
# orders namespace tests.
#
# Common library.
add_library("test_orders" STATIC
# Sources.
"${TEST_DIR}/orders/buffer_handle.cc"
"${TEST_DIR}/orders/fake_listener.cc"
# Headers.
"${TEST_DIR}/orders/buffer_handle.hh"
"${TEST_DIR}/orders/fake_listener.hh")
set(ORDERS_LIBRARIES "test_orders" "${CONNECTORLIB}")
# parser tests.
# Default constructor.
set(TEST_NAME "orders_parser_ctor_default")
add_executable("${TEST_NAME}"
"${TEST_DIR}/orders/parser/ctor_default.cc")
target_link_libraries("${TEST_NAME}" ${ORDERS_LIBRARIES})
add_test("${TEST_NAME}" "${TEST_NAME}")
# EOF detection.
set(TEST_NAME "orders_parser_eof")
add_executable("${TEST_NAME}"
"${TEST_DIR}/orders/parser/eof.cc")
target_link_libraries("${TEST_NAME}" ${ORDERS_LIBRARIES})
add_test("${TEST_NAME}" "${TEST_NAME}")
# Error detection.
set(TEST_NAME "orders_parser_error")
add_executable("${TEST_NAME}"
"${TEST_DIR}/orders/parser/error.cc")
target_link_libraries("${TEST_NAME}" ${ORDERS_LIBRARIES})
add_test("${TEST_NAME}" "${TEST_NAME}")
# Version order.
set(TEST_NAME "orders_parser_version")
add_executable("${TEST_NAME}"
"${TEST_DIR}/orders/parser/version.cc")
target_link_libraries("${TEST_NAME}" ${ORDERS_LIBRARIES})
add_test("${TEST_NAME}" "${TEST_NAME}")
# Quit order.
set(TEST_NAME "orders_parser_quit")
add_executable("${TEST_NAME}"
"${TEST_DIR}/orders/parser/quit.cc")
target_link_libraries("${TEST_NAME}" ${ORDERS_LIBRARIES})
add_test("${TEST_NAME}" "${TEST_NAME}")
# Execute order.
set(TEST_NAME "orders_parser_execute")
add_executable("${TEST_NAME}"
"${TEST_DIR}/orders/parser/execute.cc")
target_link_libraries("${TEST_NAME}" ${ORDERS_LIBRARIES})
add_test("${TEST_NAME}" "${TEST_NAME}")
# Order suite.
set(TEST_NAME "orders_parser_suite")
add_executable("${TEST_NAME}"
"${TEST_DIR}/orders/parser/suite.cc")
target_link_libraries("${TEST_NAME}" ${ORDERS_LIBRARIES})
add_test("${TEST_NAME}" "${TEST_NAME}")
# multiplexer tests.
# Check singleton.
set(TEST_NAME "multiplexer_singleton")
......
......@@ -41,6 +41,8 @@ namespace orders {
listener(listener const& l);
virtual ~listener();
listener& operator=(listener const& l);
virtual void on_eof() = 0;
virtual void on_error() = 0;
virtual void on_execute(
unsigned long long cmd_id,
time_t timeout,
......
/*
** Copyright 2011 Merethis
**
** This file is part of Centreon Connector SSH.
**
** Centreon Connector SSH is free software: you can redistribute it
** and/or modify it under the terms of the GNU Affero General Public
** License as published by the Free Software Foundation, either version
** 3 of the License, or (at your option) any later version.
**
** Centreon Connector SSH is distributed in the hope that it will be
** useful, but WITHOUT ANY WARRANTY; without even the implied warranty
** of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public
** License along with Centreon Connector SSH. If not, see
** <http://www.gnu.org/licenses/>.
*/
#ifndef CCCS_ORDERS_PARSER_HH
# define CCCS_ORDERS_PARSER_HH
# include <string>
# include "com/centreon/connector/ssh/namespace.hh"
# include "com/centreon/connector/ssh/orders/listener.hh"
# include "com/centreon/handle_listener.hh"
CCCS_BEGIN()
namespace orders {
/**
* @class parser parser.hh "com/centreon/connector/ssh/orders/parser.hh"
* @brief Parse orders.
*
* Parse orders, generally issued by the monitoring engine. The
* parser class can handle be registered with one handle at a time
* and one listener.
*/
class parser : public handle_listener {
public:
parser();
parser(parser const& p);
~parser() throw ();
parser& operator=(parser const& p);
void close(handle& h);
void error(handle& h);
std::string const& get_buffer() const throw ();
listener* get_listener() const throw ();
void listen(listener* l = NULL) throw ();
void read(handle& h);
bool want_read(handle& h);
bool want_write(handle& h);
private:
void _copy(parser const& p);
void _parse(std::string const& cmd);
std::string _buffer;
listener* _listnr;
};
}
CCCS_END()
#endif // !CCCS_ORDERS_PARSER_HH
/*
** Copyright 2011 Merethis
**
** This file is part of Centreon Connector SSH.
**
** Centreon Connector SSH is free software: you can redistribute it
** and/or modify it under the terms of the GNU Affero General Public
** License as published by the Free Software Foundation, either version
** 3 of the License, or (at your option) any later version.
**
** Centreon Connector SSH is distributed in the hope that it will be
** useful, but WITHOUT ANY WARRANTY; without even the implied warranty
** of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public
** License along with Centreon Connector SSH. If not, see
** <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string>
#include <string.h>
#include "com/centreon/connector/ssh/orders/parser.hh"
#include "com/centreon/exceptions/basic.hh"
#include "com/centreon/logging/logger.hh"
using namespace com::centreon::connector::ssh::orders;
/**************************************
* *
* Public Methods *
* *
**************************************/
/**
* Default constructor.
*/
parser::parser() : _listnr(NULL) {}
/**
* Copy constructor.
*
* @param[in] p Object to copy.
*/
parser::parser(parser const& p) : handle_listener(p) {
_copy(p);
}
/**
* Destructor.
*/
parser::~parser() throw () {}
/**
* Assignment operator.
*
* @param[in] p Object to copy.
*
* @return This object.
*/
parser& parser::operator=(parser const& p) {
if (this != &p) {
handle_listener::operator=(p);
_copy(p);
}
return (*this);
}
/**
* Got close event on handle.
*
* @param[in] h Handle.
*/
void parser::close(handle& h) {
(void)h;
if (_listnr)
_listnr->on_eof();
return ;
}
/**
* Got error event on handle.
*
* @param[in] h Handle.
*/
void parser::error(handle& h) {
(void)h;
if (_listnr)
_listnr->on_error();
return ;
}
/**
* Get unparsed buffer.
*
* @return Unparsed buffer.
*/
std::string const& parser::get_buffer() const throw () {
return (_buffer);
}
/**
* Get associated listener.
*
* @return Listener if object has one, NULL otherwise.
*/
listener* parser::get_listener() const throw () {
return (_listnr);
}
/**
* Change the listener.
*
* @param[in] l Listener.
*/
void parser::listen(listener* l) throw () {
_listnr = l;
return ;
}
/**
* Read data from handle.
*
* @param[in] h Handle.
*/
void parser::read(handle& h) {
// Read data.
logging::debug(logging::medium) << "reading data for parsing";
char buffer[4096];
unsigned long rb(h.read(buffer, sizeof(buffer)));
logging::debug(logging::medium) << "read "
<< rb << " bytes from handle";
// stdin's eof is reached.
if (!rb) {
logging::debug(logging::high) << "got eof on read handle";
if (_listnr)
_listnr->on_eof();
}
// Data was read.
else {
_buffer.append(buffer, rb);
// Find a command boundary.
char boundary[4];
memset(boundary, 0, sizeof(boundary));
size_t bound(_buffer.find(boundary, 0, sizeof(boundary)));
// Parse command.
while (bound != std::string::npos) {
logging::debug(logging::low)
<< "got command boundary at offset " << bound;
bound += sizeof(boundary);
std::string cmd(_buffer.substr(0, bound));
_buffer.erase(0, bound);
bool error(false);
try {
_parse(cmd);
}
catch (std::exception const& e) {
logging::error(logging::high) << "orders parsing error: "
<< e.what();
error = true;
}
catch (...) {
logging::error(logging::high) << "unknown orders parsing error";
error = true;
}
if (error && _listnr)
_listnr->on_error();
bound = _buffer.find(boundary, 0, sizeof(boundary));
}
}
return ;
}
/**
* Do we want to read handle ?
*
* @return Always true.
*/
bool parser::want_read(handle& h) {
(void)h;
return (true);
}
/**
* Do we want to write to handle ?
*
* @return Always false (class just parse).
*/
bool parser::want_write(handle& h) {
(void)h;
return (false);
}
/**************************************
* *
* Private Methods *
* *
**************************************/
/**
* Copy internal data members.
*
* @param[in] p Object to copy.
*/
void parser::_copy(parser const& p) {
_buffer = p._buffer;
_listnr = p._listnr;
return ;
}
/**
* Parse a command.
*
* @param[in] cmd Command to parse.
*/
void parser::_parse(std::string const& cmd) {
// Get command ID.
size_t pos(cmd.find('\0'));
if (std::string::npos == pos)
throw (basic_error() << "invalid command received");
unsigned int id(strtoul(cmd.c_str(), NULL, 10));
++pos;
// Process each command as necessary.
switch (id) {
case 0: // Version query.
if (_listnr)
_listnr->on_version();
break ;
case 2: // Execute query.
{
// Find command ID.
size_t end(cmd.find('\0', pos));
if (std::string::npos == end)
throw (basic_error() << "invalid execution request received");
unsigned long long cmd_id(strtoull(cmd.c_str() + pos, NULL, 10));
pos = end + 1;
// Find timeout value.
end = cmd.find('\0', pos);
if (std::string::npos == end)
throw (basic_error() << "invalid execution request received");
time_t timeout(static_cast<time_t>(strtoull(
cmd.c_str() + pos,
NULL,
10)));
timeout += time(NULL);
pos = end + 1;
// Find start time.
end = cmd.find('\0', pos);
if (std::string::npos == end)
throw (basic_error() << "invalid execution request received");
pos = end + 1;
// Find command to execute.
end = cmd.find('\0', pos);
if (std::string::npos == end)
throw (basic_error() << "invalid execution request received");
std::string cmdline(cmd.substr(pos, end - pos));
// Find target host.
pos = 0;
end = cmdline.find(' ', pos);
if (std::string::npos == end)
throw (basic_error() << "invalid execution command");
std::string host(cmdline.substr(pos, end - pos));
pos = end + 1;
// Find user name.
end = cmdline.find(' ', pos);
if (std::string::npos == end)
throw (basic_error() << "invalid execution command");
std::string user(cmdline.substr(pos, end - pos));
pos = end + 1;
// Find password.
end = cmdline.find(' ', pos);
if (std::string::npos == end)
throw (basic_error() << "invalid execution command");
std::string password(cmdline.substr(pos, end - pos));
pos = end + 1;
// Find command.
std::string command(cmdline.substr(pos));
// Notify listener.
if (_listnr)
_listnr->on_execute(
cmd_id,
timeout,
host,
user,
password,
command);
}
break ;
case 4: // Quit query.
if (_listnr)
_listnr->on_quit();
break ;
};
return ;
}
/*
** Copyright 2011 Merethis
**
** This file is part of Centreon Connector SSH.
**
** Centreon Connector SSH is free software: you can redistribute it
** and/or modify it under the terms of the GNU Affero General Public
** License as published by the Free Software Foundation, either version
** 3 of the License, or (at your option) any later version.
**
** Centreon Connector SSH is distributed in the hope that it will be
** useful, but WITHOUT ANY WARRANTY; without even the implied warranty
** of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public
** License along with Centreon Connector SSH. If not, see
** <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "test/orders/buffer_handle.hh"
using namespace com::centreon;
/**
* Default constructor.
*/
buffer_handle::buffer_handle() {}
/**
* Copy constructor.
*
* @param[in] bh Object to copy.
*/
buffer_handle::buffer_handle(buffer_handle const& bh) : handle(bh) {
_copy(bh);
}
/**
* Destructor.
*/
buffer_handle::~buffer_handle() throw () {}
/**
* Assignment operator.
*
* @param[in] bh Object to copy.
*
* @return This object.
*/
buffer_handle& buffer_handle::operator=(buffer_handle const& bh) {
if (this != &bh) {
handle::operator=(bh);
_copy(bh);
}
return (*this);
}
/**
* Close handle.
*/
void buffer_handle::close() {
_buffer.clear();
return ;
}
/**
* Check if buffer is empty.
*
* @return true if buffer is empty.
*/
bool buffer_handle::empty() const {
return (_buffer.empty());
}
/**
* Read data.
*
* @param[in] data Destination buffer.
* @param[in] size Maximum size to read.
*
* @return Number of bytes read.
*/
unsigned long buffer_handle::read(void* data, unsigned long size) {
// Check size to read.
{
unsigned long buffer_size(_buffer.size());
if (size > buffer_size)
size = buffer_size;
}
// Read data.
memcpy(data, _buffer.c_str(), size);
_buffer.erase(0, size);
return (size);
}
/**
* Write data.
*
* @param[in] data Source buffer.
* @param[in] size Size to write.
*
* @return size.
*/
unsigned long buffer_handle::write(
void const* data,
unsigned long size) {
_buffer.append(static_cast<char const*>(data), size);
return (size);
}
/**************************************
* *
* Private Methods *
* *
**************************************/
/**
* Copy internal data members.
*
* @param[in] bh Object to copy.
*/
void buffer_handle::_copy(buffer_handle const& bh) {
_buffer = bh._buffer;
return ;
}
/*
** Copyright 2011 Merethis
**
** This file is part of Centreon Connector SSH.
**
** Centreon Connector SSH is free software: you can redistribute it
** and/or modify it under the terms of the GNU Affero General Public
** License as published by the Free Software Foundation, either version
** 3 of the License, or (at your option) any later version.
**
** Centreon Connector SSH is distributed in the hope that it will be
** useful, but WITHOUT ANY WARRANTY; without even the implied warranty
** of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public
** License along with Centreon Connector SSH. If not, see
** <http://www.gnu.org/licenses/>.
*/
#ifndef TEST_ORDERS_BUFFER_HANDLE_HH
# define TEST_ORDERS_BUFFER_HANDLE_HH
# include <string>
# include "com/centreon/handle.hh"
/**