aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/ssh
diff options
context:
space:
mode:
authorChristian Kandeler <[email protected]>2012-06-19 13:03:48 +0200
committerChristian Kandeler <[email protected]>2012-08-28 15:12:04 +0200
commitedcf76613b82d4b04ad9d0797515dc42d983eb68 (patch)
tree5229324612e8489ebe70e304641ea0781893dfdd /src/libs/ssh
parenta57b4cf93efcb3fe30623566115b29e925367f7f (diff)
SSH: Implement tunneling.
This is the "direct-tcpip" port forwarding specified in RFC 4254. Change-Id: I1ffa2e923b4479c7211b1b4304e66895b565fb64 Reviewed-by: hjk <[email protected]> Reviewed-by: Christian Kandeler <[email protected]>
Diffstat (limited to 'src/libs/ssh')
-rw-r--r--src/libs/ssh/sftpchannel_p.h11
-rw-r--r--src/libs/ssh/ssh.pro7
-rw-r--r--src/libs/ssh/ssh.qbs1
-rw-r--r--src/libs/ssh/sshchannel.cpp33
-rw-r--r--src/libs/ssh/sshchannel_p.h20
-rw-r--r--src/libs/ssh/sshchannelmanager.cpp11
-rw-r--r--src/libs/ssh/sshchannelmanager_p.h7
-rw-r--r--src/libs/ssh/sshconnection.cpp13
-rw-r--r--src/libs/ssh/sshconnection.h2
-rw-r--r--src/libs/ssh/sshconnection_p.h5
-rw-r--r--src/libs/ssh/sshdirecttcpiptunnel.cpp194
-rw-r--r--src/libs/ssh/sshdirecttcpiptunnel.h90
-rw-r--r--src/libs/ssh/sshdirecttcpiptunnel_p.h84
-rw-r--r--src/libs/ssh/sshoutgoingpacket.cpp11
-rw-r--r--src/libs/ssh/sshoutgoingpacket_p.h3
-rw-r--r--src/libs/ssh/sshremoteprocess.cpp1
-rw-r--r--src/libs/ssh/sshremoteprocess_p.h13
-rw-r--r--src/libs/ssh/sshsendfacility.cpp9
-rw-r--r--src/libs/ssh/sshsendfacility_p.h3
19 files changed, 477 insertions, 41 deletions
diff --git a/src/libs/ssh/sftpchannel_p.h b/src/libs/ssh/sftpchannel_p.h
index e3979312b2d..9597e28e2d9 100644
--- a/src/libs/ssh/sftpchannel_p.h
+++ b/src/libs/ssh/sftpchannel_p.h
@@ -49,14 +49,8 @@ class SftpChannelPrivate : public AbstractSshChannel
Q_OBJECT
friend class QSsh::SftpChannel;
public:
-
enum SftpState { Inactive, SubsystemRequested, InitSent, Initialized };
- virtual void handleChannelSuccess();
- virtual void handleChannelFailure();
-
- virtual void closeHook();
-
signals:
void initialized();
void initializationFailed(const QString &reason);
@@ -72,6 +66,9 @@ private:
SftpChannel *sftp);
SftpJobId createJob(const AbstractSftpOperation::Ptr &job);
+ virtual void handleChannelSuccess();
+ virtual void handleChannelFailure();
+
virtual void handleOpenSuccessInternal();
virtual void handleOpenFailureInternal(const QString &reason);
virtual void handleChannelDataInternal(const QByteArray &data);
@@ -80,6 +77,8 @@ private:
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus);
virtual void handleExitSignal(const SshChannelExitSignal &signal);
+ virtual void closeHook();
+
void handleCurrentPacket();
void handleServerVersion();
void handleHandle();
diff --git a/src/libs/ssh/ssh.pro b/src/libs/ssh/ssh.pro
index 2df5b0430b0..3b4ce049627 100644
--- a/src/libs/ssh/ssh.pro
+++ b/src/libs/ssh/ssh.pro
@@ -29,7 +29,8 @@ SOURCES = $$PWD/sshsendfacility.cpp \
$$PWD/sshconnectionmanager.cpp \
$$PWD/sshkeypasswordretriever.cpp \
$$PWD/sftpfilesystemmodel.cpp \
- $$PWD/sshkeycreationdialog.cpp
+ $$PWD/sshkeycreationdialog.cpp \
+ $$PWD/sshdirecttcpiptunnel.cpp
HEADERS = $$PWD/sshsendfacility_p.h \
$$PWD/sshremoteprocess.h \
@@ -62,6 +63,8 @@ HEADERS = $$PWD/sshsendfacility_p.h \
$$PWD/sshkeypasswordretriever_p.h \
$$PWD/sftpfilesystemmodel.h \
$$PWD/sshkeycreationdialog.h \
- $$PWD/ssh_global.h
+ $$PWD/ssh_global.h \
+ $$PWD/sshdirecttcpiptunnel_p.h \
+ $$PWD/sshdirecttcpiptunnel.h
FORMS = $$PWD/sshkeycreationdialog.ui
diff --git a/src/libs/ssh/ssh.qbs b/src/libs/ssh/ssh.qbs
index cb8603327c3..42b84abcc5c 100644
--- a/src/libs/ssh/ssh.qbs
+++ b/src/libs/ssh/ssh.qbs
@@ -35,6 +35,7 @@ QtcLibrary {
"sshpacket.cpp", "sshpacket_p.h",
"sshpacketparser.cpp", "sshpacketparser_p.h",
"sshremoteprocess.cpp", "sshremoteprocess.h", "sshremoteprocess_p.h",
+ "sshdirecttcpiptunnel.h", "sshdirecttcpiptunnel_p.h", "sshdirecttcpiptunnel.cpp",
"sshremoteprocessrunner.cpp", "sshremoteprocessrunner.h",
"sshsendfacility.cpp", "sshsendfacility_p.h",
"sshkeypasswordretriever.cpp",
diff --git a/src/libs/ssh/sshchannel.cpp b/src/libs/ssh/sshchannel.cpp
index f513f5121f3..a2dfe78b5cb 100644
--- a/src/libs/ssh/sshchannel.cpp
+++ b/src/libs/ssh/sshchannel.cpp
@@ -40,18 +40,14 @@
namespace QSsh {
namespace Internal {
-namespace {
- const quint32 MinMaxPacketSize = 32768;
- const quint32 MaxPacketSize = 16 * 1024 * 1024;
- const quint32 InitialWindowSize = MaxPacketSize;
- const quint32 NoChannel = 0xffffffffu;
-} // anonymous namespace
+const quint32 MinMaxPacketSize = 32768;
+const quint32 NoChannel = 0xffffffffu;
AbstractSshChannel::AbstractSshChannel(quint32 channelId,
SshSendFacility &sendFacility)
: m_sendFacility(sendFacility), m_timeoutTimer(new QTimer(this)),
m_localChannel(channelId), m_remoteChannel(NoChannel),
- m_localWindowSize(InitialWindowSize), m_remoteWindowSize(0),
+ m_localWindowSize(initialWindowSize()), m_remoteWindowSize(0),
m_state(Inactive)
{
m_timeoutTimer->setSingleShot(true);
@@ -77,8 +73,7 @@ void AbstractSshChannel::requestSessionStart()
// with our cryptography stuff, it would have hit us before, on
// establishing the connection.
try {
- m_sendFacility.sendSessionPacket(m_localChannel, InitialWindowSize,
- MaxPacketSize);
+ m_sendFacility.sendSessionPacket(m_localChannel, initialWindowSize(), maxPacketSize());
setChannelState(SessionRequested);
m_timeoutTimer->start(ReplyTimeout);
} catch (Botan::Exception &e) {
@@ -98,6 +93,16 @@ void AbstractSshChannel::sendData(const QByteArray &data)
}
}
+quint32 AbstractSshChannel::initialWindowSize()
+{
+ return maxPacketSize();
+}
+
+quint32 AbstractSshChannel::maxPacketSize()
+{
+ return 16 * 1024 * 1024;
+}
+
void AbstractSshChannel::handleWindowAdjust(quint32 bytesToAdd)
{
checkChannelActive();
@@ -174,6 +179,7 @@ void AbstractSshChannel::handleChannelEof()
"Unexpected SSH_MSG_CHANNEL_EOF message.");
}
m_localWindowSize = 0;
+ emit eof();
}
void AbstractSshChannel::handleChannelClose()
@@ -224,10 +230,9 @@ int AbstractSshChannel::handleChannelOrExtendedChannelData(const QByteArray &dat
qWarning("Misbehaving server does not respect local window, clipping.");
m_localWindowSize -= bytesToDeliver;
- if (m_localWindowSize < MaxPacketSize) {
- m_localWindowSize += MaxPacketSize;
- m_sendFacility.sendWindowAdjustPacket(m_remoteChannel,
- MaxPacketSize);
+ if (m_localWindowSize < maxPacketSize()) {
+ m_localWindowSize += maxPacketSize();
+ m_sendFacility.sendWindowAdjustPacket(m_remoteChannel, maxPacketSize());
}
return bytesToDeliver;
}
@@ -256,7 +261,7 @@ void AbstractSshChannel::checkChannelActive()
quint32 AbstractSshChannel::maxDataSize() const
{
- return qMin(m_localWindowSize, MaxPacketSize);
+ return qMin(m_localWindowSize, maxPacketSize());
}
} // namespace Internal
diff --git a/src/libs/ssh/sshchannel_p.h b/src/libs/ssh/sshchannel_p.h
index d1a84e15632..5898bc44b18 100644
--- a/src/libs/ssh/sshchannel_p.h
+++ b/src/libs/ssh/sshchannel_p.h
@@ -53,17 +53,12 @@ public:
Inactive, SessionRequested, SessionEstablished, CloseRequested, Closed
};
- ChannelState channelState() const { return m_state; }
- void setChannelState(ChannelState state);
-
quint32 localChannelId() const { return m_localChannel; }
quint32 remoteChannel() const { return m_remoteChannel; }
virtual void handleChannelSuccess() = 0;
virtual void handleChannelFailure() = 0;
- virtual void closeHook() = 0;
-
void handleOpenSuccess(quint32 remoteChannelId, quint32 remoteWindowSize,
quint32 remoteMaxPacketSize);
void handleOpenFailure(const QString &reason);
@@ -74,8 +69,6 @@ public:
void handleChannelExtendedData(quint32 type, const QByteArray &data);
void handleChannelRequest(const SshIncomingPacket &packet);
- void requestSessionStart();
- void sendData(const QByteArray &data);
void closeChannel();
virtual ~AbstractSshChannel();
@@ -84,10 +77,20 @@ public:
signals:
void timeout();
+ void eof();
protected:
AbstractSshChannel(quint32 channelId, SshSendFacility &sendFacility);
+ void setChannelState(ChannelState state);
+ ChannelState channelState() const { return m_state; }
+
+ void requestSessionStart();
+ void sendData(const QByteArray &data);
+
+ static quint32 initialWindowSize();
+ static quint32 maxPacketSize();
+
quint32 maxDataSize() const;
void checkChannelActive();
@@ -103,7 +106,8 @@ private:
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus) = 0;
virtual void handleExitSignal(const SshChannelExitSignal &signal) = 0;
- void setState(ChannelState newState);
+ virtual void closeHook() = 0;
+
void flushSendBuffer();
int handleChannelOrExtendedChannelData(const QByteArray &data);
diff --git a/src/libs/ssh/sshchannelmanager.cpp b/src/libs/ssh/sshchannelmanager.cpp
index 792963702e0..5d7f35f91d8 100644
--- a/src/libs/ssh/sshchannelmanager.cpp
+++ b/src/libs/ssh/sshchannelmanager.cpp
@@ -32,6 +32,8 @@
#include "sftpchannel.h"
#include "sftpchannel_p.h"
+#include "sshdirecttcpiptunnel.h"
+#include "sshdirecttcpiptunnel_p.h"
#include "sshincomingpacket_p.h"
#include "sshremoteprocess.h"
#include "sshremoteprocess_p.h"
@@ -168,6 +170,15 @@ QSsh::SftpChannel::Ptr SshChannelManager::createSftpChannel()
return sftp;
}
+SshDirectTcpIpTunnel::Ptr SshChannelManager::createTunnel(quint16 remotePort,
+ const SshConnectionInfo &connectionInfo)
+{
+ SshDirectTcpIpTunnel::Ptr tunnel(new SshDirectTcpIpTunnel(m_nextLocalChannelId++, remotePort,
+ connectionInfo, m_sendFacility));
+ insertChannel(tunnel->d, tunnel);
+ return tunnel;
+}
+
void SshChannelManager::insertChannel(AbstractSshChannel *priv,
const QSharedPointer<QObject> &pub)
{
diff --git a/src/libs/ssh/sshchannelmanager_p.h b/src/libs/ssh/sshchannelmanager_p.h
index 16626eddb18..28f7266debd 100644
--- a/src/libs/ssh/sshchannelmanager_p.h
+++ b/src/libs/ssh/sshchannelmanager_p.h
@@ -36,8 +36,9 @@
#include <QSharedPointer>
namespace QSsh {
-
class SftpChannel;
+class SshConnectionInfo;
+class SshDirectTcpIpTunnel;
class SshRemoteProcess;
namespace Internal {
@@ -55,8 +56,10 @@ public:
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel();
- int channelCount() const;
+ QSharedPointer<SshDirectTcpIpTunnel> createTunnel(quint16 remotePort,
+ const SshConnectionInfo &connectionInfo);
+ int channelCount() const;
enum CloseAllMode { CloseAllRegular, CloseAllAndReset };
int closeAllChannels(CloseAllMode mode);
diff --git a/src/libs/ssh/sshconnection.cpp b/src/libs/ssh/sshconnection.cpp
index ebf233d3b6d..8dfd475dd5b 100644
--- a/src/libs/ssh/sshconnection.cpp
+++ b/src/libs/ssh/sshconnection.cpp
@@ -35,8 +35,10 @@
#include "sshcapabilities_p.h"
#include "sshchannelmanager_p.h"
#include "sshcryptofacility_p.h"
+#include "sshdirecttcpiptunnel.h"
#include "sshexception_p.h"
#include "sshkeyexchange_p.h"
+#include "sshremoteprocess.h"
#include <botan/botan.h>
@@ -191,6 +193,12 @@ QSharedPointer<SftpChannel> SshConnection::createSftpChannel()
return d->createSftpChannel();
}
+SshDirectTcpIpTunnel::Ptr SshConnection::createTunnel(quint16 remotePort)
+{
+ QSSH_ASSERT_AND_RETURN_VALUE(state() == Connected, SshDirectTcpIpTunnel::Ptr());
+ return d->createTunnel(remotePort);
+}
+
int SshConnection::closeAllChannels()
{
try {
@@ -730,6 +738,11 @@ QSharedPointer<SftpChannel> SshConnectionPrivate::createSftpChannel()
return m_channelManager->createSftpChannel();
}
+SshDirectTcpIpTunnel::Ptr SshConnectionPrivate::createTunnel(quint16 remotePort)
+{
+ return m_channelManager->createTunnel(remotePort, m_conn->connectionInfo());
+}
+
const quint64 SshConnectionPrivate::InvalidSeqNr = static_cast<quint64>(-1);
} // namespace Internal
diff --git a/src/libs/ssh/sshconnection.h b/src/libs/ssh/sshconnection.h
index 66263c30772..3c982b197e2 100644
--- a/src/libs/ssh/sshconnection.h
+++ b/src/libs/ssh/sshconnection.h
@@ -43,6 +43,7 @@
namespace QSsh {
class SftpChannel;
+class SshDirectTcpIpTunnel;
class SshRemoteProcess;
namespace Internal {
@@ -103,6 +104,7 @@ public:
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel();
+ QSharedPointer<SshDirectTcpIpTunnel> createTunnel(quint16 remotePort);
// -1 if an error occurred, number of channels closed otherwise.
int closeAllChannels();
diff --git a/src/libs/ssh/sshconnection_p.h b/src/libs/ssh/sshconnection_p.h
index bdf0c26c960..ed74322b4d1 100644
--- a/src/libs/ssh/sshconnection_p.h
+++ b/src/libs/ssh/sshconnection_p.h
@@ -34,7 +34,6 @@
#include "sshconnection.h"
#include "sshexception_p.h"
#include "sshincomingpacket_p.h"
-#include "sshremoteprocess.h"
#include "sshsendfacility_p.h"
#include <QHash>
@@ -50,6 +49,8 @@ QT_END_NAMESPACE
namespace QSsh {
class SftpChannel;
+class SshRemoteProcess;
+class SshDirectTcpIpTunnel;
namespace Internal {
class SshChannelManager;
@@ -88,6 +89,8 @@ public:
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel();
+ QSharedPointer<SshDirectTcpIpTunnel> createTunnel(quint16 remotePort);
+
SshStateInternal state() const { return m_state; }
SshError error() const { return m_error; }
QString errorString() const { return m_errorString; }
diff --git a/src/libs/ssh/sshdirecttcpiptunnel.cpp b/src/libs/ssh/sshdirecttcpiptunnel.cpp
new file mode 100644
index 00000000000..ef0cada6536
--- /dev/null
+++ b/src/libs/ssh/sshdirecttcpiptunnel.cpp
@@ -0,0 +1,194 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation ([email protected])
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at [email protected].
+**
+**************************************************************************/
+#include "sshdirecttcpiptunnel.h"
+#include "sshdirecttcpiptunnel_p.h"
+
+#include "sshincomingpacket_p.h"
+#include "sshsendfacility_p.h"
+
+#include <QTimer>
+
+namespace QSsh {
+namespace Internal {
+
+SshDirectTcpIpTunnelPrivate::SshDirectTcpIpTunnelPrivate(quint32 channelId, quint16 remotePort,
+ const SshConnectionInfo &connectionInfo, SshSendFacility &sendFacility)
+ : AbstractSshChannel(channelId, sendFacility),
+ m_remotePort(remotePort),
+ m_connectionInfo(connectionInfo)
+{
+ connect(this, SIGNAL(eof()), SLOT(handleEof()));
+}
+
+void SshDirectTcpIpTunnelPrivate::handleChannelSuccess()
+{
+ throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
+ "Unexpected SSH_MSG_CHANNEL_SUCCESS message.");
+}
+
+void SshDirectTcpIpTunnelPrivate::handleChannelFailure()
+{
+ throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
+ "Unexpected SSH_MSG_CHANNEL_FAILURE message.");
+}
+
+void SshDirectTcpIpTunnelPrivate::handleOpenSuccessInternal()
+{
+ emit initialized();
+}
+
+void SshDirectTcpIpTunnelPrivate::handleOpenFailureInternal(const QString &reason)
+{
+ emit error(reason);
+ closeChannel();
+}
+
+void SshDirectTcpIpTunnelPrivate::handleChannelDataInternal(const QByteArray &data)
+{
+ m_data += data;
+ emit readyRead();
+}
+
+void SshDirectTcpIpTunnelPrivate::handleChannelExtendedDataInternal(quint32 type,
+ const QByteArray &data)
+{
+ qDebug("%s: Unexpected extended channel data. Type is %u, content is '%s'.", Q_FUNC_INFO, type,
+ data.constData());
+}
+
+void SshDirectTcpIpTunnelPrivate::handleExitStatus(const SshChannelExitStatus &exitStatus)
+{
+ qDebug("%s: Unexpected exit status %d.", Q_FUNC_INFO, exitStatus.exitStatus);
+}
+
+void SshDirectTcpIpTunnelPrivate::handleExitSignal(const SshChannelExitSignal &signal)
+{
+ qDebug("%s: Unexpected exit signal %s.", Q_FUNC_INFO, signal.signal.constData());
+}
+
+void SshDirectTcpIpTunnelPrivate::closeHook()
+{
+ emit closed();
+}
+
+void SshDirectTcpIpTunnelPrivate::handleEof()
+{
+ /*
+ * For some reason, the OpenSSH server only sends EOF when the remote port goes away,
+ * but does not close the channel, even though it becomes useless in that case.
+ * So we close it ourselves.
+ */
+ closeChannel();
+}
+
+} // namespace Internal
+
+using namespace Internal;
+
+SshDirectTcpIpTunnel::SshDirectTcpIpTunnel(quint32 channelId, quint16 remotePort,
+ const SshConnectionInfo &connectionInfo, SshSendFacility &sendFacility)
+ : d(new SshDirectTcpIpTunnelPrivate(channelId, remotePort, connectionInfo, sendFacility))
+{
+ connect(d, SIGNAL(initialized()), SIGNAL(initialized()), Qt::QueuedConnection);
+ connect(d, SIGNAL(readyRead()), SIGNAL(readyRead()), Qt::QueuedConnection);
+ connect(d, SIGNAL(closed()), SIGNAL(tunnelClosed()), Qt::QueuedConnection);
+ connect(d, SIGNAL(error(QString)), SLOT(handleError(QString)), Qt::QueuedConnection);
+}
+
+SshDirectTcpIpTunnel::~SshDirectTcpIpTunnel()
+{
+ d->closeChannel();
+ delete d;
+}
+
+bool SshDirectTcpIpTunnel::atEnd() const
+{
+ return QIODevice::atEnd() && d->m_data.isEmpty();
+}
+
+qint64 SshDirectTcpIpTunnel::bytesAvailable() const
+{
+ return QIODevice::bytesAvailable() + d->m_data.count();
+}
+
+bool SshDirectTcpIpTunnel::canReadLine() const
+{
+ return QIODevice::canReadLine() || d->m_data.contains('\n');
+}
+
+void SshDirectTcpIpTunnel::close()
+{
+ d->closeChannel();
+ QIODevice::close();
+}
+
+void SshDirectTcpIpTunnel::initialize()
+{
+ QSSH_ASSERT_AND_RETURN(d->channelState() == AbstractSshChannel::Inactive);
+
+ try {
+ QIODevice::open(QIODevice::ReadWrite);
+ d->m_sendFacility.sendDirectTcpIpPacket(d->localChannelId(), d->initialWindowSize(),
+ d->maxPacketSize(), d->m_connectionInfo.peerAddress.toString().toUtf8(),
+ d->m_remotePort, d->m_connectionInfo.localAddress.toString().toUtf8(),
+ d->m_connectionInfo.localPort);
+ d->setChannelState(AbstractSshChannel::SessionRequested);
+ d->m_timeoutTimer->start(d->ReplyTimeout);
+ } catch (Botan::Exception &e) { // Won't happen, but let's play it safe.
+ qDebug("Botan error: %s", e.what());
+ d->closeChannel();
+ }
+}
+
+qint64 SshDirectTcpIpTunnel::readData(char *data, qint64 maxlen)
+{
+ const qint64 bytesRead = qMin(qint64(d->m_data.count()), maxlen);
+ memcpy(data, d->m_data.constData(), bytesRead);
+ d->m_data.remove(0, bytesRead);
+ return bytesRead;
+}
+
+qint64 SshDirectTcpIpTunnel::writeData(const char *data, qint64 len)
+{
+ QSSH_ASSERT_AND_RETURN_VALUE(d->channelState() == AbstractSshChannel::SessionEstablished, 0);
+
+ d->sendData(QByteArray(data, len));
+ return len;
+}
+
+void SshDirectTcpIpTunnel::handleError(const QString &reason)
+{
+ setErrorString(reason);
+ emit error(reason);
+}
+
+} // namespace QSsh
diff --git a/src/libs/ssh/sshdirecttcpiptunnel.h b/src/libs/ssh/sshdirecttcpiptunnel.h
new file mode 100644
index 00000000000..b451c96afcd
--- /dev/null
+++ b/src/libs/ssh/sshdirecttcpiptunnel.h
@@ -0,0 +1,90 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation ([email protected])
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at [email protected].
+**
+**************************************************************************/
+
+#ifndef SSHDIRECTTCPIPTUNNEL_H
+#define SSHDIRECTTCPIPTUNNEL_H
+
+#include "ssh_global.h"
+
+#include <QIODevice>
+#include <QSharedPointer>
+
+namespace QSsh {
+class SshConnectionInfo;
+
+namespace Internal {
+class SshChannelManager;
+class SshDirectTcpIpTunnelPrivate;
+class SshSendFacility;
+} // namespace Internal
+
+class QSSH_EXPORT SshDirectTcpIpTunnel : public QIODevice
+{
+ Q_OBJECT
+
+ friend class Internal::SshChannelManager;
+
+public:
+ typedef QSharedPointer<SshDirectTcpIpTunnel> Ptr;
+
+ ~SshDirectTcpIpTunnel();
+
+ // QIODevice stuff
+ bool atEnd() const;
+ qint64 bytesAvailable() const;
+ bool canReadLine() const;
+ void close();
+ bool isSequential() const { return true; }
+
+ void initialize();
+
+signals:
+ void initialized();
+ void error(const QString &reason);
+ void tunnelClosed();
+
+private:
+ SshDirectTcpIpTunnel(quint32 channelId, quint16 remotePort,
+ const SshConnectionInfo &connectionInfo, Internal::SshSendFacility &sendFacility);
+
+ // QIODevice stuff
+ qint64 readData(char *data, qint64 maxlen);
+ qint64 writeData(const char *data, qint64 len);
+
+ Q_SLOT void handleError(const QString &reason);
+
+ Internal::SshDirectTcpIpTunnelPrivate * const d;
+};
+
+} // namespace QSsh
+
+#endif // SSHDIRECTTCPIPTUNNEL_H
diff --git a/src/libs/ssh/sshdirecttcpiptunnel_p.h b/src/libs/ssh/sshdirecttcpiptunnel_p.h
new file mode 100644
index 00000000000..7122c4dc2a3
--- /dev/null
+++ b/src/libs/ssh/sshdirecttcpiptunnel_p.h
@@ -0,0 +1,84 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation ([email protected])
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at [email protected].
+**
+**************************************************************************/
+#ifndef DIRECTTCPIPCHANNEL_P_H
+#define DIRECTTCPIPCHANNEL_P_H
+
+#include "sshchannel_p.h"
+
+#include "sshconnection.h"
+
+namespace QSsh {
+class SshDirectTcpIpTunnel;
+
+namespace Internal {
+
+class SshDirectTcpIpTunnelPrivate : public AbstractSshChannel
+{
+ Q_OBJECT
+
+ friend class QSsh::SshDirectTcpIpTunnel;
+
+public:
+ explicit SshDirectTcpIpTunnelPrivate(quint32 channelId, quint16 remotePort,
+ const SshConnectionInfo &connectionInfo, SshSendFacility &sendFacility);
+
+signals:
+ void initialized();
+ void readyRead();
+ void error(const QString &reason);
+ void closed();
+
+private slots:
+ void handleEof();
+
+private:
+ void handleChannelSuccess();
+ void handleChannelFailure();
+
+ void handleOpenSuccessInternal();
+ void handleOpenFailureInternal(const QString &reason);
+ void handleChannelDataInternal(const QByteArray &data);
+ void handleChannelExtendedDataInternal(quint32 type, const QByteArray &data);
+ void handleExitStatus(const SshChannelExitStatus &exitStatus);
+ void handleExitSignal(const SshChannelExitSignal &signal);
+
+ void closeHook();
+
+ const quint16 m_remotePort;
+ const SshConnectionInfo m_connectionInfo;
+ QByteArray m_data;
+};
+
+} // namespace Internal
+} // namespace QSsh
+
+#endif // DIRECTTCPIPCHANNEL_P_H
diff --git a/src/libs/ssh/sshoutgoingpacket.cpp b/src/libs/ssh/sshoutgoingpacket.cpp
index 97b199beed0..1be0aa49343 100644
--- a/src/libs/ssh/sshoutgoingpacket.cpp
+++ b/src/libs/ssh/sshoutgoingpacket.cpp
@@ -143,7 +143,16 @@ void SshOutgoingPacket::generateSessionPacket(quint32 channelId,
quint32 windowSize, quint32 maxPacketSize)
{
init(SSH_MSG_CHANNEL_OPEN).appendString("session").appendInt(channelId)
- .appendInt(windowSize).appendInt(maxPacketSize).finalize();
+ .appendInt(windowSize).appendInt(maxPacketSize).finalize();
+}
+
+void SshOutgoingPacket::generateDirectTcpIpPacket(quint32 channelId, quint32 windowSize,
+ quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort,
+ const QByteArray &localIpAddress, quint32 localPort)
+{
+ init(SSH_MSG_CHANNEL_OPEN).appendString("direct-tcpip").appendInt(channelId)
+ .appendInt(windowSize).appendInt(maxPacketSize).appendString(remoteHost)
+ .appendInt(remotePort).appendString(localIpAddress).appendInt(localPort).finalize();
}
void SshOutgoingPacket::generateEnvPacket(quint32 remoteChannel,
diff --git a/src/libs/ssh/sshoutgoingpacket_p.h b/src/libs/ssh/sshoutgoingpacket_p.h
index 60b2d3087a2..7c77c749b30 100644
--- a/src/libs/ssh/sshoutgoingpacket_p.h
+++ b/src/libs/ssh/sshoutgoingpacket_p.h
@@ -62,6 +62,9 @@ public:
void generateInvalidMessagePacket();
void generateSessionPacket(quint32 channelId, quint32 windowSize,
quint32 maxPacketSize);
+ void generateDirectTcpIpPacket(quint32 channelId, quint32 windowSize,
+ quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort,
+ const QByteArray &localIpAddress, quint32 localPort);
void generateEnvPacket(quint32 remoteChannel, const QByteArray &var,
const QByteArray &value);
void generatePtyRequestPacket(quint32 remoteChannel,
diff --git a/src/libs/ssh/sshremoteprocess.cpp b/src/libs/ssh/sshremoteprocess.cpp
index 36f71b5b805..a4f4ae76b5a 100644
--- a/src/libs/ssh/sshremoteprocess.cpp
+++ b/src/libs/ssh/sshremoteprocess.cpp
@@ -167,6 +167,7 @@ void SshRemoteProcess::init()
connect(d, SIGNAL(readyReadStandardError()), this,
SIGNAL(readyReadStandardError()), Qt::QueuedConnection);
connect(d, SIGNAL(closed(int)), this, SIGNAL(closed(int)), Qt::QueuedConnection);
+ connect(d, SIGNAL(eof()), SIGNAL(readChannelFinished()), Qt::QueuedConnection);
}
void SshRemoteProcess::addToEnvironment(const QByteArray &var, const QByteArray &value)
diff --git a/src/libs/ssh/sshremoteprocess_p.h b/src/libs/ssh/sshremoteprocess_p.h
index 57bf3f9ceb7..6cecde117c9 100644
--- a/src/libs/ssh/sshremoteprocess_p.h
+++ b/src/libs/ssh/sshremoteprocess_p.h
@@ -54,13 +54,6 @@ public:
NotYetStarted, ExecRequested, StartFailed, Running, Exited
};
- virtual void handleChannelSuccess();
- virtual void handleChannelFailure();
-
- virtual void closeHook();
-
- QByteArray &data();
-
signals:
void started();
void readyRead();
@@ -74,6 +67,9 @@ private:
SshRemoteProcessPrivate(quint32 channelId, SshSendFacility &sendFacility,
SshRemoteProcess *proc);
+ virtual void handleChannelSuccess();
+ virtual void handleChannelFailure();
+
virtual void handleOpenSuccessInternal();
virtual void handleOpenFailureInternal(const QString &reason);
virtual void handleChannelDataInternal(const QByteArray &data);
@@ -82,8 +78,11 @@ private:
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus);
virtual void handleExitSignal(const SshChannelExitSignal &signal);
+ virtual void closeHook();
+
void init();
void setProcState(ProcessState newState);
+ QByteArray &data();
QProcess::ProcessChannel m_readChannel;
diff --git a/src/libs/ssh/sshsendfacility.cpp b/src/libs/ssh/sshsendfacility.cpp
index 07f0a3755fd..e90ba622464 100644
--- a/src/libs/ssh/sshsendfacility.cpp
+++ b/src/libs/ssh/sshsendfacility.cpp
@@ -150,6 +150,15 @@ void SshSendFacility::sendSessionPacket(quint32 channelId, quint32 windowSize,
sendPacket();
}
+void SshSendFacility::sendDirectTcpIpPacket(quint32 channelId, quint32 windowSize,
+ quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort,
+ const QByteArray &localIpAddress, quint32 localPort)
+{
+ m_outgoingPacket.generateDirectTcpIpPacket(channelId, windowSize, maxPacketSize, remoteHost,
+ remotePort, localIpAddress, localPort);
+ sendPacket();
+}
+
void SshSendFacility::sendPtyRequestPacket(quint32 remoteChannel,
const SshPseudoTerminal &terminal)
{
diff --git a/src/libs/ssh/sshsendfacility_p.h b/src/libs/ssh/sshsendfacility_p.h
index d7d20d901d5..b17484e491d 100644
--- a/src/libs/ssh/sshsendfacility_p.h
+++ b/src/libs/ssh/sshsendfacility_p.h
@@ -69,6 +69,9 @@ public:
void sendInvalidPacket();
void sendSessionPacket(quint32 channelId, quint32 windowSize,
quint32 maxPacketSize);
+ void sendDirectTcpIpPacket(quint32 channelId, quint32 windowSize, quint32 maxPacketSize,
+ const QByteArray &remoteHost, quint32 remotePort, const QByteArray &localIpAddress,
+ quint32 localPort);
void sendPtyRequestPacket(quint32 remoteChannel,
const SshPseudoTerminal &terminal);
void sendEnvPacket(quint32 remoteChannel, const QByteArray &var,