initial commit
This commit is contained in:
commit
4b60ece582
327 changed files with 28286 additions and 0 deletions
23
lib/wSsh/CMakeLists.txt
Normal file
23
lib/wSsh/CMakeLists.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(wSsh)
|
||||
|
||||
find_package(Qt5Core REQUIRED)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
set(HEADERS
|
||||
sshsocket.h
|
||||
qsshsocket.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
sshsocket.cpp
|
||||
qsshsocket.cpp
|
||||
)
|
||||
|
||||
add_library(wSsh ${HEADERS} ${SOURCES})
|
||||
|
||||
target_link_libraries(wSsh Qt5::Core)
|
||||
target_link_libraries(wSsh ssh)
|
||||
target_link_libraries(wSsh ssh_threads)
|
186
lib/wSsh/qsshsocket.cpp
Normal file
186
lib/wSsh/qsshsocket.cpp
Normal file
|
@ -0,0 +1,186 @@
|
|||
#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");
|
||||
}
|
||||
}
|
||||
|
81
lib/wSsh/qsshsocket.h
Normal file
81
lib/wSsh/qsshsocket.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
#ifndef QSSHSOCKET_H
|
||||
#define QSSHSOCKET_H
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QSocketNotifier>
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QMap>
|
||||
|
||||
class QSshSocket: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
enum SshError
|
||||
{
|
||||
SocketError,
|
||||
SessionCreationError,
|
||||
ChannelCreationError,
|
||||
ReadError,
|
||||
WriteError,
|
||||
PasswordAuthenticationFailedError
|
||||
};
|
||||
|
||||
explicit QSshSocket(QObject* parent = 0);
|
||||
~QSshSocket();
|
||||
|
||||
bool isLoggedIn();
|
||||
bool isConnected();
|
||||
bool isExecuting();
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
void disconnected();
|
||||
void error(QSshSocket::SshError error);
|
||||
void loginSuccessful();
|
||||
void commandData(QString data);
|
||||
void endOfFile();
|
||||
|
||||
public slots:
|
||||
void connect(QString host, int port = 22);
|
||||
void disconnect();
|
||||
void executeCommand(QString command);
|
||||
void login(QString user, QString password);
|
||||
void interrupt();
|
||||
|
||||
private:
|
||||
struct Command
|
||||
{
|
||||
qintptr id;
|
||||
QString command;
|
||||
ssh_channel channel;
|
||||
QSocketNotifier* notifier;
|
||||
};
|
||||
|
||||
bool loggedIn;
|
||||
ssh_session session;
|
||||
bool m_connected;
|
||||
bool executing;
|
||||
Command* command;
|
||||
static bool lib_ssh_inited;
|
||||
static void lib_ssh_init();
|
||||
|
||||
private:
|
||||
void destroyCommand();
|
||||
|
||||
private slots:
|
||||
void socketRead(int ptr);
|
||||
};
|
||||
|
||||
|
||||
Q_DECLARE_METATYPE(QSshSocket::SshError)
|
||||
|
||||
|
||||
#endif // QSSHSOCKET_H
|
195
lib/wSsh/sshsocket.cpp
Normal file
195
lib/wSsh/sshsocket.cpp
Normal file
|
@ -0,0 +1,195 @@
|
|||
#include "sshsocket.h"
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
W::SshSocket::SshSocket(const QString& p_login, const QString& p_password, QObject* parent):
|
||||
QObject(parent),
|
||||
socket(new QSshSocket()),
|
||||
thread(new QThread()),
|
||||
login(p_login),
|
||||
password(p_password),
|
||||
state(Disconnected)
|
||||
{
|
||||
connect(socket, SIGNAL(connected()), this, SLOT(onSocketConnected()));
|
||||
connect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
|
||||
connect(socket, SIGNAL(loginSuccessful()), this, SLOT(onSocketLoggedIn()));
|
||||
connect(socket, SIGNAL(error(QSshSocket::SshError)), this, SLOT(onSocketError(QSshSocket::SshError)));
|
||||
connect(socket, SIGNAL(commandData(QString)), this, SLOT(onSocketCommandData(QString)));
|
||||
connect(socket, SIGNAL(endOfFile()), this, SLOT(onSocketEOF()));
|
||||
|
||||
socket->moveToThread(thread);
|
||||
}
|
||||
|
||||
W::SshSocket::~SshSocket()
|
||||
{
|
||||
if (state != Disconnected) {
|
||||
if (state == Disconnecting) {
|
||||
onSocketDisconnected();
|
||||
} else {
|
||||
qDebug("Socket wasn't closed, terminating the inner thread");
|
||||
thread->terminate();
|
||||
}
|
||||
}
|
||||
socket->deleteLater();
|
||||
thread->deleteLater();
|
||||
//TODO;
|
||||
}
|
||||
|
||||
void W::SshSocket::open(const QString& address, uint16_t port)
|
||||
{
|
||||
if (state == Disconnected) {
|
||||
state = Connecting;
|
||||
thread->start();
|
||||
QMetaObject::invokeMethod(socket, "connect", Qt::QueuedConnection, Q_ARG(QString, address), Q_ARG(int, port));
|
||||
} else {
|
||||
//TODO;
|
||||
}
|
||||
}
|
||||
|
||||
void W::SshSocket::onSocketConnected()
|
||||
{
|
||||
if (state == Connecting) {
|
||||
state = Connected;
|
||||
authorize();
|
||||
} else {
|
||||
//TODO;
|
||||
}
|
||||
}
|
||||
|
||||
void W::SshSocket::authorize()
|
||||
{
|
||||
if (state == Connected) {
|
||||
state = Authorizing;
|
||||
QMetaObject::invokeMethod(socket, "login", Qt::QueuedConnection, Q_ARG(QString, login), Q_ARG(QString, password));
|
||||
} else {
|
||||
//TODO;
|
||||
}
|
||||
}
|
||||
|
||||
void W::SshSocket::onSocketLoggedIn()
|
||||
{
|
||||
if (state == Authorizing) {
|
||||
state = Authorized;
|
||||
emit opened();
|
||||
}
|
||||
}
|
||||
|
||||
void W::SshSocket::close()
|
||||
{
|
||||
switch (state) {
|
||||
case Disconnected:
|
||||
//TODO;
|
||||
break;
|
||||
case Connecting:
|
||||
case Connected:
|
||||
case Authorizing:
|
||||
case Authorized:
|
||||
QMetaObject::invokeMethod(socket, "disconnect", Qt::QueuedConnection);
|
||||
state = Disconnecting;
|
||||
break;
|
||||
case Disconnecting:
|
||||
//TODO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void W::SshSocket::onSocketDisconnected()
|
||||
{
|
||||
if (state == Disconnecting) {
|
||||
thread->quit();
|
||||
thread->wait();
|
||||
state = Disconnected;
|
||||
emit closed();
|
||||
} else {
|
||||
//TODO;
|
||||
}
|
||||
}
|
||||
|
||||
void W::SshSocket::execute(const QString& command)
|
||||
{
|
||||
if (state == Authorized) {
|
||||
QMetaObject::invokeMethod(socket, "executeCommand", Qt::QueuedConnection, Q_ARG(QString, command));
|
||||
} else {
|
||||
//TODO;
|
||||
}
|
||||
}
|
||||
|
||||
void W::SshSocket::onSocketCommandData(QString p_data)
|
||||
{
|
||||
if (state == Authorized) {
|
||||
emit data(p_data);
|
||||
}
|
||||
}
|
||||
|
||||
void W::SshSocket::onSocketError(QSshSocket::SshError p_error)
|
||||
{
|
||||
QString msg;
|
||||
Error errCode;
|
||||
switch (p_error) {
|
||||
case QSshSocket::SocketError:
|
||||
msg = "There was a trouble creating a socket. Looks like you have problems with internet connectiion";
|
||||
errCode = SocketError;
|
||||
break;
|
||||
case QSshSocket::SessionCreationError:
|
||||
msg = "No route to the remote host";
|
||||
errCode = SessionCreationError;
|
||||
if (state == Connecting) {
|
||||
state = Disconnected;
|
||||
}
|
||||
break;
|
||||
case QSshSocket::ChannelCreationError:
|
||||
msg = "An ssh channel could not be created";
|
||||
errCode = ChannelCreationError;
|
||||
break;
|
||||
case QSshSocket::ReadError:
|
||||
msg = "There was an error reading the socket";
|
||||
errCode = ReadError;
|
||||
break;
|
||||
case QSshSocket::WriteError:
|
||||
msg = "There was an error writing to the socket";
|
||||
errCode = WriteError;
|
||||
break;
|
||||
case QSshSocket::PasswordAuthenticationFailedError:
|
||||
msg = "The credentials of a user on the remote host could not be authenticated";
|
||||
errCode = PasswordAuthenticationError;
|
||||
if (state == Authorizing) {
|
||||
state = Connected;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
emit error(errCode, msg);
|
||||
}
|
||||
|
||||
void W::SshSocket::onSocketEOF()
|
||||
{
|
||||
emit finished();
|
||||
}
|
||||
|
||||
bool W::SshSocket::isReady() const
|
||||
{
|
||||
return state == Authorized;
|
||||
}
|
||||
|
||||
void W::SshSocket::interrupt()
|
||||
{
|
||||
if (state == Authorized) {
|
||||
QMetaObject::invokeMethod(socket, "interrupt", Qt::QueuedConnection);
|
||||
} else {
|
||||
//TODO;
|
||||
}
|
||||
}
|
||||
|
||||
void W::SshSocket::setLogin(const QString& lng)
|
||||
{
|
||||
login = lng;
|
||||
}
|
||||
|
||||
void W::SshSocket::setPassword(const QString& pass)
|
||||
{
|
||||
password = pass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
69
lib/wSsh/sshsocket.h
Normal file
69
lib/wSsh/sshsocket.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#ifndef SSHSOCKET_H
|
||||
#define SSHSOCKET_H
|
||||
|
||||
#include "qsshsocket.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
namespace W {
|
||||
class SshSocket : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SshSocket(const QString& p_login, const QString& p_password, QObject* parent = 0);
|
||||
~SshSocket();
|
||||
|
||||
enum Error {
|
||||
SocketError,
|
||||
SessionCreationError,
|
||||
ChannelCreationError,
|
||||
ReadError,
|
||||
WriteError,
|
||||
PasswordAuthenticationError
|
||||
};
|
||||
|
||||
void open(const QString& address, uint16_t port = 22);
|
||||
void close();
|
||||
void execute(const QString& command);
|
||||
void interrupt();
|
||||
bool isReady() const;
|
||||
void setLogin(const QString& lng);
|
||||
void setPassword(const QString& pass);
|
||||
|
||||
signals:
|
||||
void opened();
|
||||
void closed();
|
||||
void error(W::SshSocket::Error code, const QString& message);
|
||||
void data(const QString& data);
|
||||
void finished();
|
||||
|
||||
private:
|
||||
void authorize();
|
||||
enum State {
|
||||
Disconnected,
|
||||
Connecting,
|
||||
Connected,
|
||||
Authorizing,
|
||||
Authorized,
|
||||
Disconnecting
|
||||
};
|
||||
|
||||
QSshSocket* socket;
|
||||
QThread* thread;
|
||||
QString login;
|
||||
QString password;
|
||||
State state;
|
||||
|
||||
private slots:
|
||||
void onSocketConnected();
|
||||
void onSocketDisconnected();
|
||||
void onSocketLoggedIn();
|
||||
void onSocketError(QSshSocket::SshError p_error);
|
||||
void onSocketCommandData(QString p_data);
|
||||
void onSocketEOF();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SSHSOCKET_H
|
Loading…
Add table
Add a link
Reference in a new issue