radio/lib/wSsh/qsshsocket.cpp

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");
}
}