forked from qt-creator/qt-creator
SSH: Implement tunneling.
This is the "direct-tcpip" port forwarding specified in RFC 4254. Change-Id: I1ffa2e923b4479c7211b1b4304e66895b565fb64 Reviewed-by: hjk <qthjk@ovi.com> Reviewed-by: Christian Kandeler <christian.kandeler@nokia.com>
This commit is contained in:
@@ -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();
|
||||
|
@@ -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
|
||||
|
@@ -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",
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
|
@@ -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; }
|
||||
|
194
src/libs/ssh/sshdirecttcpiptunnel.cpp
Normal file
194
src/libs/ssh/sshdirecttcpiptunnel.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** 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 qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#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
|
90
src/libs/ssh/sshdirecttcpiptunnel.h
Normal file
90
src/libs/ssh/sshdirecttcpiptunnel.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** 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 qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#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
|
84
src/libs/ssh/sshdirecttcpiptunnel_p.h
Normal file
84
src/libs/ssh/sshdirecttcpiptunnel_p.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** 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 qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#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
|
@@ -146,6 +146,15 @@ void SshOutgoingPacket::generateSessionPacket(quint32 channelId,
|
||||
.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,
|
||||
const QByteArray &var, const QByteArray &value)
|
||||
{
|
||||
|
@@ -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,
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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,
|
||||
|
@@ -71,10 +71,10 @@ private:
|
||||
const QSsh::SshConnectionParameters m_sshParams;
|
||||
QTimer * const m_timeoutTimer;
|
||||
QTextStream *m_textStream;
|
||||
QSsh::SshRemoteProcessRunner * const m_remoteRunner;
|
||||
QSsh::SshRemoteProcess::Ptr m_catProcess;
|
||||
QSsh::SshRemoteProcess::Ptr m_echoProcess;
|
||||
QSsh::SshConnection *m_sshConnection;
|
||||
QSsh::SshRemoteProcessRunner * const m_remoteRunner;
|
||||
QByteArray m_remoteStdout;
|
||||
QByteArray m_remoteStderr;
|
||||
QByteArray m_remoteData;
|
||||
|
@@ -5,4 +5,4 @@
|
||||
#-------------------------------------------------
|
||||
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = errorhandling sftp remoteprocess shell sftpfsmodel
|
||||
SUBDIRS = errorhandling sftp remoteprocess shell sftpfsmodel tunnel
|
||||
|
174
tests/manual/ssh/tunnel/argumentscollector.cpp
Normal file
174
tests/manual/ssh/tunnel/argumentscollector.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** 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 qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#include "argumentscollector.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace QSsh;
|
||||
|
||||
using namespace std;
|
||||
|
||||
ArgumentsCollector::ArgumentsCollector(const QStringList &args)
|
||||
: m_arguments(args)
|
||||
{
|
||||
}
|
||||
|
||||
QSsh::SshConnectionParameters ArgumentsCollector::collect(bool &success) const
|
||||
{
|
||||
SshConnectionParameters parameters;
|
||||
parameters.host = QLatin1String("localhost");
|
||||
|
||||
try {
|
||||
bool authTypeGiven = false;
|
||||
bool portGiven = false;
|
||||
bool timeoutGiven = false;
|
||||
bool proxySettingGiven = false;
|
||||
int pos;
|
||||
int port;
|
||||
|
||||
for (pos = 1; pos < m_arguments.count() - 1; ++pos) {
|
||||
if (checkAndSetStringArg(pos, parameters.userName, "-u"))
|
||||
continue;
|
||||
if (checkAndSetIntArg(pos, port, portGiven, "-p")
|
||||
|| checkAndSetIntArg(pos, parameters.timeout, timeoutGiven, "-t"))
|
||||
continue;
|
||||
if (checkAndSetStringArg(pos, parameters.password, "-pwd")) {
|
||||
if (!parameters.privateKeyFile.isEmpty())
|
||||
throw ArgumentErrorException(QLatin1String("-pwd and -k are mutually exclusive."));
|
||||
parameters.authenticationType
|
||||
= SshConnectionParameters::AuthenticationByPassword;
|
||||
authTypeGiven = true;
|
||||
continue;
|
||||
}
|
||||
if (checkAndSetStringArg(pos, parameters.privateKeyFile, "-k")) {
|
||||
if (!parameters.password.isEmpty())
|
||||
throw ArgumentErrorException(QLatin1String("-pwd and -k are mutually exclusive."));
|
||||
parameters.authenticationType
|
||||
= SshConnectionParameters::AuthenticationByKey;
|
||||
authTypeGiven = true;
|
||||
continue;
|
||||
}
|
||||
if (!checkForNoProxy(pos, parameters.proxyType, proxySettingGiven))
|
||||
throw ArgumentErrorException(QLatin1String("unknown option ") + m_arguments.at(pos));
|
||||
}
|
||||
|
||||
Q_ASSERT(pos <= m_arguments.count());
|
||||
if (pos == m_arguments.count() - 1) {
|
||||
if (!checkForNoProxy(pos, parameters.proxyType, proxySettingGiven))
|
||||
throw ArgumentErrorException(QLatin1String("unknown option ") + m_arguments.at(pos));
|
||||
}
|
||||
|
||||
if (!authTypeGiven) {
|
||||
parameters.authenticationType = SshConnectionParameters::AuthenticationByKey;
|
||||
parameters.privateKeyFile = QDir::homePath() + QLatin1String("/.ssh/id_rsa");
|
||||
}
|
||||
|
||||
if (parameters.userName.isEmpty()) {
|
||||
parameters.userName
|
||||
= QProcessEnvironment::systemEnvironment().value(QLatin1String("USER"));
|
||||
}
|
||||
if (parameters.userName.isEmpty())
|
||||
throw ArgumentErrorException(QLatin1String("No user name given."));
|
||||
|
||||
if (parameters.host.isEmpty())
|
||||
throw ArgumentErrorException(QLatin1String("No host given."));
|
||||
|
||||
parameters.port = portGiven ? port : 22;
|
||||
if (!timeoutGiven)
|
||||
parameters.timeout = 30;
|
||||
success = true;
|
||||
} catch (ArgumentErrorException &ex) {
|
||||
cerr << "Error: " << qPrintable(ex.error) << endl;
|
||||
printUsage();
|
||||
success = false;
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
void ArgumentsCollector::printUsage() const
|
||||
{
|
||||
cerr << "Usage: " << qPrintable(m_arguments.first())
|
||||
<< "[ -u <user> ] "
|
||||
<< "[ -pwd <password> | -k <private key file> ] [ -p <port> ] "
|
||||
<< "[ -t <timeout> ] [ -no-proxy ]" << endl;
|
||||
}
|
||||
|
||||
bool ArgumentsCollector::checkAndSetStringArg(int &pos, QString &arg, const char *opt) const
|
||||
{
|
||||
if (m_arguments.at(pos) == QLatin1String(opt)) {
|
||||
if (!arg.isEmpty()) {
|
||||
throw ArgumentErrorException(QLatin1String("option ") + opt
|
||||
+ QLatin1String(" was given twice."));
|
||||
}
|
||||
arg = m_arguments.at(++pos);
|
||||
if (arg.isEmpty() && QLatin1String(opt) != QLatin1String("-pwd"))
|
||||
throw ArgumentErrorException(QLatin1String("empty argument not allowed here."));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ArgumentsCollector::checkAndSetIntArg(int &pos, int &val,
|
||||
bool &alreadyGiven, const char *opt) const
|
||||
{
|
||||
if (m_arguments.at(pos) == QLatin1String(opt)) {
|
||||
if (alreadyGiven) {
|
||||
throw ArgumentErrorException(QLatin1String("option ") + opt
|
||||
+ QLatin1String(" was given twice."));
|
||||
}
|
||||
bool isNumber;
|
||||
val = m_arguments.at(++pos).toInt(&isNumber);
|
||||
if (!isNumber) {
|
||||
throw ArgumentErrorException(QLatin1String("option ") + opt
|
||||
+ QLatin1String(" needs integer argument"));
|
||||
}
|
||||
alreadyGiven = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ArgumentsCollector::checkForNoProxy(int &pos,
|
||||
SshConnectionParameters::ProxyType &type, bool &alreadyGiven) const
|
||||
{
|
||||
if (m_arguments.at(pos) == QLatin1String("-no-proxy")) {
|
||||
if (alreadyGiven)
|
||||
throw ArgumentErrorException(QLatin1String("proxy setting given twice."));
|
||||
type = SshConnectionParameters::NoProxy;
|
||||
alreadyGiven = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
63
tests/manual/ssh/tunnel/argumentscollector.h
Normal file
63
tests/manual/ssh/tunnel/argumentscollector.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** 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 qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef ARGUMENTSCOLLECTOR_H
|
||||
#define ARGUMENTSCOLLECTOR_H
|
||||
|
||||
#include <ssh/sshconnection.h>
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
class ArgumentsCollector
|
||||
{
|
||||
public:
|
||||
ArgumentsCollector(const QStringList &args);
|
||||
QSsh::SshConnectionParameters collect(bool &success) const;
|
||||
private:
|
||||
struct ArgumentErrorException
|
||||
{
|
||||
ArgumentErrorException(const QString &error) : error(error) {}
|
||||
const QString error;
|
||||
};
|
||||
|
||||
void printUsage() const;
|
||||
bool checkAndSetStringArg(int &pos, QString &arg, const char *opt) const;
|
||||
bool checkAndSetIntArg(int &pos, int &val, bool &alreadyGiven,
|
||||
const char *opt) const;
|
||||
bool checkForNoProxy(int &pos,
|
||||
QSsh::SshConnectionParameters::ProxyType &type,
|
||||
bool &alreadyGiven) const;
|
||||
|
||||
const QStringList m_arguments;
|
||||
};
|
||||
|
||||
#endif // ARGUMENTSCOLLECTOR_H
|
55
tests/manual/ssh/tunnel/main.cpp
Normal file
55
tests/manual/ssh/tunnel/main.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** 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 qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#include "../remoteprocess/argumentscollector.h"
|
||||
#include "tunnel.h"
|
||||
|
||||
#include <ssh/sshconnection.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
bool parseSuccess;
|
||||
const QSsh::SshConnectionParameters ¶meters
|
||||
= ArgumentsCollector(app.arguments()).collect(parseSuccess);
|
||||
if (!parseSuccess)
|
||||
return EXIT_FAILURE;
|
||||
Tunnel tunnel(parameters);
|
||||
tunnel.run();
|
||||
return app.exec();
|
||||
}
|
165
tests/manual/ssh/tunnel/tunnel.cpp
Normal file
165
tests/manual/ssh/tunnel/tunnel.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** 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 qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#include "tunnel.h"
|
||||
|
||||
#include <ssh/sshconnection.h>
|
||||
#include <ssh/sshdirecttcpiptunnel.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QTcpServer>
|
||||
#include <QTcpSocket>
|
||||
#include <QTimer>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
const QByteArray ServerDataPrefix("Received the following data: ");
|
||||
const QByteArray TestData("Urgsblubb?");
|
||||
|
||||
using namespace QSsh;
|
||||
|
||||
Tunnel::Tunnel(const QSsh::SshConnectionParameters ¶meters, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_connection(new SshConnection(parameters, this)),
|
||||
m_tunnelServer(new QTcpServer(this)),
|
||||
m_expectingChannelClose(false)
|
||||
{
|
||||
connect(m_connection, SIGNAL(connected()), SLOT(handleConnected()));
|
||||
connect(m_connection, SIGNAL(error(QSsh::SshError)), SLOT(handleConnectionError()));
|
||||
}
|
||||
|
||||
Tunnel::~Tunnel()
|
||||
{
|
||||
}
|
||||
|
||||
void Tunnel::run()
|
||||
{
|
||||
std::cout << "Connecting to SSH server..." << std::endl;
|
||||
m_connection->connectToHost();
|
||||
}
|
||||
|
||||
void Tunnel::handleConnectionError()
|
||||
{
|
||||
std::cerr << "SSH connection error: " << qPrintable(m_connection->errorString()) << std::endl;
|
||||
qApp->exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void Tunnel::handleConnected()
|
||||
{
|
||||
std::cout << "Opening server side..." << std::endl;
|
||||
if (!m_tunnelServer->listen(QHostAddress::LocalHost)) {
|
||||
std::cerr << "Error opening port: "
|
||||
<< m_tunnelServer->errorString().toLocal8Bit().constData() << std::endl;
|
||||
qApp->exit(EXIT_FAILURE);
|
||||
return;
|
||||
}
|
||||
m_forwardedPort = m_tunnelServer->serverPort();
|
||||
connect(m_tunnelServer, SIGNAL(newConnection()), SLOT(handleNewConnection()));
|
||||
|
||||
m_tunnel = m_connection->createTunnel(m_forwardedPort);
|
||||
connect(m_tunnel.data(), SIGNAL(initialized()), SLOT(handleInitialized()));
|
||||
connect(m_tunnel.data(), SIGNAL(error(QString)), SLOT(handleTunnelError(QString)));
|
||||
connect(m_tunnel.data(), SIGNAL(readyRead()), SLOT(handleServerData()));
|
||||
connect(m_tunnel.data(), SIGNAL(tunnelClosed()), SLOT(handleTunnelClosed()));
|
||||
|
||||
std::cout << "Initializing tunnel..." << std::endl;
|
||||
m_tunnel->initialize();
|
||||
}
|
||||
|
||||
void Tunnel::handleInitialized()
|
||||
{
|
||||
std::cout << "Writing data into the tunnel..." << std::endl;
|
||||
m_tunnel->write(TestData);
|
||||
QTimer * const timeoutTimer = new QTimer(this);
|
||||
connect(timeoutTimer, SIGNAL(timeout()), SLOT(handleTimeout()));
|
||||
timeoutTimer->start(10000);
|
||||
}
|
||||
|
||||
void Tunnel::handleServerData()
|
||||
{
|
||||
m_dataReceivedFromServer += m_tunnel->readAll();
|
||||
if (m_dataReceivedFromServer == ServerDataPrefix + TestData) {
|
||||
std::cout << "Data exchange successful. Closing server socket..." << std::endl;
|
||||
m_expectingChannelClose = true;
|
||||
m_tunnelSocket->close();
|
||||
}
|
||||
}
|
||||
|
||||
void Tunnel::handleTunnelError(const QString &reason)
|
||||
{
|
||||
std::cerr << "Tunnel error: " << reason.toLocal8Bit().constData() << std::endl;
|
||||
qApp->exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void Tunnel::handleTunnelClosed()
|
||||
{
|
||||
if (m_expectingChannelClose) {
|
||||
std::cout << "Successfully detected channel close." << std::endl;
|
||||
std::cout << "Test finished successfully." << std::endl;
|
||||
qApp->quit();
|
||||
} else {
|
||||
std::cerr << "Error: Remote host closed channel." << std::endl;
|
||||
qApp->exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void Tunnel::handleNewConnection()
|
||||
{
|
||||
m_tunnelSocket = m_tunnelServer->nextPendingConnection();
|
||||
m_tunnelServer->close();
|
||||
connect(m_tunnelSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(handleSocketError()));
|
||||
connect(m_tunnelSocket, SIGNAL(readyRead()), SLOT(handleClientData()));
|
||||
handleClientData();
|
||||
}
|
||||
|
||||
void Tunnel::handleSocketError()
|
||||
{
|
||||
std::cerr << "Socket error: " << m_tunnelSocket->errorString().toLocal8Bit().constData()
|
||||
<< std::endl;
|
||||
qApp->exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void Tunnel::handleClientData()
|
||||
{
|
||||
m_dataReceivedFromClient += m_tunnelSocket->readAll();
|
||||
if (m_dataReceivedFromClient == TestData) {
|
||||
std::cout << "Client data successfully received by server, now sending data to client..."
|
||||
<< std::endl;
|
||||
m_tunnelSocket->write(ServerDataPrefix + m_dataReceivedFromClient);
|
||||
}
|
||||
}
|
||||
|
||||
void Tunnel::handleTimeout()
|
||||
{
|
||||
std::cerr << "Error: Timeout waiting for test completion." << std::endl;
|
||||
qApp->exit(EXIT_FAILURE);
|
||||
}
|
81
tests/manual/ssh/tunnel/tunnel.h
Normal file
81
tests/manual/ssh/tunnel/tunnel.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** 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 qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#ifndef TUNNEL_H
|
||||
#define TUNNEL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QTcpServer;
|
||||
class QTcpSocket;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace QSsh {
|
||||
class SshConnection;
|
||||
class SshConnectionParameters;
|
||||
class SshDirectTcpIpTunnel;
|
||||
}
|
||||
|
||||
class Tunnel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Tunnel(const QSsh::SshConnectionParameters ¶meters, QObject *parent = 0);
|
||||
~Tunnel();
|
||||
|
||||
void run();
|
||||
|
||||
private slots:
|
||||
void handleConnected();
|
||||
void handleConnectionError();
|
||||
void handleServerData();
|
||||
void handleInitialized();
|
||||
void handleTunnelError(const QString &reason);
|
||||
void handleTunnelClosed();
|
||||
void handleNewConnection();
|
||||
void handleSocketError();
|
||||
void handleClientData();
|
||||
void handleTimeout();
|
||||
|
||||
private:
|
||||
QSsh::SshConnection * const m_connection;
|
||||
QSharedPointer<QSsh::SshDirectTcpIpTunnel> m_tunnel;
|
||||
QTcpServer * const m_tunnelServer;
|
||||
QTcpSocket *m_tunnelSocket;
|
||||
quint16 m_forwardedPort;
|
||||
QByteArray m_dataReceivedFromServer;
|
||||
QByteArray m_dataReceivedFromClient;
|
||||
bool m_expectingChannelClose;
|
||||
};
|
||||
|
||||
#endif // TUNNEL_H
|
5
tests/manual/ssh/tunnel/tunnel.pro
Normal file
5
tests/manual/ssh/tunnel/tunnel.pro
Normal file
@@ -0,0 +1,5 @@
|
||||
include(../ssh.pri)
|
||||
|
||||
TARGET=tunnel
|
||||
SOURCES=main.cpp tunnel.cpp argumentscollector.cpp
|
||||
HEADERS=tunnel.h argumentscollector.h
|
Reference in New Issue
Block a user