Commit 1b7ed58c authored by ck's avatar ck
Browse files

SSH: Remove busy loop.

parent 26e9569a
......@@ -293,13 +293,15 @@ void *ne7ssh::selectThread (void *initData)
return 0;
}
int ne7ssh::connectWithPassword (const char *host, const int port, const char* username, const char* password, bool shell, const int timeout)
int ne7ssh::connectWithPassword (const char *host, const int port,
const char* username, const char* password, bool shell, const int timeout,
void (*callbackFunc)(void *), void *callbackArg)
{
int channel;
uint32 currentRecord, z;
uint32 channelID;
ne7ssh_connection* con = new ne7ssh_connection ();
ne7ssh_connection* con = new ne7ssh_connection (callbackFunc, callbackArg);
if (!lock()) return -1;
if (!conCount) connections = (ne7ssh_connection**) malloc (sizeof (ne7ssh_connection*));
......@@ -344,13 +346,15 @@ int ne7ssh::connectWithPassword (const char *host, const int port, const char* u
return channel;
}
int ne7ssh::connectWithKey (const char* host, const int port, const char* username, const char* privKeyFileName, bool shell, const int timeout)
int ne7ssh::connectWithKey (const char* host, const int port,
const char* username, const char* privKeyFileName, bool shell,
const int timeout, void (*callbackFunc)(void *), void *callbackArg)
{
int channel;
uint32 currentRecord, z;
uint32 channelID;
ne7ssh_connection* con = new ne7ssh_connection ();
ne7ssh_connection* con = new ne7ssh_connection (callbackFunc, callbackArg);
if (!lock()) return -1;
if (!conCount) connections = (ne7ssh_connection**) malloc (sizeof (ne7ssh_connection*) * (conCount + 1));
else connections = (ne7ssh_connection**) realloc (connections, sizeof (ne7ssh_connection*) * (conCount + 1));
......
......@@ -175,7 +175,9 @@ class SSH_EXPORT ne7ssh
* @param timeout Timeout for the connection procedure, in seconds.
* @return Returns newly assigned channel ID, or -1 if connection failed.
*/
int connectWithPassword (const char* host, const int port, const char* username, const char* password, bool shell = true, const int timeout = 0);
int connectWithPassword (const char* host, const int port, const char* username,
const char* password, bool shell = true, const int timeout = 0,
void (*callbackFunc)(void *) = 0, void *callbackArg = 0);
/**
* Connect to remote host using SSH2 protocol, with publickey authentication.
......@@ -189,7 +191,9 @@ class SSH_EXPORT ne7ssh
* @param timeout Timeout for the connection procedure, in seconds.
* @return Returns newly assigned channel ID, or -1 if connection failed.
*/
int connectWithKey (const char* host, const int port, const char* username, const char* privKeyFileName, bool shell = true, const int timeout = 0);
int connectWithKey (const char* host, const int port, const char* username,
const char* privKeyFileName, bool shell = true, const int timeout = 0,
void (*callbackFunc)(void *) = 0, void *callbackArg = 0);
/**
* Retrieves a pointer to all current connections.
......
......@@ -20,7 +20,10 @@
using namespace Botan;
ne7ssh_connection::ne7ssh_connection() : sock (-1), thisChannel(0), sftp(0), connected(false), cmdRunning(false), cmdClosed(false)
ne7ssh_connection::ne7ssh_connection(void (*callbackFunc)(void *),
void *callbackArg)
: sock (-1), thisChannel(0), sftp(0), connected(false), cmdRunning(false),
cmdClosed(false), callbackFunc(callbackFunc), callbackArg(callbackArg)
{
session = new ne7ssh_session();
crypto = new ne7ssh_crypt(session);
......@@ -285,6 +288,8 @@ bool ne7ssh_connection::sendLocalVersion ()
void ne7ssh_connection::handleData ()
{
channel->receive();
if (callbackFunc && getReceived().size() > 0)
callbackFunc(callbackArg);
}
void ne7ssh_connection::sendData (const char* data)
......
......@@ -46,6 +46,8 @@ class ne7ssh_connection
bool cmdRunning;
bool cmdClosed;
void (*callbackFunc)(void *);
void *callbackArg;
/**
* Checks if remote side is returning a correctly formated SSH version string, and makes sure that version 2 of SSH protocol is supported by the remote side.
......@@ -88,7 +90,7 @@ class ne7ssh_connection
/**
* ne7ssh_connection class constructor.
*/
ne7ssh_connection();
ne7ssh_connection(void (*callbackFunc)(void *) = 0, void *callbackArg = 0);
/**
* ne7ssh_connection class destructor.
......
......@@ -46,7 +46,9 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QMutex>
#include <QtCore/QThread>
#include <QtCore/QWaitCondition>
#include <ne7ssh.h>
......@@ -71,14 +73,14 @@ public:
quit();
}
bool start(bool shell)
bool start(bool shell, void (*callbackFunc)(void *), void *callbackArg)
{
Q_ASSERT(m_channel == -1);
try {
const QString *authString;
int (ne7ssh::*connFunc)(const char *, int, const char *,
const char *, bool, int);
const char *, bool, int, void (*)(void *), void *);
if (m_server.authType == SshServerInfo::AuthByPwd) {
authString = &m_server.pwd;
connFunc = &ne7ssh::connectWithPassword;
......@@ -87,14 +89,14 @@ public:
connFunc = &ne7ssh::connectWithKey;
}
m_channel = (ssh.data()->*connFunc)(m_server.host.toLatin1(),
m_server.port, m_server.uname.toAscii(),
authString->toLatin1(), shell, m_server.timeout);
m_server.port, m_server.uname.toAscii(), authString->toLatin1(),
shell, m_server.timeout, callbackFunc, callbackArg);
if (m_channel == -1) {
setError(tr("Could not connect to host."), false);
return false;
}
} catch (const std::exception &e) {
// Should in theory not be necessary, but Net7 leaks Botan exceptions.
// Should in theory not be necessary, but Net7 leaks Botan exceptions.
setError(tr("Error in cryptography backend: %1")
.arg(QLatin1String(e.what())), false);
return false;
......@@ -133,7 +135,6 @@ private:
int m_channel;
};
char *alloc(size_t n)
{
return new char[n];
......@@ -165,7 +166,8 @@ class ConnectionOutputReader : public QThread
{
public:
ConnectionOutputReader(InteractiveSshConnection *parent)
: QThread(parent), m_conn(parent), m_stopRequested(false)
: QThread(parent), m_conn(parent), m_stopRequested(false),
m_dataAvailable(false)
{}
~ConnectionOutputReader()
......@@ -174,35 +176,63 @@ public:
wait();
}
// TODO: Use a wakeup mechanism here as soon as we no longer poll for output
// from Net7.
void stop()
{
m_mutex.lock();
m_stopRequested = true;
m_waitCond.wakeOne();
m_mutex.unlock();
}
void dataAvailable()
{
m_mutex.lock();
m_dataAvailable = true;
m_waitCond.wakeOne();
m_mutex.unlock();
}
private:
virtual void run()
{
while (!m_stopRequested) {
while (true) {
m_mutex.lock();
if (m_stopRequested) {
m_mutex.unlock();
return;
}
const int channel = m_conn->d->conn.channel();
if (channel != -1) {
QScopedPointer<char, QScopedPointerArrayDeleter<char> >
if (!m_dataAvailable || channel == -1)
m_waitCond.wait(&m_mutex);
m_dataAvailable = false;
m_mutex.unlock();
QScopedPointer<char, QScopedPointerArrayDeleter<char> >
output(m_conn->d->conn.ssh->readAndReset(channel, alloc));
if (output)
emit m_conn->remoteOutput(QByteArray(output.data()));
}
usleep(100000); // TODO: Hack Net7 to enable wait() functionality.
if (output)
emit m_conn->remoteOutput(QByteArray(output.data()));
}
}
InteractiveSshConnection *m_conn;
bool m_stopRequested;
bool m_dataAvailable;
QMutex m_mutex;
QWaitCondition m_waitCond;
};
} // namespace Internal
namespace {
void wakeupReader(void *opaqueReader)
{
static_cast<Internal::ConnectionOutputReader*>(opaqueReader)->dataAvailable();
}
} // Anonymous namespace
InteractiveSshConnection::InteractiveSshConnection(const SshServerInfo &server)
: d(new Internal::InteractiveSshConnectionPrivate(server))
{
......@@ -218,7 +248,7 @@ InteractiveSshConnection::~InteractiveSshConnection()
bool InteractiveSshConnection::start()
{
if (!d->conn.start(true))
if (!d->conn.start(true, wakeupReader, d->outputReader))
return false;
d->outputReader->start();
......@@ -283,7 +313,7 @@ SftpConnection::~SftpConnection()
bool SftpConnection::start()
{
if (!d->conn.start(false))
if (!d->conn.start(false, 0, 0))
return false;
if (!d->conn.ssh->initSftp(d->sftp, d->conn.channel())
|| !d->sftp.setTimeout(d->conn.server().timeout)) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment