187 lines
4.3 KiB
C++
187 lines
4.3 KiB
C++
#include "qsshsocket.h"
|
|
#include <libssh/callbacks.h>
|
|
|
|
bool QSshSocket::lib_ssh_inited = false;
|
|
|
|
QSshSocket::QSshSocket(QObject * parent)
|
|
:QObject(parent),
|
|
loggedIn(false),
|
|
session(0),
|
|
m_connected(false),
|
|
executing(false),
|
|
command(0)
|
|
{
|
|
if (!lib_ssh_inited) {
|
|
lib_ssh_init();
|
|
lib_ssh_inited = true;
|
|
}
|
|
qRegisterMetaType<QSshSocket::SshError>(); //not sure if it supposed to be here
|
|
}
|
|
|
|
QSshSocket::~QSshSocket()
|
|
{
|
|
}
|
|
|
|
void QSshSocket::disconnect()
|
|
{
|
|
if (m_connected) {
|
|
loggedIn = false;
|
|
m_connected = false;
|
|
|
|
if (executing) {
|
|
destroyCommand();
|
|
}
|
|
ssh_disconnect(session);
|
|
ssh_free(session);
|
|
session = 0;
|
|
emit disconnected();
|
|
}
|
|
}
|
|
|
|
void QSshSocket::connect(QString host, int port)
|
|
{
|
|
if (!m_connected) {
|
|
session = ssh_new();
|
|
int verbosity = SSH_LOG_PROTOCOL;
|
|
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
|
ssh_options_set(session, SSH_OPTIONS_HOST, host.toUtf8().data());
|
|
ssh_options_set(session, SSH_OPTIONS_PORT, &port);
|
|
|
|
int connectionResponse = ssh_connect(session);
|
|
|
|
if (connectionResponse == SSH_OK) {
|
|
m_connected = true;
|
|
emit connected();
|
|
} else {
|
|
ssh_disconnect(session);
|
|
ssh_free(session);
|
|
session = 0;
|
|
emit error(SessionCreationError);
|
|
}
|
|
} else {
|
|
throw 1; //TODO
|
|
}
|
|
}
|
|
void QSshSocket::login(QString user, QString password)
|
|
{
|
|
if (m_connected && !loggedIn) {
|
|
int worked = ssh_userauth_password(session, user.toUtf8().data(), password.toUtf8().data());
|
|
|
|
if (worked == SSH_OK) {
|
|
loggedIn = true;
|
|
emit loginSuccessful();
|
|
} else {
|
|
emit error(PasswordAuthenticationFailedError);
|
|
disconnect();
|
|
}
|
|
} else {
|
|
throw 2; //TODO
|
|
}
|
|
|
|
}
|
|
|
|
void QSshSocket::executeCommand(QString p_command)
|
|
{
|
|
if (executing) {
|
|
//todo
|
|
return;
|
|
}
|
|
ssh_channel channel = ssh_channel_new(session);
|
|
if (ssh_channel_open_session(channel) != SSH_OK) {
|
|
emit error(ChannelCreationError);
|
|
}
|
|
int success;
|
|
do {
|
|
success = ssh_channel_request_exec(channel, p_command.toUtf8().data());
|
|
} while (success == SSH_AGAIN);
|
|
|
|
if (success != SSH_OK) {
|
|
ssh_channel_close(channel);
|
|
ssh_channel_free(channel);
|
|
emit error(WriteError);
|
|
} else {
|
|
qintptr fd = ssh_get_fd(session);
|
|
QSocketNotifier* readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read);
|
|
QObject::connect(readNotifier, SIGNAL(activated(int)), this, SLOT(socketRead(int)));
|
|
|
|
command = new Command{fd, p_command, channel, readNotifier};
|
|
executing = true;
|
|
}
|
|
}
|
|
|
|
|
|
bool QSshSocket::isConnected()
|
|
{
|
|
return m_connected;
|
|
}
|
|
|
|
bool QSshSocket::isLoggedIn()
|
|
{
|
|
return loggedIn;
|
|
}
|
|
|
|
bool QSshSocket::isExecuting()
|
|
{
|
|
return executing;
|
|
}
|
|
|
|
|
|
void QSshSocket::socketRead(int ptr)
|
|
{
|
|
command->notifier->setEnabled(false);
|
|
|
|
char* buffer = new char[1048576];
|
|
|
|
int totalBytes = 0;
|
|
int newBytes = 0;
|
|
do {
|
|
newBytes = ssh_channel_read_nonblocking(command->channel, &buffer[totalBytes], 1048576 - totalBytes, 0);
|
|
|
|
if (newBytes > 0) {
|
|
totalBytes += newBytes;
|
|
}
|
|
|
|
} while (newBytes > 0);
|
|
|
|
if (newBytes == SSH_ERROR) {
|
|
emit error(ReadError);
|
|
destroyCommand();
|
|
} else if (ssh_channel_is_eof(command->channel) != 0) {
|
|
command->notifier->setEnabled(true);
|
|
QString response = QString::fromUtf8(buffer, totalBytes);
|
|
emit commandData(response);
|
|
emit endOfFile();
|
|
destroyCommand();
|
|
} else {
|
|
command->notifier->setEnabled(true);
|
|
QString response = QString::fromUtf8(buffer, totalBytes);
|
|
emit commandData(response);
|
|
}
|
|
|
|
delete[] buffer;
|
|
}
|
|
|
|
void QSshSocket::destroyCommand()
|
|
{
|
|
delete command->notifier;
|
|
ssh_channel_send_eof(command->channel);
|
|
ssh_channel_close(command->channel);
|
|
ssh_channel_free(command->channel);
|
|
delete command;
|
|
executing = false;
|
|
}
|
|
|
|
void QSshSocket::lib_ssh_init()
|
|
{
|
|
ssh_threads_set_callbacks(ssh_threads_get_pthread());
|
|
ssh_init();
|
|
}
|
|
|
|
void QSshSocket::interrupt()
|
|
{
|
|
if (executing) {
|
|
ssh_channel_request_send_signal(command->channel, "INT");
|
|
}
|
|
}
|
|
|