#ifndef REMOTESESSIONHANDLE_H
#define REMOTESESSIONHANDLE_H
#include "utils/asyncloop.h"
#include "utils/misc.h"
// 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 <boost/function.hpp>
namespace ssh
{
class SessionHandle;
class RemoteSessionHandle
{
public:
RemoteSessionHandle(boost::function<void(std::string)>& pReportStatus,
boost::asio::ip::tcp::socket& pSock, SessionHandle& pSessionHandle);
~RemoteSessionHandle();
void CloseSession();
// WE MAY ADD MOVE IN THE FUTURE, BUT NOT COPY
RemoteSessionHandle(RemoteSessionHandle&&) = delete;
RemoteSessionHandle& operator=(RemoteSessionHandle&&) = delete;
RemoteSessionHandle(RemoteSessionHandle const&) = delete;
RemoteSessionHandle& operator=(RemoteSessionHandle const&) = delete;
private:
utils::TaskState DoHandshake();
utils::TaskState DoCloseSession();
utils::CleanupState cleanupState;
boost::function<void(std::string)>& reportStatus;
boost::asio::ip::tcp::socket& sock;
SessionHandle& sessionHandle;
};
} // namespace ssh
#endif // REMOTESESSIONHANDLE_H
remotesessionhandle.cpp
#include "remotesessionhandle.h"
using utils::AsyncLoopTimer;
using utils::AsyncLoopSocket;
using boost::asio::io_service;
#include "sshexception.h"
#include "sessionhandle.h"
#include "libssh2_config.h"
#include <libssh2.h>
#include <boost/bind.hpp>
#include <boost/bind/protect.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
using boost::bind;
using boost::protect;
using boost::lexical_cast;
using boost::asio::deadline_timer;
using boost::posix_time::milliseconds;
#include <string>
using std::string;
namespace ssh
{
RemoteSessionHandle::RemoteSessionHandle(
boost::function<void(std::string)>& pReportStatus,
boost::asio::ip::tcp::socket& pSock, SessionHandle& pSessionHandle) :
cleanupState(utils::CleanupState::NoCleanup),
reportStatus(pReportStatus), sock(pSock), sessionHandle(pSessionHandle)
{
if (!reportStatus.empty())
reportStatus("SSH Handshake");
io_service& ios = sock.get_io_service();
ios.reset();
sock.async_read_some(boost::asio::null_buffers(), bind(AsyncLoopSocket,
protect(bind(&RemoteSessionHandle::DoHandshake, this)),
boost::ref(sock), true));
ios.run();
}
RemoteSessionHandle::~RemoteSessionHandle()
{
if (!reportStatus.empty())
reportStatus("Cleanup: SSH remote session.");
// WE'LL ONLY TRY TO CLEANUP IF NO ATTEMPT HAS BEEN MADE YET
if (cleanupState == utils::CleanupState::NoCleanup)
{
try
{
CloseSession();
}
catch (...)
{ }
}
}
void RemoteSessionHandle::CloseSession()
{
io_service ios;
deadline_timer dt(ios);
dt.expires_from_now(milliseconds(10));
dt.async_wait(bind(AsyncLoopTimer,
protect(bind(&RemoteSessionHandle::DoCloseSession, this)),
boost::ref(dt), 10));
cleanupState = utils::CleanupState::CleanupInProgress;
ios.run();
cleanupState = utils::CleanupState::CleanupDone;
}
utils::TaskState RemoteSessionHandle::DoHandshake()
{
int rc = libssh2_session_handshake(sessionHandle.GetSession(),
sock.native_handle());
if (rc == LIBSSH2_ERROR_EAGAIN)
{
return utils::TASK_WORKING;
}
if (rc)
{
BOOST_THROW_EXCEPTION(SSHHandshakeError() <<
ssh_error_string("Error " + lexical_cast<string>(rc) +
" during SSH Handshake.") << ssh_error_id(rc));
}
return utils::TASK_DONE;
}
utils::TaskState RemoteSessionHandle::DoCloseSession()
{
int rc = libssh2_session_disconnect(sessionHandle.GetSession(),
"Disconnect SSH session");
if (rc == LIBSSH2_ERROR_EAGAIN)
{
return utils::TASK_WORKING;
}
if (rc)
{
BOOST_THROW_EXCEPTION(SSHDisconnectSessionError() <<
ssh_error_string("Error " + lexical_cast<string>(rc) +
" disconnecting SSH session.") << ssh_error_id(rc));
}
return utils::TASK_DONE;
}
} // namespace ssh
No comments:
Post a Comment