#ifndef EXCEPTION_H
#define EXCEPTION_H
#include <boost/exception/all.hpp>
#include <string>
namespace utils
{
/*!
* \brief error_key An unique ID given to the error according to its
* location. Probably redundant, since we'll be using __FILE__ and
* __LINE__, but it's a low-maintenance scheme, we'll keep it.
*/
typedef boost::error_info<struct tag_error_id, unsigned long> error_key;
/*!
* \brief error_id Similar to boost::errinfo_errno, but without the
* automatic error message mechanism. E.g., if we have an error
* code 3 and use boost::errinfo_errno, it'll include the message
* "No such process", which won't be suitable for our error,
* since it has a different meaning.
*/
typedef boost::error_info<struct tag_error_id, int> error_id;
typedef boost::error_info<struct tag_error_message, std::string>
error_message;
/*!
* \brief nested_exception Sometimes, we'll be using neste exceptions
* just to implement a very basic stack trace. It' won't be a real
* stack trace, since it has nothing outside of our own code, but
* it's a starting point.
*/
typedef boost::error_info<struct tag_nested_exception,
boost::exception_ptr> nested_exception;
/*!
* \brief The PCBBaseException struct. As the name states,
* it's our base exception
*/
struct PCBBaseException : virtual std::exception,
virtual boost::exception { };
} // namespace utils
#endif // EXCEPTION_H
sshexception.h
#ifndef SSHEXCEPTION_H
#define SSHEXCEPTION_H
#include "utils/exception.h"
#include <boost/exception/all.hpp>
#include <string>
namespace ssh
{
typedef boost::error_info<struct tag_ssh_error_id, int> ssh_error_id;
typedef boost::error_info<struct tag_ssh_error_string, std::string>
ssh_error_string;
struct SSHBaseException : virtual utils::PCBBaseException { };
struct SSHConnectionError :
virtual SSHBaseException { }; // SOCKET SONNECTION
struct SSHCreateSessionError : virtual SSHBaseException { };
struct SSHHandshakeError : virtual SSHBaseException { };
struct SSHAuthenticationError : virtual SSHBaseException { };
struct SSHDisconnectSessionError :
virtual SSHBaseException { }; // SESSION TERMINATION
struct SSHFreeSessionError : virtual SSHBaseException { };
struct SSHDisconnectionError :
virtual SSHBaseException { }; // SOCKET DISCONNECTION
} // namespace ssh
#endif // SSHEXCEPTION_H
misc.h
#ifndef MISC_H
#define MISC_H
namespace utils
{
enum class CleanupState { NoCleanup, CleanupInProgress, CleanupDone };
} // namespace ssh
#endif // MISC_H
sessionhandle.h
#ifndef SESSIONHANDLE_H
#define SESSIONHANDLE_H
#include "utils/asyncloop.h"
#include "utils/misc.h"
// EVEN THOUGH BOOST ASIO ISN'T USED HERE,
// UNTIL I SOLVE THE PROBLEM WITH THE
// WIN32 #define, I CANNOT #include IT AFTER libssh2
// AVOID ERROR BECAUSE OF swprintf
#undef __STRICT_ANSI__
// #define FOR WIN7. CAN'T FIND sdkddkver.h ON MINGW
#define _WIN32_WINNT 0x0601
#include <boost/asio.hpp>
#include "libssh2_config.h"
#include <libssh2.h>
namespace ssh
{
class SessionHandle
{
public:
SessionHandle();
~SessionHandle();
void CloseSession();
LIBSSH2_SESSION* GetSession() { return session; }
// WE MAY ADD MOVE IN THE FUTURE, BUT NOT COPY
SessionHandle(SessionHandle&&) = delete;
SessionHandle& operator=(SessionHandle&&) = delete;
SessionHandle(SessionHandle const&) = delete;
SessionHandle& operator=(SessionHandle const&) = delete;
private:
utils::TaskState DoCloseSession();
utils::CleanupState cleanupState;
LIBSSH2_SESSION *session;
};
} // namespace ssh
#endif // SESSIONHANDLE_H
sessionhandle.cpp
#include "sshexception.h"
#include "sessionhandle.h"
using utils::AsyncLoopTimer;
#include <boost/bind.hpp>
#include <boost/bind/protect.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lexical_cast.hpp>
using boost::asio::io_service;
using boost::asio::deadline_timer;
using boost::bind;
using boost::posix_time::milliseconds;
using boost::protect;
using boost::lexical_cast;
#include <string>
using std::string;
namespace ssh
{
SessionHandle::SessionHandle() :
cleanupState(utils::CleanupState::NoCleanup),
session(nullptr)
{
session = libssh2_session_init();
if (!session)
{
BOOST_THROW_EXCEPTION(SSHCreateSessionError() <<
ssh_error_string("Error creating SSH session."));
}
libssh2_session_set_blocking(session, 0);
}
SessionHandle::~SessionHandle()
{
// WE'LL ONLY TRY TO CLEANUP
// IF NO ATTEMPT HAS BEEN MADE YET
if ((session != nullptr) &&
(cleanupState == utils::CleanupState::NoCleanup))
{
try
{
CloseSession();
}
catch (...)
{ }
}
}
void SessionHandle::CloseSession()
{
io_service ios;
deadline_timer dt(ios);
dt.expires_from_now(milliseconds(10));
dt.async_wait(bind(AsyncLoopTimer,
protect(bind(&SessionHandle::DoCloseSession, this)),
boost::ref(dt), 10));
cleanupState = utils::CleanupState::CleanupInProgress;
ios.run();
session = nullptr;
cleanupState = utils::CleanupState::CleanupDone;
}
utils::TaskState SessionHandle::DoCloseSession()
{
int rc = libssh2_session_free(session);
if (rc == LIBSSH2_ERROR_EAGAIN)
{
return utils::TASK_WORKING;
}
if (rc)
{
BOOST_THROW_EXCEPTION(SSHFreeSessionError() <<
ssh_error_string("Error " + lexical_cast<string>(rc) +
" freeing SSH session"));
}
return utils::TASK_DONE;
}
} // namespace ssh
No comments:
Post a Comment