Commit e8876030 authored by Matthieu Kermagoret's avatar Matthieu Kermagoret
Browse files

Connector SSH: made session compile again.

parent 13e9cee1
......@@ -127,7 +127,7 @@ add_library("${CONNECTORLIB}"
"${SRC_DIR}/commander.cc"
# "${SRC_DIR}/credentials.cc"
"${SRC_DIR}/multiplexer.cc"
# "${SRC_DIR}/session.cc"
"${SRC_DIR}/session.cc"
# "${SRC_DIR}/sessions.cc"
"${SRC_DIR}/socket_handle.cc"
# "${SRC_DIR}/std_io.cc"
......@@ -138,7 +138,7 @@ add_library("${CONNECTORLIB}"
# "${INC_DIR}/credentials.hh"
"${INC_DIR}/multiplexer.hh"
"${INC_DIR}/namespace.hh"
# "${INC_DIR}/session.hh"
"${INC_DIR}/session.hh"
# "${INC_DIR}/sessions.hh"
"${INC_DIR}/socket_handle.hh"
# "${INC_DIR}/std_io.hh"
......
......@@ -43,6 +43,7 @@ public:
std::string const& cmd,
unsigned long long cmd_id);
~channel();
unsigned long long get_command_id() const;
bool run(check_result& cr);
private:
......
......@@ -23,6 +23,7 @@
# include <memory>
# include <string>
# include "com/centreon/connector/ssh/check_result.hh"
# include "com/centreon/connector/ssh/namespace.hh"
# include "com/centreon/handle_listener.hh"
# include "com/centreon/io/standard_input.hh"
......@@ -45,6 +46,7 @@ public:
static void load();
void read(handle& h);
void reg();
void submit_check_result(check_result const& cr);
static void unload();
void unreg(bool all = true);
bool want_read(handle& h);
......
......@@ -18,17 +18,19 @@
** <http://www.gnu.org/licenses/>.
*/
#ifndef CCC_SSH_SESSION_HH_
# define CCC_SSH_SESSION_HH_
#ifndef CCCS_SESSION_HH
# define CCCS_SESSION_HH
# include <libssh2.h>
# include <list>
# include <queue>
# include <string>
# include <sys/types.h>
# include "com/centreon/connector/ssh/namespace.hh"
# include <libssh2.h>
# include <list>
# include <queue>
# include <string>
# include <sys/types.h>
# include "com/centreon/connector/ssh/namespace.hh"
# include "com/centreon/connector/ssh/socket_handle.hh"
# include "com/centreon/handle_listener.hh"
CCC_SSH_BEGIN()
CCCS_BEGIN()
// Forward declaration.
class channel;
......@@ -40,8 +42,28 @@ class channel;
* SSH session between Centreon Connector SSH and a remote
* host. The session is kept open as long as needed.
*/
class session {
private:
class session : public com::centreon::handle_listener {
public:
session(
std::string const& host,
std::string const& user,
std::string const& password);
~session() throw ();
void close();
void close(handle& h);
bool empty() const;
void error(handle& h);
void open();
void read(handle& h);
void run(
std::string const& cmd,
unsigned long long cmd_id,
time_t timeout);
bool want_read(handle& h);
bool want_write(handle& h);
void write(handle& h);
private:
enum e_step {
session_connect = 0,
session_startup,
......@@ -54,41 +76,26 @@ class session {
unsigned long long cmd_id;
time_t timeout;
};
std::list<channel*> _channels;
std::queue<s_command> _commands;
std::string _host;
std::string _password;
LIBSSH2_SESSION* _session;
int _socket;
e_step _step;
std::string _user;
session(session const& s);
session& operator=(session const& s);
void _connect();
void _exec();
void _key();
void _passwd();
void _run();
void _startup();
session(session const& s);
session& operator=(session const& s);
public:
session(std::string const& host,
std::string const& user,
std::string const& password);
~session();
bool empty() const;
time_t get_timeout();
void read();
bool read_wanted() const;
void run(std::string const& cmd,
unsigned long long cmd_id,
time_t timeout);
int socket() const;
void timeout(time_t now);
void write();
bool write_wanted() const;
std::list<channel*> _channels;
std::queue<s_command> _commands;
std::string _host;
std::string _password;
LIBSSH2_SESSION* _session;
socket_handle _socket;
e_step _step;
std::string _user;
};
CCC_SSH_END()
CCCS_END()
#endif /* !CCC_SSH_SESSION_HH_ */
#endif // !CCCS_SESSION_HH
......@@ -64,6 +64,15 @@ channel::~channel() {
}
}
/**
* Get command ID associated with channel.
*
* @return Command ID associated with channel.
*/
unsigned long long channel::get_command_id() const {
return (_cmd_id);
}
/**
* Attempt to run command.
*
......
......@@ -147,6 +147,46 @@ void commander::reg() {
return ;
}
/**
* Send a check result back to the monitoring engine.
*
* @param[in] cr Check result.
*/
void commander::submit_check_result(check_result const& cr) {
// Build packet.
std::ostringstream oss;
// Packet ID.
oss << "3";
oss.put('\0');
// Command ID.
oss << cr.get_command_id();
oss.put('\0');
// Executed.
oss << (cr.get_executed() ? "1" : "0");
oss.put('\0');
// Exit code.
oss << cr.get_exit_code();
oss.put('\0');
// Error output.
if (cr.get_error().empty())
oss.put(' ');
else
oss << cr.get_error();
oss.put('\0');
// Standard output.
if (cr.get_output().empty())
oss.put(' ');
else
oss << cr.get_output();
// Packet boundary.
for (unsigned int i = 0; i < 4; ++i)
oss.put('\0');
// Append packet to write buffer.
_wbuffer.append(oss.str());
return ;
}
/**
* Unload singleton.
*/
......
......@@ -32,12 +32,311 @@
#include <string.h>
#include <sys/socket.h>
#include "com/centreon/connector/ssh/channel.hh"
#include "com/centreon/connector/ssh/commander.hh"
#include "com/centreon/connector/ssh/multiplexer.hh"
#include "com/centreon/connector/ssh/session.hh"
#include "com/centreon/connector/ssh/std_io.hh"
#include "com/centreon/exceptions/basic.hh"
#include "com/centreon/logging/logger.hh"
using namespace com::centreon;
using namespace com::centreon::connector::ssh;
/**************************************
* *
* Public Methods *
* *
**************************************/
/**
* Constructor.
*
* @param[in] host Host to connect to.
* @param[in] user User name.
* @param[in] password Password.
*/
session::session(
std::string const& host,
std::string const& user,
std::string const& password)
: _host(host),
_password(password),
_session(NULL),
_socket(-1),
_step(session_connect),
_user(user) {}
/**
* Destructor.
*/
session::~session() throw () {
try {
this->close();
}
catch (...) {}
}
/**
* Close session.
*/
void session::close() {
// Unregister with multiplexer.
// XXX
// Shutdown channels.
for (std::list<channel*>::iterator
it = _channels.begin(),
end = _channels.end();
it != end;
++it)
try {
check_result cr;
cr.set_command_id((*it)->get_command_id());
commander::instance().submit_check_result(cr);
delete *it;
}
catch (...) {}
_channels.clear();
// Send result of not run commands.
while (!_commands.empty()) {
check_result cr;
cr.set_command_id(_commands.front().cmd_id);
commander::instance().submit_check_result(cr);
_commands.pop();
}
// Delete session.
libssh2_session_set_blocking(_session, 1);
libssh2_session_disconnect(
_session,
"Centreon Connector SSH shutdown");
libssh2_session_free(_session);
_session = NULL;
// Close socket.
_socket.close();
return ;
}
/**
* Close callback.
*
* @param[in,out] h Handle.
*/
void session::close(handle& h) {
// XXX
return ;
}
/**
* Check if channel list is empty or not.
*
* @return true if the channel list is empty.
*/
bool session::empty() const {
return (_channels.empty());
}
/**
* Error callback.
*
* @param[in,out] h Handle.
*/
void session::error(handle& h) {
// XXX
return ;
}
/**
* Open session.
*/
void session::open() {
// Check that session wasn't already open.
if (_socket.get_internal_handle() >= 0) {
logging::info(logging::high)
<< "attempt to open already opened session";
return ;
}
// Step.
_step = session_connect;
// Host pointer.
char const* host_ptr(_host.c_str());
// Host lookup.
sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
{
// Try to avoid DNS lookup.
in_addr_t addr(inet_addr(host_ptr));
if (addr != (in_addr_t)-1)
sin.sin_addr.s_addr = addr;
// DNS lookup.
else {
// IPv4 address lookup only.
addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;
addrinfo* res;
int retval(getaddrinfo(host_ptr,
NULL,
&hint,
&res));
if (retval)
throw (basic_error() << "lookup of host '" << host_ptr
<< "' failed: " << gai_strerror(retval));
else if (!res)
throw (basic_error() << "no IPv4 address found for host '"
<< host_ptr << "'");
// Get address.
sin.sin_addr.s_addr = ((sockaddr_in*)(res->ai_addr))->sin_addr.s_addr;
// Free result.
freeaddrinfo(res);
}
}
// Set address info.
sin.sin_family = AF_INET;
sin.sin_port = htons(22); // Standard SSH port.
// Create socket.
int mysocket;
mysocket = ::socket(AF_INET, SOCK_STREAM, 0);
if (mysocket < 0) {
char const* msg(strerror(errno));
throw (basic_error() << "socket creation failed: " << msg);
}
// Set socket non-blocking.
int flags(fcntl(mysocket, F_GETFL));
if (flags < 0) {
char const* msg(strerror(errno));
::close(mysocket);
throw (basic_error() << "could not get socket flags: " << msg);
}
flags |= O_NONBLOCK;
if (fcntl(mysocket, F_SETFL, flags) == -1) {
char const* msg(strerror(errno));
::close(mysocket);
throw (basic_error()
<< "could not make socket non blocking: " << msg);
}
// Connect to remote host.
if ((connect(mysocket, (sockaddr*)&sin, sizeof(sin)) != 0)
&& (errno != EINPROGRESS)) {
char const* msg(strerror(errno));
::close(mysocket);
throw (basic_error() << "could not connect to '"
<< host_ptr << "': " << msg);
}
// Set socket handle.
_socket.set_native_handle(mysocket);
// Register with multiplexer.
multiplexer::instance().handle_manager::add(&_socket, this);
return ;
}
/**
* Read data is available.
*
* @param[in] h Handle.
*/
void session::read(handle& h) {
(void)h;
static void (session::* const redirector[])() = {
&session::_connect,
&session::_startup,
&session::_passwd,
&session::_key,
&session::_exec
};
(this->*redirector[_step])();
return ;
}
/**
* Run a command.
*
* @param[in] cmd Command line.
* @param[in] cmd_id Command ID.
* @param[in] timeout Command timeout.
*/
void session::run(
std::string const& cmd,
unsigned long long cmd_id,
time_t timeout) {
s_command s;
s.cmd = cmd;
s.cmd_id = cmd_id;
s.timeout = timeout;
_commands.push(s);
return ;
}
/**
* Check timeouts.
*
* @param[in] now Current time.
*/
/*void session::check_timeout(time_t now) {
for (std::list<channel*>::iterator
it = _channels.begin(),
end = _channels.end();
it != end;)
if ((*it)->timeout() < now) {
try {
// XXX : check_result
delete *it;
}
catch (...) {}
_channels.erase(it++);
}
else
++it;
return ;
}*/
/**
* Check if read monitoring is wanted.
*
* @return true if read monitoring is wanted.
*/
bool session::want_read(handle& h) {
(void)h;
return (_session && (libssh2_session_block_directions(_session)
& LIBSSH2_SESSION_BLOCK_INBOUND));
}
/**
* Check if write monitoring is wanted.
*
* @return true if write monitoring is wanted.
*/
bool session::want_write(handle& h) {
(void)h;
return (!_session || (libssh2_session_block_directions(_session)
& LIBSSH2_SESSION_BLOCK_OUTBOUND));
}
/**
* Write data is available.
*
* @param[in] h Handle.
*/
void session::write(handle& h) {
read(h);
return ;
}
/**************************************
* *
* Private Methods *
......@@ -53,7 +352,7 @@ using namespace com::centreon::connector::ssh;
*/
session::session(session const& s) {
(void)s;
assert(false);
assert(!"session is not copyable");
abort();
}
......@@ -68,7 +367,7 @@ session::session(session const& s) {
*/
session& session::operator=(session const& s) {
(void)s;
assert(false);
assert(!"session is not copyable");
abort();
return (*this);
}
......@@ -106,8 +405,9 @@ void session::_exec() {
// Delete object is 1) requested by channel or
// 2) because channel thrown an exception.
bool to_del(false);
check_result cr;
try {
to_del = !(*it)->run();
to_del = !(*it)->run(cr);
}
catch (std::exception const& e) {
to_del = true;
......@@ -117,6 +417,7 @@ void session::_exec() {
to_del = true;
}
if (to_del) {
commander::instance().submit_check_result(cr);
delete *it;
_channels.erase(it);
break ;
......@@ -213,17 +514,14 @@ void session::_run() {
try {
std::auto_ptr<channel> ptr(new channel(_session,
s.cmd,
s.cmd_id,
s.timeout));
s.cmd_id));
_channels.push_back(ptr.get());
ptr.release();
}
catch (...) {
std_io::instance().submit_check_result(s.cmd_id,
false,
-1,
"",
"");
check_result cr;
cr.set_command_id(s.cmd_id);
commander::instance().submit_check_result(cr);
}
_commands.pop();
}
......@@ -235,7 +533,9 @@ void session::_run() {
*/
void session::_startup() {
// Exchange banners, keys, setup crypto, compression, ...
int retval(libssh2_session_startup(_session, _socket));
int retval(libssh2_session_startup(
_session,
_socket.get_internal_handle()));
if (retval) {
if (retval != LIBSSH2_ERROR_EAGAIN) { // Fatal failure.
char* msg;
......@@ -327,259 +627,5 @@ void session::_startup() {
_passwd();
}
}
}
/**************************************
* *
* Public Methods *
* *
**************************************/
/**
* Constructor.
*
* @param[in] host Host to connect to.
* @param[in] user User name.
* @param[in] password Password.
*/
session::session(std::string const& host,
std::string const& user,
std::string const& password)
: _host(host),
_password(password),
_session(NULL),
_socket(-1),
_step(session_connect),
_user(user) {
// Host pointer.
char const* host_ptr(_host.c_str());