diff --git a/src/libs/3rdparty/net7ssh/src/ne7ssh.cpp b/src/libs/3rdparty/net7ssh/src/ne7ssh.cpp index 08fbe52a1be3537cdc70a6534eb7fa43249e1206..fee569089a397026a18b31ddb45a3aeb06beb638 100644 --- a/src/libs/3rdparty/net7ssh/src/ne7ssh.cpp +++ b/src/libs/3rdparty/net7ssh/src/ne7ssh.cpp @@ -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)); diff --git a/src/libs/3rdparty/net7ssh/src/ne7ssh.h b/src/libs/3rdparty/net7ssh/src/ne7ssh.h index 853d8b08ffe5fca7dceda626138b3b5618ce570f..57cc281b90285ab309504c416d89e532ed71f70c 100644 --- a/src/libs/3rdparty/net7ssh/src/ne7ssh.h +++ b/src/libs/3rdparty/net7ssh/src/ne7ssh.h @@ -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. diff --git a/src/libs/3rdparty/net7ssh/src/ne7ssh_connection.cpp b/src/libs/3rdparty/net7ssh/src/ne7ssh_connection.cpp index 569eaa44508a9c4dc3af49a194ef3115c423567f..7361dba4d80c183b98b309cdf372ed97e79edc41 100644 --- a/src/libs/3rdparty/net7ssh/src/ne7ssh_connection.cpp +++ b/src/libs/3rdparty/net7ssh/src/ne7ssh_connection.cpp @@ -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) diff --git a/src/libs/3rdparty/net7ssh/src/ne7ssh_connection.h b/src/libs/3rdparty/net7ssh/src/ne7ssh_connection.h index a201c19262f564252f8bff415a876fdda0faa240..182b48294fcf4293b3594f6febf9ad7d653d9f0c 100644 --- a/src/libs/3rdparty/net7ssh/src/ne7ssh_connection.h +++ b/src/libs/3rdparty/net7ssh/src/ne7ssh_connection.h @@ -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. diff --git a/src/plugins/coreplugin/ssh/sshconnection.cpp b/src/plugins/coreplugin/ssh/sshconnection.cpp index 4b3f1741c2d7b9a97c3bfb611b7ecb43a6061e5b..4f5b54f2f3454f23d5fd024f4693d85842f2d9d1 100644 --- a/src/plugins/coreplugin/ssh/sshconnection.cpp +++ b/src/plugins/coreplugin/ssh/sshconnection.cpp @@ -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)) {