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
|
Q_OBJECT
|
||||||
friend class QSsh::SftpChannel;
|
friend class QSsh::SftpChannel;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum SftpState { Inactive, SubsystemRequested, InitSent, Initialized };
|
enum SftpState { Inactive, SubsystemRequested, InitSent, Initialized };
|
||||||
|
|
||||||
virtual void handleChannelSuccess();
|
|
||||||
virtual void handleChannelFailure();
|
|
||||||
|
|
||||||
virtual void closeHook();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void initialized();
|
void initialized();
|
||||||
void initializationFailed(const QString &reason);
|
void initializationFailed(const QString &reason);
|
||||||
@@ -72,6 +66,9 @@ private:
|
|||||||
SftpChannel *sftp);
|
SftpChannel *sftp);
|
||||||
SftpJobId createJob(const AbstractSftpOperation::Ptr &job);
|
SftpJobId createJob(const AbstractSftpOperation::Ptr &job);
|
||||||
|
|
||||||
|
virtual void handleChannelSuccess();
|
||||||
|
virtual void handleChannelFailure();
|
||||||
|
|
||||||
virtual void handleOpenSuccessInternal();
|
virtual void handleOpenSuccessInternal();
|
||||||
virtual void handleOpenFailureInternal(const QString &reason);
|
virtual void handleOpenFailureInternal(const QString &reason);
|
||||||
virtual void handleChannelDataInternal(const QByteArray &data);
|
virtual void handleChannelDataInternal(const QByteArray &data);
|
||||||
@@ -80,6 +77,8 @@ private:
|
|||||||
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus);
|
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus);
|
||||||
virtual void handleExitSignal(const SshChannelExitSignal &signal);
|
virtual void handleExitSignal(const SshChannelExitSignal &signal);
|
||||||
|
|
||||||
|
virtual void closeHook();
|
||||||
|
|
||||||
void handleCurrentPacket();
|
void handleCurrentPacket();
|
||||||
void handleServerVersion();
|
void handleServerVersion();
|
||||||
void handleHandle();
|
void handleHandle();
|
||||||
|
@@ -29,7 +29,8 @@ SOURCES = $$PWD/sshsendfacility.cpp \
|
|||||||
$$PWD/sshconnectionmanager.cpp \
|
$$PWD/sshconnectionmanager.cpp \
|
||||||
$$PWD/sshkeypasswordretriever.cpp \
|
$$PWD/sshkeypasswordretriever.cpp \
|
||||||
$$PWD/sftpfilesystemmodel.cpp \
|
$$PWD/sftpfilesystemmodel.cpp \
|
||||||
$$PWD/sshkeycreationdialog.cpp
|
$$PWD/sshkeycreationdialog.cpp \
|
||||||
|
$$PWD/sshdirecttcpiptunnel.cpp
|
||||||
|
|
||||||
HEADERS = $$PWD/sshsendfacility_p.h \
|
HEADERS = $$PWD/sshsendfacility_p.h \
|
||||||
$$PWD/sshremoteprocess.h \
|
$$PWD/sshremoteprocess.h \
|
||||||
@@ -62,6 +63,8 @@ HEADERS = $$PWD/sshsendfacility_p.h \
|
|||||||
$$PWD/sshkeypasswordretriever_p.h \
|
$$PWD/sshkeypasswordretriever_p.h \
|
||||||
$$PWD/sftpfilesystemmodel.h \
|
$$PWD/sftpfilesystemmodel.h \
|
||||||
$$PWD/sshkeycreationdialog.h \
|
$$PWD/sshkeycreationdialog.h \
|
||||||
$$PWD/ssh_global.h
|
$$PWD/ssh_global.h \
|
||||||
|
$$PWD/sshdirecttcpiptunnel_p.h \
|
||||||
|
$$PWD/sshdirecttcpiptunnel.h
|
||||||
|
|
||||||
FORMS = $$PWD/sshkeycreationdialog.ui
|
FORMS = $$PWD/sshkeycreationdialog.ui
|
||||||
|
@@ -35,6 +35,7 @@ QtcLibrary {
|
|||||||
"sshpacket.cpp", "sshpacket_p.h",
|
"sshpacket.cpp", "sshpacket_p.h",
|
||||||
"sshpacketparser.cpp", "sshpacketparser_p.h",
|
"sshpacketparser.cpp", "sshpacketparser_p.h",
|
||||||
"sshremoteprocess.cpp", "sshremoteprocess.h", "sshremoteprocess_p.h",
|
"sshremoteprocess.cpp", "sshremoteprocess.h", "sshremoteprocess_p.h",
|
||||||
|
"sshdirecttcpiptunnel.h", "sshdirecttcpiptunnel_p.h", "sshdirecttcpiptunnel.cpp",
|
||||||
"sshremoteprocessrunner.cpp", "sshremoteprocessrunner.h",
|
"sshremoteprocessrunner.cpp", "sshremoteprocessrunner.h",
|
||||||
"sshsendfacility.cpp", "sshsendfacility_p.h",
|
"sshsendfacility.cpp", "sshsendfacility_p.h",
|
||||||
"sshkeypasswordretriever.cpp",
|
"sshkeypasswordretriever.cpp",
|
||||||
|
@@ -40,18 +40,14 @@
|
|||||||
namespace QSsh {
|
namespace QSsh {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
namespace {
|
const quint32 MinMaxPacketSize = 32768;
|
||||||
const quint32 MinMaxPacketSize = 32768;
|
const quint32 NoChannel = 0xffffffffu;
|
||||||
const quint32 MaxPacketSize = 16 * 1024 * 1024;
|
|
||||||
const quint32 InitialWindowSize = MaxPacketSize;
|
|
||||||
const quint32 NoChannel = 0xffffffffu;
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
AbstractSshChannel::AbstractSshChannel(quint32 channelId,
|
AbstractSshChannel::AbstractSshChannel(quint32 channelId,
|
||||||
SshSendFacility &sendFacility)
|
SshSendFacility &sendFacility)
|
||||||
: m_sendFacility(sendFacility), m_timeoutTimer(new QTimer(this)),
|
: m_sendFacility(sendFacility), m_timeoutTimer(new QTimer(this)),
|
||||||
m_localChannel(channelId), m_remoteChannel(NoChannel),
|
m_localChannel(channelId), m_remoteChannel(NoChannel),
|
||||||
m_localWindowSize(InitialWindowSize), m_remoteWindowSize(0),
|
m_localWindowSize(initialWindowSize()), m_remoteWindowSize(0),
|
||||||
m_state(Inactive)
|
m_state(Inactive)
|
||||||
{
|
{
|
||||||
m_timeoutTimer->setSingleShot(true);
|
m_timeoutTimer->setSingleShot(true);
|
||||||
@@ -77,8 +73,7 @@ void AbstractSshChannel::requestSessionStart()
|
|||||||
// with our cryptography stuff, it would have hit us before, on
|
// with our cryptography stuff, it would have hit us before, on
|
||||||
// establishing the connection.
|
// establishing the connection.
|
||||||
try {
|
try {
|
||||||
m_sendFacility.sendSessionPacket(m_localChannel, InitialWindowSize,
|
m_sendFacility.sendSessionPacket(m_localChannel, initialWindowSize(), maxPacketSize());
|
||||||
MaxPacketSize);
|
|
||||||
setChannelState(SessionRequested);
|
setChannelState(SessionRequested);
|
||||||
m_timeoutTimer->start(ReplyTimeout);
|
m_timeoutTimer->start(ReplyTimeout);
|
||||||
} catch (Botan::Exception &e) {
|
} 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)
|
void AbstractSshChannel::handleWindowAdjust(quint32 bytesToAdd)
|
||||||
{
|
{
|
||||||
checkChannelActive();
|
checkChannelActive();
|
||||||
@@ -174,6 +179,7 @@ void AbstractSshChannel::handleChannelEof()
|
|||||||
"Unexpected SSH_MSG_CHANNEL_EOF message.");
|
"Unexpected SSH_MSG_CHANNEL_EOF message.");
|
||||||
}
|
}
|
||||||
m_localWindowSize = 0;
|
m_localWindowSize = 0;
|
||||||
|
emit eof();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractSshChannel::handleChannelClose()
|
void AbstractSshChannel::handleChannelClose()
|
||||||
@@ -224,10 +230,9 @@ int AbstractSshChannel::handleChannelOrExtendedChannelData(const QByteArray &dat
|
|||||||
qWarning("Misbehaving server does not respect local window, clipping.");
|
qWarning("Misbehaving server does not respect local window, clipping.");
|
||||||
|
|
||||||
m_localWindowSize -= bytesToDeliver;
|
m_localWindowSize -= bytesToDeliver;
|
||||||
if (m_localWindowSize < MaxPacketSize) {
|
if (m_localWindowSize < maxPacketSize()) {
|
||||||
m_localWindowSize += MaxPacketSize;
|
m_localWindowSize += maxPacketSize();
|
||||||
m_sendFacility.sendWindowAdjustPacket(m_remoteChannel,
|
m_sendFacility.sendWindowAdjustPacket(m_remoteChannel, maxPacketSize());
|
||||||
MaxPacketSize);
|
|
||||||
}
|
}
|
||||||
return bytesToDeliver;
|
return bytesToDeliver;
|
||||||
}
|
}
|
||||||
@@ -256,7 +261,7 @@ void AbstractSshChannel::checkChannelActive()
|
|||||||
|
|
||||||
quint32 AbstractSshChannel::maxDataSize() const
|
quint32 AbstractSshChannel::maxDataSize() const
|
||||||
{
|
{
|
||||||
return qMin(m_localWindowSize, MaxPacketSize);
|
return qMin(m_localWindowSize, maxPacketSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -53,17 +53,12 @@ public:
|
|||||||
Inactive, SessionRequested, SessionEstablished, CloseRequested, Closed
|
Inactive, SessionRequested, SessionEstablished, CloseRequested, Closed
|
||||||
};
|
};
|
||||||
|
|
||||||
ChannelState channelState() const { return m_state; }
|
|
||||||
void setChannelState(ChannelState state);
|
|
||||||
|
|
||||||
quint32 localChannelId() const { return m_localChannel; }
|
quint32 localChannelId() const { return m_localChannel; }
|
||||||
quint32 remoteChannel() const { return m_remoteChannel; }
|
quint32 remoteChannel() const { return m_remoteChannel; }
|
||||||
|
|
||||||
virtual void handleChannelSuccess() = 0;
|
virtual void handleChannelSuccess() = 0;
|
||||||
virtual void handleChannelFailure() = 0;
|
virtual void handleChannelFailure() = 0;
|
||||||
|
|
||||||
virtual void closeHook() = 0;
|
|
||||||
|
|
||||||
void handleOpenSuccess(quint32 remoteChannelId, quint32 remoteWindowSize,
|
void handleOpenSuccess(quint32 remoteChannelId, quint32 remoteWindowSize,
|
||||||
quint32 remoteMaxPacketSize);
|
quint32 remoteMaxPacketSize);
|
||||||
void handleOpenFailure(const QString &reason);
|
void handleOpenFailure(const QString &reason);
|
||||||
@@ -74,8 +69,6 @@ public:
|
|||||||
void handleChannelExtendedData(quint32 type, const QByteArray &data);
|
void handleChannelExtendedData(quint32 type, const QByteArray &data);
|
||||||
void handleChannelRequest(const SshIncomingPacket &packet);
|
void handleChannelRequest(const SshIncomingPacket &packet);
|
||||||
|
|
||||||
void requestSessionStart();
|
|
||||||
void sendData(const QByteArray &data);
|
|
||||||
void closeChannel();
|
void closeChannel();
|
||||||
|
|
||||||
virtual ~AbstractSshChannel();
|
virtual ~AbstractSshChannel();
|
||||||
@@ -84,10 +77,20 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void timeout();
|
void timeout();
|
||||||
|
void eof();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AbstractSshChannel(quint32 channelId, SshSendFacility &sendFacility);
|
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;
|
quint32 maxDataSize() const;
|
||||||
void checkChannelActive();
|
void checkChannelActive();
|
||||||
|
|
||||||
@@ -103,7 +106,8 @@ private:
|
|||||||
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus) = 0;
|
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus) = 0;
|
||||||
virtual void handleExitSignal(const SshChannelExitSignal &signal) = 0;
|
virtual void handleExitSignal(const SshChannelExitSignal &signal) = 0;
|
||||||
|
|
||||||
void setState(ChannelState newState);
|
virtual void closeHook() = 0;
|
||||||
|
|
||||||
void flushSendBuffer();
|
void flushSendBuffer();
|
||||||
int handleChannelOrExtendedChannelData(const QByteArray &data);
|
int handleChannelOrExtendedChannelData(const QByteArray &data);
|
||||||
|
|
||||||
|
@@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
#include "sftpchannel.h"
|
#include "sftpchannel.h"
|
||||||
#include "sftpchannel_p.h"
|
#include "sftpchannel_p.h"
|
||||||
|
#include "sshdirecttcpiptunnel.h"
|
||||||
|
#include "sshdirecttcpiptunnel_p.h"
|
||||||
#include "sshincomingpacket_p.h"
|
#include "sshincomingpacket_p.h"
|
||||||
#include "sshremoteprocess.h"
|
#include "sshremoteprocess.h"
|
||||||
#include "sshremoteprocess_p.h"
|
#include "sshremoteprocess_p.h"
|
||||||
@@ -168,6 +170,15 @@ QSsh::SftpChannel::Ptr SshChannelManager::createSftpChannel()
|
|||||||
return sftp;
|
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,
|
void SshChannelManager::insertChannel(AbstractSshChannel *priv,
|
||||||
const QSharedPointer<QObject> &pub)
|
const QSharedPointer<QObject> &pub)
|
||||||
{
|
{
|
||||||
|
@@ -36,8 +36,9 @@
|
|||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
|
||||||
namespace QSsh {
|
namespace QSsh {
|
||||||
|
|
||||||
class SftpChannel;
|
class SftpChannel;
|
||||||
|
class SshConnectionInfo;
|
||||||
|
class SshDirectTcpIpTunnel;
|
||||||
class SshRemoteProcess;
|
class SshRemoteProcess;
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -55,8 +56,10 @@ public:
|
|||||||
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
|
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
|
||||||
QSharedPointer<SshRemoteProcess> createRemoteShell();
|
QSharedPointer<SshRemoteProcess> createRemoteShell();
|
||||||
QSharedPointer<SftpChannel> createSftpChannel();
|
QSharedPointer<SftpChannel> createSftpChannel();
|
||||||
int channelCount() const;
|
QSharedPointer<SshDirectTcpIpTunnel> createTunnel(quint16 remotePort,
|
||||||
|
const SshConnectionInfo &connectionInfo);
|
||||||
|
|
||||||
|
int channelCount() const;
|
||||||
enum CloseAllMode { CloseAllRegular, CloseAllAndReset };
|
enum CloseAllMode { CloseAllRegular, CloseAllAndReset };
|
||||||
int closeAllChannels(CloseAllMode mode);
|
int closeAllChannels(CloseAllMode mode);
|
||||||
|
|
||||||
|
@@ -35,8 +35,10 @@
|
|||||||
#include "sshcapabilities_p.h"
|
#include "sshcapabilities_p.h"
|
||||||
#include "sshchannelmanager_p.h"
|
#include "sshchannelmanager_p.h"
|
||||||
#include "sshcryptofacility_p.h"
|
#include "sshcryptofacility_p.h"
|
||||||
|
#include "sshdirecttcpiptunnel.h"
|
||||||
#include "sshexception_p.h"
|
#include "sshexception_p.h"
|
||||||
#include "sshkeyexchange_p.h"
|
#include "sshkeyexchange_p.h"
|
||||||
|
#include "sshremoteprocess.h"
|
||||||
|
|
||||||
#include <botan/botan.h>
|
#include <botan/botan.h>
|
||||||
|
|
||||||
@@ -191,6 +193,12 @@ QSharedPointer<SftpChannel> SshConnection::createSftpChannel()
|
|||||||
return d->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()
|
int SshConnection::closeAllChannels()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -730,6 +738,11 @@ QSharedPointer<SftpChannel> SshConnectionPrivate::createSftpChannel()
|
|||||||
return m_channelManager->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);
|
const quint64 SshConnectionPrivate::InvalidSeqNr = static_cast<quint64>(-1);
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -43,6 +43,7 @@
|
|||||||
|
|
||||||
namespace QSsh {
|
namespace QSsh {
|
||||||
class SftpChannel;
|
class SftpChannel;
|
||||||
|
class SshDirectTcpIpTunnel;
|
||||||
class SshRemoteProcess;
|
class SshRemoteProcess;
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -103,6 +104,7 @@ public:
|
|||||||
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
|
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
|
||||||
QSharedPointer<SshRemoteProcess> createRemoteShell();
|
QSharedPointer<SshRemoteProcess> createRemoteShell();
|
||||||
QSharedPointer<SftpChannel> createSftpChannel();
|
QSharedPointer<SftpChannel> createSftpChannel();
|
||||||
|
QSharedPointer<SshDirectTcpIpTunnel> createTunnel(quint16 remotePort);
|
||||||
|
|
||||||
// -1 if an error occurred, number of channels closed otherwise.
|
// -1 if an error occurred, number of channels closed otherwise.
|
||||||
int closeAllChannels();
|
int closeAllChannels();
|
||||||
|
@@ -34,7 +34,6 @@
|
|||||||
#include "sshconnection.h"
|
#include "sshconnection.h"
|
||||||
#include "sshexception_p.h"
|
#include "sshexception_p.h"
|
||||||
#include "sshincomingpacket_p.h"
|
#include "sshincomingpacket_p.h"
|
||||||
#include "sshremoteprocess.h"
|
|
||||||
#include "sshsendfacility_p.h"
|
#include "sshsendfacility_p.h"
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
@@ -50,6 +49,8 @@ QT_END_NAMESPACE
|
|||||||
|
|
||||||
namespace QSsh {
|
namespace QSsh {
|
||||||
class SftpChannel;
|
class SftpChannel;
|
||||||
|
class SshRemoteProcess;
|
||||||
|
class SshDirectTcpIpTunnel;
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
class SshChannelManager;
|
class SshChannelManager;
|
||||||
@@ -88,6 +89,8 @@ public:
|
|||||||
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
|
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
|
||||||
QSharedPointer<SshRemoteProcess> createRemoteShell();
|
QSharedPointer<SshRemoteProcess> createRemoteShell();
|
||||||
QSharedPointer<SftpChannel> createSftpChannel();
|
QSharedPointer<SftpChannel> createSftpChannel();
|
||||||
|
QSharedPointer<SshDirectTcpIpTunnel> createTunnel(quint16 remotePort);
|
||||||
|
|
||||||
SshStateInternal state() const { return m_state; }
|
SshStateInternal state() const { return m_state; }
|
||||||
SshError error() const { return m_error; }
|
SshError error() const { return m_error; }
|
||||||
QString errorString() const { return m_errorString; }
|
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();
|
.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,
|
void SshOutgoingPacket::generateEnvPacket(quint32 remoteChannel,
|
||||||
const QByteArray &var, const QByteArray &value)
|
const QByteArray &var, const QByteArray &value)
|
||||||
{
|
{
|
||||||
|
@@ -62,6 +62,9 @@ public:
|
|||||||
void generateInvalidMessagePacket();
|
void generateInvalidMessagePacket();
|
||||||
void generateSessionPacket(quint32 channelId, quint32 windowSize,
|
void generateSessionPacket(quint32 channelId, quint32 windowSize,
|
||||||
quint32 maxPacketSize);
|
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,
|
void generateEnvPacket(quint32 remoteChannel, const QByteArray &var,
|
||||||
const QByteArray &value);
|
const QByteArray &value);
|
||||||
void generatePtyRequestPacket(quint32 remoteChannel,
|
void generatePtyRequestPacket(quint32 remoteChannel,
|
||||||
|
@@ -167,6 +167,7 @@ void SshRemoteProcess::init()
|
|||||||
connect(d, SIGNAL(readyReadStandardError()), this,
|
connect(d, SIGNAL(readyReadStandardError()), this,
|
||||||
SIGNAL(readyReadStandardError()), Qt::QueuedConnection);
|
SIGNAL(readyReadStandardError()), Qt::QueuedConnection);
|
||||||
connect(d, SIGNAL(closed(int)), this, SIGNAL(closed(int)), 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)
|
void SshRemoteProcess::addToEnvironment(const QByteArray &var, const QByteArray &value)
|
||||||
|
@@ -54,13 +54,6 @@ public:
|
|||||||
NotYetStarted, ExecRequested, StartFailed, Running, Exited
|
NotYetStarted, ExecRequested, StartFailed, Running, Exited
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void handleChannelSuccess();
|
|
||||||
virtual void handleChannelFailure();
|
|
||||||
|
|
||||||
virtual void closeHook();
|
|
||||||
|
|
||||||
QByteArray &data();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void started();
|
void started();
|
||||||
void readyRead();
|
void readyRead();
|
||||||
@@ -74,6 +67,9 @@ private:
|
|||||||
SshRemoteProcessPrivate(quint32 channelId, SshSendFacility &sendFacility,
|
SshRemoteProcessPrivate(quint32 channelId, SshSendFacility &sendFacility,
|
||||||
SshRemoteProcess *proc);
|
SshRemoteProcess *proc);
|
||||||
|
|
||||||
|
virtual void handleChannelSuccess();
|
||||||
|
virtual void handleChannelFailure();
|
||||||
|
|
||||||
virtual void handleOpenSuccessInternal();
|
virtual void handleOpenSuccessInternal();
|
||||||
virtual void handleOpenFailureInternal(const QString &reason);
|
virtual void handleOpenFailureInternal(const QString &reason);
|
||||||
virtual void handleChannelDataInternal(const QByteArray &data);
|
virtual void handleChannelDataInternal(const QByteArray &data);
|
||||||
@@ -82,8 +78,11 @@ private:
|
|||||||
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus);
|
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus);
|
||||||
virtual void handleExitSignal(const SshChannelExitSignal &signal);
|
virtual void handleExitSignal(const SshChannelExitSignal &signal);
|
||||||
|
|
||||||
|
virtual void closeHook();
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void setProcState(ProcessState newState);
|
void setProcState(ProcessState newState);
|
||||||
|
QByteArray &data();
|
||||||
|
|
||||||
QProcess::ProcessChannel m_readChannel;
|
QProcess::ProcessChannel m_readChannel;
|
||||||
|
|
||||||
|
@@ -150,6 +150,15 @@ void SshSendFacility::sendSessionPacket(quint32 channelId, quint32 windowSize,
|
|||||||
sendPacket();
|
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,
|
void SshSendFacility::sendPtyRequestPacket(quint32 remoteChannel,
|
||||||
const SshPseudoTerminal &terminal)
|
const SshPseudoTerminal &terminal)
|
||||||
{
|
{
|
||||||
|
@@ -69,6 +69,9 @@ public:
|
|||||||
void sendInvalidPacket();
|
void sendInvalidPacket();
|
||||||
void sendSessionPacket(quint32 channelId, quint32 windowSize,
|
void sendSessionPacket(quint32 channelId, quint32 windowSize,
|
||||||
quint32 maxPacketSize);
|
quint32 maxPacketSize);
|
||||||
|
void sendDirectTcpIpPacket(quint32 channelId, quint32 windowSize, quint32 maxPacketSize,
|
||||||
|
const QByteArray &remoteHost, quint32 remotePort, const QByteArray &localIpAddress,
|
||||||
|
quint32 localPort);
|
||||||
void sendPtyRequestPacket(quint32 remoteChannel,
|
void sendPtyRequestPacket(quint32 remoteChannel,
|
||||||
const SshPseudoTerminal &terminal);
|
const SshPseudoTerminal &terminal);
|
||||||
void sendEnvPacket(quint32 remoteChannel, const QByteArray &var,
|
void sendEnvPacket(quint32 remoteChannel, const QByteArray &var,
|
||||||
|
@@ -71,10 +71,10 @@ private:
|
|||||||
const QSsh::SshConnectionParameters m_sshParams;
|
const QSsh::SshConnectionParameters m_sshParams;
|
||||||
QTimer * const m_timeoutTimer;
|
QTimer * const m_timeoutTimer;
|
||||||
QTextStream *m_textStream;
|
QTextStream *m_textStream;
|
||||||
QSsh::SshRemoteProcessRunner * const m_remoteRunner;
|
|
||||||
QSsh::SshRemoteProcess::Ptr m_catProcess;
|
QSsh::SshRemoteProcess::Ptr m_catProcess;
|
||||||
QSsh::SshRemoteProcess::Ptr m_echoProcess;
|
QSsh::SshRemoteProcess::Ptr m_echoProcess;
|
||||||
QSsh::SshConnection *m_sshConnection;
|
QSsh::SshConnection *m_sshConnection;
|
||||||
|
QSsh::SshRemoteProcessRunner * const m_remoteRunner;
|
||||||
QByteArray m_remoteStdout;
|
QByteArray m_remoteStdout;
|
||||||
QByteArray m_remoteStderr;
|
QByteArray m_remoteStderr;
|
||||||
QByteArray m_remoteData;
|
QByteArray m_remoteData;
|
||||||
|
@@ -5,4 +5,4 @@
|
|||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
|
|
||||||
TEMPLATE = subdirs
|
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