initial commit

This commit is contained in:
Blue 2018-08-05 00:46:25 +03:00 committed by Юрий Губич
commit 4b60ece582
327 changed files with 28286 additions and 0 deletions

23
lib/wSsh/CMakeLists.txt Normal file
View 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
View 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
View 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
View 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
View 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