diff options
author | Christian Kandeler <[email protected]> | 2012-06-19 13:03:48 +0200 |
---|---|---|
committer | Christian Kandeler <[email protected]> | 2012-08-28 15:12:04 +0200 |
commit | edcf76613b82d4b04ad9d0797515dc42d983eb68 (patch) | |
tree | 5229324612e8489ebe70e304641ea0781893dfdd /src/libs/ssh | |
parent | a57b4cf93efcb3fe30623566115b29e925367f7f (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.h | 11 | ||||
-rw-r--r-- | src/libs/ssh/ssh.pro | 7 | ||||
-rw-r--r-- | src/libs/ssh/ssh.qbs | 1 | ||||
-rw-r--r-- | src/libs/ssh/sshchannel.cpp | 33 | ||||
-rw-r--r-- | src/libs/ssh/sshchannel_p.h | 20 | ||||
-rw-r--r-- | src/libs/ssh/sshchannelmanager.cpp | 11 | ||||
-rw-r--r-- | src/libs/ssh/sshchannelmanager_p.h | 7 | ||||
-rw-r--r-- | src/libs/ssh/sshconnection.cpp | 13 | ||||
-rw-r--r-- | src/libs/ssh/sshconnection.h | 2 | ||||
-rw-r--r-- | src/libs/ssh/sshconnection_p.h | 5 | ||||
-rw-r--r-- | src/libs/ssh/sshdirecttcpiptunnel.cpp | 194 | ||||
-rw-r--r-- | src/libs/ssh/sshdirecttcpiptunnel.h | 90 | ||||
-rw-r--r-- | src/libs/ssh/sshdirecttcpiptunnel_p.h | 84 | ||||
-rw-r--r-- | src/libs/ssh/sshoutgoingpacket.cpp | 11 | ||||
-rw-r--r-- | src/libs/ssh/sshoutgoingpacket_p.h | 3 | ||||
-rw-r--r-- | src/libs/ssh/sshremoteprocess.cpp | 1 | ||||
-rw-r--r-- | src/libs/ssh/sshremoteprocess_p.h | 13 | ||||
-rw-r--r-- | src/libs/ssh/sshsendfacility.cpp | 9 | ||||
-rw-r--r-- | src/libs/ssh/sshsendfacility_p.h | 3 |
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, |