Merge PR #16: Allow multiple tunnels for one valid token
commit
a8a10f80d5
|
|
@ -129,6 +129,11 @@ void ProxyClient::setName(const QString &name)
|
|||
m_name = name;
|
||||
}
|
||||
|
||||
QString ProxyClient::tunnelIdentifier() const
|
||||
{
|
||||
return m_token + m_nonce;
|
||||
}
|
||||
|
||||
QString ProxyClient::token() const
|
||||
{
|
||||
return m_token;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ public:
|
|||
QString name() const;
|
||||
void setName(const QString &name);
|
||||
|
||||
QString tunnelIdentifier() const;
|
||||
|
||||
QString token() const;
|
||||
void setToken(const QString &token);
|
||||
|
||||
|
|
|
|||
|
|
@ -147,13 +147,13 @@ void ProxyServer::saveStatistics()
|
|||
|
||||
ProxyClient *ProxyServer::getRemoteClient(ProxyClient *proxyClient)
|
||||
{
|
||||
if (!m_tunnels.contains(proxyClient->token()))
|
||||
if (!m_tunnels.contains(proxyClient->tunnelIdentifier()))
|
||||
return nullptr;
|
||||
|
||||
if (proxyClient == m_tunnels.value(proxyClient->token()).clientOne()) {
|
||||
return m_tunnels.value(proxyClient->token()).clientTwo();
|
||||
} else if (proxyClient == m_tunnels.value(proxyClient->token()).clientTwo()) {
|
||||
return m_tunnels.value(proxyClient->token()).clientOne();
|
||||
if (proxyClient == m_tunnels.value(proxyClient->tunnelIdentifier()).clientOne()) {
|
||||
return m_tunnels.value(proxyClient->tunnelIdentifier()).clientTwo();
|
||||
} else if (proxyClient == m_tunnels.value(proxyClient->tunnelIdentifier()).clientTwo()) {
|
||||
return m_tunnels.value(proxyClient->tunnelIdentifier()).clientOne();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
|
@ -169,7 +169,7 @@ void ProxyServer::establishTunnel(ProxyClient *firstClient, ProxyClient *secondC
|
|||
//FIXME:
|
||||
}
|
||||
|
||||
m_tunnels.insert(tunnel.token(), tunnel);
|
||||
m_tunnels.insert(tunnel.tunnelIdentifier(), tunnel);
|
||||
|
||||
// Tell both clients the tunnel has been established
|
||||
QVariantMap notificationParamsFirst;
|
||||
|
|
@ -241,11 +241,11 @@ void ProxyServer::onClientDisconnected(const QUuid &clientId)
|
|||
m_jsonRpcServer->unregisterClient(proxyClient);
|
||||
|
||||
// Check if
|
||||
if (m_tunnels.contains(proxyClient->token())) {
|
||||
if (m_tunnels.contains(proxyClient->tunnelIdentifier())) {
|
||||
|
||||
// There is a tunnel connection for this client, remove the tunnel and disconnect also the other client
|
||||
ProxyClient *remoteClient = getRemoteClient(proxyClient);
|
||||
TunnelConnection tunnelConnection = m_tunnels.take(proxyClient->token());
|
||||
TunnelConnection tunnelConnection = m_tunnels.take(proxyClient->tunnelIdentifier());
|
||||
Engine::instance()->logEngine()->logTunnel(tunnelConnection);
|
||||
if (remoteClient) {
|
||||
remoteClient->killConnection("Tunnel client disconnected");
|
||||
|
|
@ -285,7 +285,7 @@ void ProxyServer::onClientDataAvailable(const QUuid &clientId, const QByteArray
|
|||
if (proxyClient->isAuthenticated() && proxyClient->isTunnelConnected()) {
|
||||
ProxyClient *remoteClient = getRemoteClient(proxyClient);
|
||||
Q_ASSERT_X(remoteClient, "ProxyServer", "Tunnel existing but not tunnel client available");
|
||||
Q_ASSERT_X(m_tunnels.contains(proxyClient->token()), "ProxyServer", "Tunnel connect but not existing");
|
||||
Q_ASSERT_X(m_tunnels.contains(proxyClient->tunnelIdentifier()), "ProxyServer", "Tunnel connect but not existing");
|
||||
|
||||
// Calculate server statisitcs
|
||||
m_troughputCounter += data.count();
|
||||
|
|
@ -310,18 +310,17 @@ void ProxyServer::onProxyClientAuthenticated()
|
|||
|
||||
qCDebug(dcProxyServer()) << "Client authenticated" << proxyClient;
|
||||
|
||||
// Check if we already have a tunnel for this token
|
||||
if (m_tunnels.contains(proxyClient->token())) {
|
||||
// A new connection attempt with the same token, kill the old tunnel
|
||||
// connection and allow the new connection to stablish the tunnel
|
||||
qCWarning(dcProxyServer()) << "New authenticated client which already has a tunnel connection. Closing and clean up the old tunnel.";
|
||||
//FIXME: limit the amount of connection with one token
|
||||
|
||||
TunnelConnection tunnel = m_tunnels.take(proxyClient->token());
|
||||
qCDebug(dcProxyServer()) << "Killing " << tunnel;
|
||||
tunnel.clientOne()->killConnection("Clean up for new connection.");
|
||||
tunnel.clientTwo()->killConnection("Clean up for new connection.");
|
||||
// Check if we already have a tunnel with this identifier
|
||||
if (m_tunnels.contains(proxyClient->tunnelIdentifier())) {
|
||||
qCWarning(dcProxyServer()) << "There is already a tunnel with this token and nonce. The client has to take a new nonce or a new token.";
|
||||
// There is already a tunnel with this token and nonce. Reject the connection
|
||||
proxyClient->killConnection("Tunnel already exists for this token nonce combination.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: for backwards compatibility
|
||||
if (proxyClient->nonce().isEmpty()) {
|
||||
// Check if we have an other authenticated client with this token
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ private:
|
|||
// FIXME: Token, ProxyClient
|
||||
QHash<QString, ProxyClient *> m_authenticatedClients;
|
||||
|
||||
// Nonce, ProxyClient
|
||||
// TunnelIdentifier (token + nonce), ProxyClient
|
||||
QHash<QString, ProxyClient *> m_authenticatedClientsNonce;
|
||||
|
||||
// Token, Tunnel
|
||||
|
|
|
|||
|
|
@ -46,6 +46,22 @@ QString TunnelConnection::token() const
|
|||
return m_clientOne->token();
|
||||
}
|
||||
|
||||
QString TunnelConnection::nonce() const
|
||||
{
|
||||
if (!isValid())
|
||||
return QString();
|
||||
|
||||
return m_clientOne->nonce();
|
||||
}
|
||||
|
||||
QString TunnelConnection::tunnelIdentifier() const
|
||||
{
|
||||
if (!isValid())
|
||||
return QString();
|
||||
|
||||
return m_clientOne->tunnelIdentifier();
|
||||
}
|
||||
|
||||
uint TunnelConnection::creationTime() const
|
||||
{
|
||||
return m_creationTimeStamp;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ public:
|
|||
TunnelConnection(ProxyClient *clientOne = nullptr, ProxyClient *clientTwo = nullptr);
|
||||
|
||||
QString token() const;
|
||||
QString nonce() const;
|
||||
QString tunnelIdentifier() const;
|
||||
|
||||
uint creationTime() const;
|
||||
QString creationTimeString() const;
|
||||
|
|
|
|||
|
|
@ -699,6 +699,36 @@ void RemoteProxyOfflineTests::remoteConnection()
|
|||
stopServer();
|
||||
}
|
||||
|
||||
void RemoteProxyOfflineTests::multipleRemoteConnection()
|
||||
{
|
||||
// Start the server
|
||||
startServer();
|
||||
|
||||
// Configure moch authenticator
|
||||
m_mockAuthenticator->setExpectedAuthenticationError();
|
||||
m_mockAuthenticator->setTimeoutDuration(1000);
|
||||
m_configuration->setAuthenticationTimeout(2000);
|
||||
m_configuration->setJsonRpcTimeout(5000);
|
||||
m_configuration->setInactiveTimeout(5000);
|
||||
|
||||
// Create multiple tunnels with one token, but different nonces for each connection
|
||||
QObject *parent = new QObject(this);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
qDebug() << "============== Create remote connection" << i;
|
||||
bool connectionResult = createRemoteConnection(m_testToken, QUuid::createUuid().toString(), parent);
|
||||
if (!connectionResult) {
|
||||
qWarning() << "Test failed because could not create remote connection";
|
||||
delete parent;
|
||||
}
|
||||
QVERIFY(connectionResult);
|
||||
}
|
||||
|
||||
delete parent;
|
||||
|
||||
// Clean up
|
||||
stopServer();
|
||||
}
|
||||
|
||||
void RemoteProxyOfflineTests::trippleConnection()
|
||||
{
|
||||
// Start the server
|
||||
|
|
@ -708,6 +738,8 @@ void RemoteProxyOfflineTests::trippleConnection()
|
|||
m_mockAuthenticator->setTimeoutDuration(100);
|
||||
m_mockAuthenticator->setExpectedAuthenticationError();
|
||||
|
||||
QString nonce = QUuid::createUuid().toString();
|
||||
|
||||
// Create two connection
|
||||
RemoteProxyConnection *connectionOne = new RemoteProxyConnection(QUuid::createUuid(), "Test client one", this);
|
||||
connect(connectionOne, &RemoteProxyConnection::sslErrors, this, &BaseTest::ignoreConnectionSslError);
|
||||
|
|
@ -720,7 +752,6 @@ void RemoteProxyOfflineTests::trippleConnection()
|
|||
|
||||
// Connect one
|
||||
QSignalSpy connectionOneReadySpy(connectionOne, &RemoteProxyConnection::ready);
|
||||
QSignalSpy connectionOneDisconnectedSpy(connectionOne, &RemoteProxyConnection::disconnected);
|
||||
QVERIFY(connectionOne->connectServer(m_serverUrl));
|
||||
connectionOneReadySpy.wait();
|
||||
QVERIFY(connectionOneReadySpy.count() == 1);
|
||||
|
|
@ -728,7 +759,6 @@ void RemoteProxyOfflineTests::trippleConnection()
|
|||
|
||||
// Connect two
|
||||
QSignalSpy connectionTwoReadySpy(connectionTwo, &RemoteProxyConnection::ready);
|
||||
QSignalSpy connectionTwoDisconnectedSpy(connectionTwo, &RemoteProxyConnection::disconnected);
|
||||
QVERIFY(connectionTwo->connectServer(m_serverUrl));
|
||||
connectionTwoReadySpy.wait();
|
||||
QVERIFY(connectionTwoReadySpy.count() == 1);
|
||||
|
|
@ -736,7 +766,7 @@ void RemoteProxyOfflineTests::trippleConnection()
|
|||
|
||||
// Authenticate one
|
||||
QSignalSpy connectionOneAuthenticatedSpy(connectionOne, &RemoteProxyConnection::authenticated);
|
||||
QVERIFY(connectionOne->authenticate(m_testToken));
|
||||
QVERIFY(connectionOne->authenticate(m_testToken, nonce));
|
||||
connectionOneAuthenticatedSpy.wait();
|
||||
QVERIFY(connectionOneAuthenticatedSpy.count() == 1);
|
||||
QVERIFY(connectionOne->isConnected());
|
||||
|
|
@ -748,7 +778,7 @@ void RemoteProxyOfflineTests::trippleConnection()
|
|||
// Authenticate two
|
||||
QSignalSpy remoteConnectionEstablishedTwo(connectionTwo, &RemoteProxyConnection::remoteConnectionEstablished);
|
||||
QSignalSpy connectionTwoAuthenticatedSpy(connectionTwo, &RemoteProxyConnection::authenticated);
|
||||
QVERIFY(connectionTwo->authenticate(m_testToken));
|
||||
QVERIFY(connectionTwo->authenticate(m_testToken, nonce));
|
||||
connectionTwoAuthenticatedSpy.wait();
|
||||
QVERIFY(connectionTwoAuthenticatedSpy.count() == 1);
|
||||
QVERIFY(connectionTwo->isConnected());
|
||||
|
|
@ -757,10 +787,11 @@ void RemoteProxyOfflineTests::trippleConnection()
|
|||
// Wait for both to be connected
|
||||
remoteConnectionEstablishedOne.wait(500);
|
||||
|
||||
// Now connect a third connection and make sure the tunnel gets closed
|
||||
// Now connect a third connection and make sure the client will be closed
|
||||
|
||||
// Connect three
|
||||
QSignalSpy connectionThreeReadySpy(connectionThree, &RemoteProxyConnection::ready);
|
||||
QSignalSpy connectionThreeDisconnectedSpy(connectionThree, &RemoteProxyConnection::disconnected);
|
||||
QVERIFY(connectionThree->connectServer(m_serverUrl));
|
||||
connectionThreeReadySpy.wait();
|
||||
QVERIFY(connectionThreeReadySpy.count() == 1);
|
||||
|
|
@ -768,17 +799,16 @@ void RemoteProxyOfflineTests::trippleConnection()
|
|||
|
||||
// Authenticate three
|
||||
QSignalSpy connectionThreeAuthenticatedSpy(connectionThree, &RemoteProxyConnection::authenticated);
|
||||
QVERIFY(connectionThree->authenticate(m_testToken));
|
||||
QVERIFY(connectionThree->authenticate(m_testToken, nonce));
|
||||
connectionThreeAuthenticatedSpy.wait();
|
||||
QVERIFY(connectionOneAuthenticatedSpy.count() == 1);
|
||||
|
||||
connectionOneDisconnectedSpy.wait(200);
|
||||
connectionTwoDisconnectedSpy.wait(200);
|
||||
connectionThreeDisconnectedSpy.wait(200);
|
||||
QVERIFY(connectionThreeDisconnectedSpy.count() >= 1);
|
||||
|
||||
QVERIFY(connectionOneDisconnectedSpy.count() >= 1);
|
||||
QVERIFY(connectionTwoDisconnectedSpy.count() >= 1);
|
||||
QVERIFY(connectionOne->state() == RemoteProxyConnection::StateDisconnected);
|
||||
QVERIFY(connectionTwo->state() == RemoteProxyConnection::StateDisconnected);
|
||||
// Make sure the one and two are still connected
|
||||
QVERIFY(connectionOne->state() == RemoteProxyConnection::StateRemoteConnected);
|
||||
QVERIFY(connectionTwo->state() == RemoteProxyConnection::StateRemoteConnected);
|
||||
|
||||
// Clean up
|
||||
stopServer();
|
||||
|
|
@ -885,6 +915,9 @@ void RemoteProxyOfflineTests::jsonRpcTimeout()
|
|||
// Configure result (authentication takes longer than json rpc timeout
|
||||
m_mockAuthenticator->setExpectedAuthenticationError();
|
||||
m_mockAuthenticator->setTimeoutDuration(4000);
|
||||
m_configuration->setAuthenticationTimeout(4000);
|
||||
m_configuration->setJsonRpcTimeout(1000);
|
||||
m_configuration->setInactiveTimeout(2000);
|
||||
|
||||
// Create request
|
||||
QVariantMap params;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ private slots:
|
|||
// Client lib
|
||||
void clientConnection();
|
||||
void remoteConnection();
|
||||
void multipleRemoteConnection();
|
||||
void trippleConnection();
|
||||
void duplicateUuid();
|
||||
void sslConfigurations();
|
||||
|
|
|
|||
|
|
@ -195,6 +195,119 @@ QVariant BaseTest::injectSocketData(const QByteArray &data)
|
|||
return QVariant();
|
||||
}
|
||||
|
||||
bool BaseTest::createRemoteConnection(const QString &token, const QString &nonce, QObject *parent)
|
||||
{
|
||||
// Configure mock authenticator
|
||||
m_mockAuthenticator->setTimeoutDuration(100);
|
||||
m_mockAuthenticator->setExpectedAuthenticationError();
|
||||
|
||||
QString nameConnectionOne = "Test client one";
|
||||
QUuid uuidConnectionOne = QUuid::createUuid();
|
||||
|
||||
QString nameConnectionTwo = "Test client two";
|
||||
QUuid uuidConnectionTwo = QUuid::createUuid();
|
||||
|
||||
QByteArray dataOne = "Hello from client one :-)";
|
||||
QByteArray dataTwo = "Hello from client two :-)";
|
||||
|
||||
// Create two connection
|
||||
RemoteProxyConnection *connectionOne = new RemoteProxyConnection(uuidConnectionOne, nameConnectionOne, parent);
|
||||
connect(connectionOne, &RemoteProxyConnection::sslErrors, this, &BaseTest::ignoreConnectionSslError);
|
||||
|
||||
RemoteProxyConnection *connectionTwo = new RemoteProxyConnection(uuidConnectionTwo, nameConnectionTwo, parent);
|
||||
connect(connectionTwo, &RemoteProxyConnection::sslErrors, this, &BaseTest::ignoreConnectionSslError);
|
||||
|
||||
// Connect one
|
||||
QSignalSpy connectionOneReadySpy(connectionOne, &RemoteProxyConnection::ready);
|
||||
if (!connectionOne->connectServer(m_serverUrl)) {
|
||||
qWarning() << "Could not connect client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
connectionOneReadySpy.wait();
|
||||
if (connectionOneReadySpy.count() != 1) {
|
||||
qWarning() << "Could not connect client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!connectionOne->isConnected()) {
|
||||
qWarning() << "Could not connect client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Connect two
|
||||
QSignalSpy connectionTwoReadySpy(connectionTwo, &RemoteProxyConnection::ready);
|
||||
if (!connectionTwo->connectServer(m_serverUrl)) {
|
||||
qWarning() << "Could not connect client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
connectionTwoReadySpy.wait();
|
||||
if (connectionTwoReadySpy.count() != 1) {
|
||||
qWarning() << "Could not connect client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!connectionTwo->isConnected()) {
|
||||
qWarning() << "Could not connect client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Authenticate one
|
||||
QSignalSpy remoteConnectionEstablishedOne(connectionOne, &RemoteProxyConnection::remoteConnectionEstablished);
|
||||
QSignalSpy connectionOneAuthenticatedSpy(connectionOne, &RemoteProxyConnection::authenticated);
|
||||
if (!connectionOne->authenticate(token, nonce)) {
|
||||
qWarning() << "Could not authenticate client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
connectionOneAuthenticatedSpy.wait(500);
|
||||
if (connectionOneAuthenticatedSpy.count() != 1) {
|
||||
qWarning() << "Could not authenticate client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connectionOne->state() != RemoteProxyConnection::StateAuthenticated) {
|
||||
qWarning() << "Could not authenticate client one";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Authenticate two
|
||||
QSignalSpy remoteConnectionEstablishedTwo(connectionTwo, &RemoteProxyConnection::remoteConnectionEstablished);
|
||||
QSignalSpy connectionTwoAuthenticatedSpy(connectionTwo, &RemoteProxyConnection::authenticated);
|
||||
if (!connectionTwo->authenticate(token, nonce)) {
|
||||
qWarning() << "Could not authenticate client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
connectionTwoAuthenticatedSpy.wait(500);
|
||||
if (connectionTwoAuthenticatedSpy.count() != 1) {
|
||||
qWarning() << "Could not authenticate client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connectionTwo->state() != RemoteProxyConnection::StateAuthenticated && connectionTwo->state() != RemoteProxyConnection::StateRemoteConnected) {
|
||||
qWarning() << "Could not authenticate client two";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for both to be connected
|
||||
remoteConnectionEstablishedOne.wait(500);
|
||||
remoteConnectionEstablishedTwo.wait(500);
|
||||
|
||||
if (remoteConnectionEstablishedOne.count() != 1 || remoteConnectionEstablishedTwo.count() != 1) {
|
||||
qWarning() << "Could not establish remote connection";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connectionOne->state() != RemoteProxyConnection::StateRemoteConnected || connectionTwo->state() != RemoteProxyConnection::StateRemoteConnected) {
|
||||
qWarning() << "Could not establish remote connection";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BaseTest::initTestCase()
|
||||
{
|
||||
qRegisterMetaType<RemoteProxyConnection::State>();
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ protected:
|
|||
QVariant invokeApiCall(const QString &method, const QVariantMap params = QVariantMap(), bool remainsConnected = true);
|
||||
QVariant injectSocketData(const QByteArray &data);
|
||||
|
||||
bool createRemoteConnection(const QString &token, const QString &nonce, QObject *parent);
|
||||
|
||||
protected slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
|
|
|
|||
Loading…
Reference in New Issue