summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2016-07-29 09:47:23 (GMT)
committerTobias Markmann <tm@ayena.de>2016-11-28 10:35:05 (GMT)
commit2039930eadd4756068a8a60c8340d9908a7136d3 (patch)
treed8aca4bf98a2bb6e3b819305b1f87af3117f4910 /Swiften/Client/UnitTest
parent2f90eb7409df91a80c60b189242ac0c1de313910 (diff)
downloadswift-2039930eadd4756068a8a60c8340d9908a7136d3.zip
swift-2039930eadd4756068a8a60c8340d9908a7136d3.tar.bz2
Correctly handle server initiated closing of stream
If a server closes the XMPP stream, it sends a </stream:stream> tag. The client is supposed to respond with the same tag and then both parties can close the TLS/TCP socket. Previously Swift(-en) would simply ignore </stream:stream> tag if it was not directly followed by a shutdown of the TCP connection. In addition there is now a timeout timer started as soon as Swiften or the server initiates a shutdown. It will close the socket and cleanup the ClientSession if the server does not respond in time or the network is faulty. Refactored some code in ClientSession in the process. Moved ClientSession::State to a C++11 strongly typed enum class. This also fixes issues where duplicated </stream:stream> tags would be send by Swift. Test-Information: Tested against Prosody ba782a093b14 and M-Link 16.3v6-0, which provide ad-hoc commands to end a user session. Previously this was ignored by Swift. Now it correctly responds to the server, detects it as a disconnect and tries to reconnect afterwards. Added unit test for the case where the server closes the session stream. Change-Id: I59dfde3aa6b50dc117f340e5db6b9e58b54b3c60
Diffstat (limited to 'Swiften/Client/UnitTest')
-rw-r--r--Swiften/Client/UnitTest/ClientSessionTest.cpp111
1 files changed, 95 insertions, 16 deletions
diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp
index bd93f4b..44df961 100644
--- a/Swiften/Client/UnitTest/ClientSessionTest.cpp
+++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp
@@ -10,6 +10,8 @@
#include <boost/bind.hpp>
#include <boost/optional.hpp>
+#include <Swiften/Base/Debug.h>
+
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
@@ -34,6 +36,7 @@
#include <Swiften/Elements/TLSProceed.h>
#include <Swiften/IDN/IDNConverter.h>
#include <Swiften/IDN/PlatformIDNConverter.h>
+#include <Swiften/Network/DummyTimerFactory.h>
#include <Swiften/Session/SessionStream.h>
#include <Swiften/TLS/BlindCertificateTrustChecker.h>
#include <Swiften/TLS/SimpleCertificate.h>
@@ -59,6 +62,11 @@ class ClientSessionTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testStreamManagement_Failed);
CPPUNIT_TEST(testUnexpectedChallenge);
CPPUNIT_TEST(testFinishAcksStanzas);
+
+ CPPUNIT_TEST(testServerInitiatedSessionClose);
+ CPPUNIT_TEST(testClientInitiatedSessionClose);
+ CPPUNIT_TEST(testTimeoutOnShutdown);
+
/*
CPPUNIT_TEST(testResourceBind);
CPPUNIT_TEST(testResourceBind_ChangeResource);
@@ -77,6 +85,7 @@ class ClientSessionTest : public CppUnit::TestFixture {
void setUp() {
crypto = std::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
idnConverter = std::shared_ptr<IDNConverter>(PlatformIDNConverter::create());
+ timerFactory = std::make_shared<DummyTimerFactory>();
server = std::make_shared<MockSessionStream>();
sessionFinishedReceived = false;
needCredentials = false;
@@ -92,7 +101,7 @@ class ClientSessionTest : public CppUnit::TestFixture {
session->start();
server->breakConnection();
- CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
CPPUNIT_ASSERT(sessionFinishedReceived);
CPPUNIT_ASSERT(sessionFinishedError);
}
@@ -103,7 +112,11 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->sendStreamStart();
server->sendStreamError();
- CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finishing, session->getState());
+ CPPUNIT_ASSERT_EQUAL(true, server->receivedEvents.back().footer);
+
+ server->onStreamEndReceived();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
CPPUNIT_ASSERT(sessionFinishedReceived);
CPPUNIT_ASSERT(sessionFinishedError);
}
@@ -136,7 +149,11 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->sendTLSFailure();
CPPUNIT_ASSERT(!server->tlsEncrypted);
- CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finishing, session->getState());
+ CPPUNIT_ASSERT_EQUAL(true, server->receivedEvents.back().footer);
+
+ server->onStreamEndReceived();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
CPPUNIT_ASSERT(sessionFinishedReceived);
CPPUNIT_ASSERT(sessionFinishedError);
}
@@ -151,7 +168,7 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->sendTLSProceed();
server->breakTLS();
- CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
CPPUNIT_ASSERT(sessionFinishedReceived);
CPPUNIT_ASSERT(sessionFinishedError);
}
@@ -167,10 +184,12 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->sendTLSProceed();
CPPUNIT_ASSERT(server->tlsEncrypted);
server->onTLSEncrypted();
+ server->close();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
- CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState());
CPPUNIT_ASSERT(sessionFinishedReceived);
CPPUNIT_ASSERT(sessionFinishedError);
+ CPPUNIT_ASSERT(std::dynamic_pointer_cast<CertificateVerificationError>(sessionFinishedError));
CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::InvalidServerIdentity, std::dynamic_pointer_cast<CertificateVerificationError>(sessionFinishedError)->getType());
}
@@ -181,7 +200,11 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->sendStreamStart();
server->sendEmptyStreamFeatures();
- CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finishing, session->getState());
+ CPPUNIT_ASSERT_EQUAL(true, server->receivedEvents.back().footer);
+
+ server->onStreamEndReceived();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
CPPUNIT_ASSERT(sessionFinishedReceived);
CPPUNIT_ASSERT(sessionFinishedError);
}
@@ -193,7 +216,7 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->sendStreamStart();
server->sendStreamFeaturesWithPLAINAuthentication();
CPPUNIT_ASSERT(needCredentials);
- CPPUNIT_ASSERT_EQUAL(ClientSession::WaitingForCredentials, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::WaitingForCredentials, session->getState());
session->sendCredentials(createSafeByteArray("mypass"));
server->receiveAuthRequest("PLAIN");
server->sendAuthSuccess();
@@ -209,12 +232,16 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->sendStreamStart();
server->sendStreamFeaturesWithPLAINAuthentication();
CPPUNIT_ASSERT(needCredentials);
- CPPUNIT_ASSERT_EQUAL(ClientSession::WaitingForCredentials, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::WaitingForCredentials, session->getState());
session->sendCredentials(createSafeByteArray("mypass"));
server->receiveAuthRequest("PLAIN");
server->sendAuthFailure();
- CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finishing, session->getState());
+ CPPUNIT_ASSERT_EQUAL(true, server->receivedEvents.back().footer);
+
+ server->onStreamEndReceived();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
CPPUNIT_ASSERT(sessionFinishedReceived);
CPPUNIT_ASSERT(sessionFinishedError);
}
@@ -227,7 +254,11 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->sendStreamStart();
server->sendStreamFeaturesWithPLAINAuthentication();
- CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finishing, session->getState());
+ CPPUNIT_ASSERT_EQUAL(true, server->receivedEvents.back().footer);
+
+ server->onStreamEndReceived();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
CPPUNIT_ASSERT(sessionFinishedReceived);
CPPUNIT_ASSERT(sessionFinishedError);
}
@@ -240,8 +271,11 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->receiveStreamStart();
server->sendStreamStart();
server->sendStreamFeaturesWithMultipleAuthentication();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finishing, session->getState());
+ CPPUNIT_ASSERT_EQUAL(true, server->receivedEvents.back().footer);
- CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState());
+ server->onStreamEndReceived();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
CPPUNIT_ASSERT(sessionFinishedReceived);
CPPUNIT_ASSERT(sessionFinishedError);
}
@@ -253,7 +287,12 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->sendStreamStart();
server->sendStreamFeaturesWithUnknownAuthentication();
- CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finishing, session->getState());
+ CPPUNIT_ASSERT_EQUAL(true, server->receivedEvents.back().footer);
+
+ server->onStreamEndReceived();
+ server->close();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
CPPUNIT_ASSERT(sessionFinishedReceived);
CPPUNIT_ASSERT(sessionFinishedError);
}
@@ -281,7 +320,11 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->sendChallenge();
server->sendChallenge();
- CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finishing, session->getState());
+ CPPUNIT_ASSERT_EQUAL(true, server->receivedEvents.back().footer);
+
+ server->onStreamEndReceived();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
CPPUNIT_ASSERT(sessionFinishedReceived);
CPPUNIT_ASSERT(sessionFinishedError);
}
@@ -305,7 +348,7 @@ class ClientSessionTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(session->getStreamManagementEnabled());
// TODO: Test if the requesters & responders do their work
- CPPUNIT_ASSERT_EQUAL(ClientSession::Initialized, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Initialized, session->getState());
session->finish();
}
@@ -328,7 +371,7 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->sendStreamManagementFailed();
CPPUNIT_ASSERT(!session->getStreamManagementEnabled());
- CPPUNIT_ASSERT_EQUAL(ClientSession::Initialized, session->getState());
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Initialized, session->getState());
session->finish();
}
@@ -345,9 +388,44 @@ class ClientSessionTest : public CppUnit::TestFixture {
server->receiveAck(3);
}
+ void testServerInitiatedSessionClose() {
+ std::shared_ptr<ClientSession> session(createSession());
+ initializeSession(session);
+
+ server->onStreamEndReceived();
+ server->close();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
+ CPPUNIT_ASSERT_EQUAL(true, server->receivedEvents.back().footer);
+ }
+
+ void testClientInitiatedSessionClose() {
+ std::shared_ptr<ClientSession> session(createSession());
+ initializeSession(session);
+
+ session->finish();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finishing, session->getState());
+ CPPUNIT_ASSERT_EQUAL(true, server->receivedEvents.back().footer);
+
+ server->onStreamEndReceived();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
+ }
+
+ void testTimeoutOnShutdown() {
+ std::shared_ptr<ClientSession> session(createSession());
+ initializeSession(session);
+
+ session->finish();
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finishing, session->getState());
+ CPPUNIT_ASSERT_EQUAL(true, server->receivedEvents.back().footer);
+ timerFactory->setTime(60000);
+
+ CPPUNIT_ASSERT_EQUAL(ClientSession::State::Finished, session->getState());
+ CPPUNIT_ASSERT(sessionFinishedReceived);
+ }
+
private:
std::shared_ptr<ClientSession> createSession() {
- std::shared_ptr<ClientSession> session = ClientSession::create(JID("me@foo.com"), server, idnConverter.get(), crypto.get());
+ std::shared_ptr<ClientSession> session = ClientSession::create(JID("me@foo.com"), server, idnConverter.get(), crypto.get(), timerFactory.get());
session->onFinished.connect(boost::bind(&ClientSessionTest::handleSessionFinished, this, _1));
session->onNeedCredentials.connect(boost::bind(&ClientSessionTest::handleSessionNeedCredentials, this));
session->setAllowPLAINOverNonTLS(true);
@@ -631,6 +709,7 @@ class ClientSessionTest : public CppUnit::TestFixture {
std::shared_ptr<Error> sessionFinishedError;
BlindCertificateTrustChecker* blindCertificateTrustChecker;
std::shared_ptr<CryptoProvider> crypto;
+ std::shared_ptr<DummyTimerFactory> timerFactory;
};
CPPUNIT_TEST_SUITE_REGISTRATION(ClientSessionTest);