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

Connector SSH: moved session to the sessions namespace and reduce its prerogatives.

parent c9d053ed
......@@ -129,10 +129,10 @@ add_library("${CONNECTORLIB}"
"${SRC_DIR}/multiplexer.cc"
"${SRC_DIR}/orders/listener.cc"
"${SRC_DIR}/orders/parser.cc"
# "${SRC_DIR}/session.cc"
# "${SRC_DIR}/sessions.cc"
"${SRC_DIR}/sessions/credentials.cc"
"${SRC_DIR}/sessions/listener.cc"
"${SRC_DIR}/sessions/session.cc"
"${SRC_DIR}/sessions/socket_handle.cc"
# Headers.
# "${INC_DIR}/channel.hh"
......@@ -143,10 +143,10 @@ add_library("${CONNECTORLIB}"
"${INC_DIR}/namespace.hh"
"${INC_DIR}/orders/listener.hh"
"${INC_DIR}/orders/parser.hh"
# "${INC_DIR}/session.hh"
# "${INC_DIR}/sessions.hh"
"${INC_DIR}/sessions/credentials.hh"
"${INC_DIR}/sessions/listener.hh"
"${INC_DIR}/sessions/session.hh"
"${INC_DIR}/sessions/socket_handle.hh"
)
target_link_libraries(
......
......@@ -38,6 +38,7 @@ namespace sessions {
listener(listener const& l);
virtual ~listener();
listener& operator=(listener const& l);
virtual void on_close() = 0;
virtual void on_connected() = 0;
};
}
......
......@@ -18,84 +18,70 @@
** <http://www.gnu.org/licenses/>.
*/
#ifndef CCCS_SESSION_HH
# define CCCS_SESSION_HH
#ifndef CCCS_SESSIONS_SESSION_HH
# define CCCS_SESSIONS_SESSION_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/connector/ssh/sessions/credentials.hh"
# include "com/centreon/connector/ssh/sessions/listener.hh"
# include "com/centreon/connector/ssh/sessions/socket_handle.hh"
# include "com/centreon/handle_listener.hh"
CCCS_BEGIN()
// Forward declaration.
class channel;
namespace sessions {
/**
* @class session session.hh "com/centreon/connector/ssh/session.hh"
* @brief SSH session.
*
* SSH session between Centreon Connector SSH and a remote
* host. The session is kept open as long as needed.
*/
class session : public com::centreon::handle_listener {
public:
session(credentials const& creds);
~session() throw ();
void close();
void close(handle& h);
void connect();
void error(handle& h);
LIBSSH2_SESSION* get_libssh2_session() const throw ();
socket_handle* get_socket_handle() throw ();
bool is_connected() const throw ();
void listen(listener* listnr);
void read(handle& h);
void unlisten(listener* listnr);
bool want_read(handle& h);
bool want_write(handle& h);
void write(handle& h);
/**
* @class session session.hh "com/centreon/connector/ssh/session.hh"
* @brief SSH session.
*
* SSH session between Centreon Connector SSH and a remote
* host. The session is kept open as long as needed.
*/
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,
session_password,
session_key,
session_keepalive
};
private:
enum e_step {
session_connect = 0,
session_startup,
session_password,
session_key,
session_exec
};
struct s_command {
std::string cmd;
unsigned long long cmd_id;
time_t timeout;
};
session(session const& s);
session& operator=(session const& s);
void _connect();
void _key();
void _nop();
void _passwd();
void _startup();
session(session const& s);
session& operator=(session const& s);
void _connect();
void _exec();
void _key();
void _passwd();
void _run();
void _startup();
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;
};
credentials _creds;
std::list<listener*> _listnrs;
LIBSSH2_SESSION* _session;
socket_handle _socket;
e_step _step;
};
}
CCCS_END()
#endif // !CCCS_SESSION_HH
#endif // !CCCS_SESSIONS_SESSION_HH
......@@ -18,6 +18,7 @@
** <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
......@@ -31,15 +32,13 @@
#include <stdlib.h>
#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/sessions/session.hh"
#include "com/centreon/exceptions/basic.hh"
#include "com/centreon/logging/logger.hh"
using namespace com::centreon;
using namespace com::centreon::connector::ssh;
using namespace com::centreon::connector::ssh::sessions;
/**************************************
* *
......@@ -50,20 +49,12 @@ using namespace com::centreon::connector::ssh;
/**
* Constructor.
*
* @param[in] host Host to connect to.
* @param[in] user User name.
* @param[in] password Password.
* @param[in] creds Connection credentials.
*/
session::session(
std::string const& host,
std::string const& user,
std::string const& password)
: _host(host),
_password(password),
session::session(credentials const& creds)
: _creds(creds),
_session(NULL),
_socket(-1),
_step(session_connect),
_user(user) {}
_step(session_connect) {}
/**
* Destructor.
......@@ -82,28 +73,13 @@ void session::close() {
// Unregister with multiplexer.
// XXX
// Shutdown channels.
for (std::list<channel*>::iterator
it = _channels.begin(),
end = _channels.end();
// Notify listeners.
for (std::list<listener*>::iterator
it = _listnrs.begin(),
end = _listnrs.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();
}
(*it)->on_close();
// Delete session.
libssh2_session_set_blocking(_session, 1);
......@@ -132,34 +108,12 @@ void session::close(handle& h) {
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) {
(void)h;
logging::error(logging::high)
<< "error detected on socket, shutting down session";
this->close();
return ;
}
/**
* Open session.
*/
void session::open() {
void session::connect() {
// Check that session wasn't already open.
if (_socket.get_internal_handle() >= 0) {
if (is_connected()) {
logging::info(logging::high)
<< "attempt to open already opened session";
return ;
......@@ -169,7 +123,7 @@ void session::open() {
_step = session_connect;
// Host pointer.
char const* host_ptr(_host.c_str());
char const* host_ptr(_creds.get_host().c_str());
// Host lookup.
sockaddr_in sin;
......@@ -234,7 +188,7 @@ void session::open() {
}
// Connect to remote host.
if ((connect(mysocket, (sockaddr*)&sin, sizeof(sin)) != 0)
if ((::connect(mysocket, (sockaddr*)&sin, sizeof(sin)) != 0)
&& (errno != EINPROGRESS)) {
char const* msg(strerror(errno));
::close(mysocket);
......@@ -251,6 +205,56 @@ void session::open() {
return ;
}
/**
* Error callback.
*
* @param[in,out] h Handle.
*/
void session::error(handle& h) {
(void)h;
logging::error(logging::high)
<< "error detected on socket, shutting down session";
this->close();
return ;
}
/**
* Get the libssh2 session object.
*
* @return libssh2 session object.
*/
LIBSSH2_SESSION* session::get_libssh2_session() const throw () {
return (_session);
}
/**
* Get the socket handle.
*
* @return Socket handle.
*/
socket_handle* session::get_socket_handle() throw () {
return (&_socket);
}
/**
* Check if session is connected.
*
* @return true if session is connected.
*/
bool session::is_connected() const throw () {
return (_step == session_keepalive);
}
/**
* Add listener to session.
*
* @param[in] listnr New listener.
*/
void session::listen(listener* listnr) {
_listnrs.push_back(listnr);
return ;
}
/**
* Read data is available.
*
......@@ -263,54 +267,22 @@ void session::read(handle& h) {
&session::_startup,
&session::_passwd,
&session::_key,
&session::_exec
&session::_nop
};
(this->*redirector[_step])();
return ;
}
/**
* Run a command.
* Remove a listener.
*
* @param[in] cmd Command line.
* @param[in] cmd_id Command ID.
* @param[in] timeout Command timeout.
* @param[in] listnr Listener to remove.
*/
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);
void session::unlisten(listener* listnr) {
std::remove(_listnrs.begin(), _listnrs.end(), listnr);
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.
*
......@@ -398,44 +370,6 @@ void session::_connect() {
return ;
}
/**
* Run commands.
*/
void session::_exec() {
// Run all channels.
for (std::list<channel*>::iterator
it = _channels.begin(),
end = _channels.end();
it != end;
++it) {
// 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(cr);
}
catch (std::exception const& e) {
to_del = true;
std::cerr << e.what() << std::endl;
}
catch (...) {
to_del = true;
}
if (to_del) {
commander::instance().submit_check_result(cr);
delete *it;
_channels.erase(it);
break ;
}
}
// Launch new commands.
_run();
return ;
}
/**
* Attempt public key authentication.
*/
......@@ -457,10 +391,10 @@ void session::_key() {
// Try public key authentication.
int retval(libssh2_userauth_publickey_fromfile(_session,
_user.c_str(),
_creds.get_user().c_str(),
pub.c_str(),
priv.c_str(),
_password.c_str()));
_creds.get_password().c_str()));
if (retval < 0) {
if (retval != LIBSSH2_ERROR_EAGAIN)
throw (basic_error() << "user authentication failed");
......@@ -470,8 +404,23 @@ void session::_key() {
libssh2_session_set_blocking(_session, 0);
// Set execution step.
_step = session_exec;
_step = session_keepalive;
for (std::list<listener*>::iterator
it = _listnrs.begin(),
end = _listnrs.end();
it != end;
++it)
(*it)->on_connected();
}
return ;
}
/**
* No operation.
*/
void session::_nop() {
logging::debug(logging::high) << "session is performing no operation";
return ;
}
/**
......@@ -480,8 +429,8 @@ void session::_key() {
void session::_passwd() {
// Try password.
int retval(libssh2_userauth_password(_session,
_user.c_str(),
_password.c_str()));
_creds.get_user().c_str(),
_creds.get_password().c_str()));
if (retval != 0) {
#if LIBSSH2_VERSION_NUM >= 0x010203
if (retval == LIBSSH2_ERROR_AUTHENTICATION_FAILED) {
......@@ -504,32 +453,14 @@ void session::_passwd() {
// Enable non-blocking mode.
libssh2_session_set_blocking(_session, 0);
// Set execution step.
_step = session_exec;
_exec();
}
return ;
}
/**
* Run new commands.
*/
void session::_run() {
while (!_commands.empty()) {
s_command& s(_commands.front());
try {
std::auto_ptr<channel> ptr(new channel(_session,
s.cmd,
s.cmd_id));
_channels.push_back(ptr.get());
ptr.release();
}
catch (...) {
check_result cr;
cr.set_command_id(s.cmd_id);
commander::instance().submit_check_result(cr);
}
_commands.pop();
// We're now connected.
_step = session_keepalive;
for (std::list<listener*>::iterator
it = _listnrs.begin(),
end = _listnrs.end();
it != end;
++it)
(*it)->on_connected();
}
return ;
}
......@@ -595,7 +526,7 @@ void session::_startup() {
#if LIBSSH2_VERSION_NUM >= 0x010206
// Introduced in 1.2.6.
int check(libssh2_knownhost_checkp(known_hosts,
_host.c_str(),
_creds.get_host().c_str(),
22,
fingerprint,
len,
......@@ -604,7 +535,7 @@ void session::_startup() {
#else
// 1.2.5 or older.
int check(libssh2_knownhost_check(known_hosts,
_host.c_str(),
creds.get_host().c_str(),
fingerprint,
len,
LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW,
......@@ -617,7 +548,7 @@ void session::_startup() {
// Check fingerprint.
if (check != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
exceptions::basic e(basic_error());
e << "host '" << _host.c_str()
e << "host '" << _creds.get_host()
<< "' is not known or could not be validated: ";
if (LIBSSH2_KNOWNHOST_CHECK_NOTFOUND == check)
e << "host was not found in known_hosts file";
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment