diff options
| author | Remko Tronçon <git@el-tramo.be> | 2009-11-25 19:19:28 (GMT) |
|---|---|---|
| committer | Remko Tronçon <git@el-tramo.be> | 2009-11-25 19:20:53 (GMT) |
| commit | db00adc9810377500e6ab27900b29496a0d05afe (patch) | |
| tree | 0f13d821883e0e99e9b6e7f15c84e3371375cd96 | |
| parent | c198064db0a6444a24220eee65cbf747eb7fbfb0 (diff) | |
| download | swift-db00adc9810377500e6ab27900b29496a0d05afe.zip swift-db00adc9810377500e6ab27900b29496a0d05afe.tar.bz2 | |
Enabled stream compression again.
| -rw-r--r-- | Swift/Controllers/MainController.cpp | 5 | ||||
| -rw-r--r-- | Swift/QtUI/SConscript | 2 | ||||
| -rw-r--r-- | Swiften/Client/Client.cpp | 3 | ||||
| -rw-r--r-- | Swiften/Client/ClientError.h | 1 | ||||
| -rw-r--r-- | Swiften/Client/ClientSession.cpp | 17 | ||||
| -rw-r--r-- | Swiften/Client/ClientSession.h | 1 | ||||
| -rw-r--r-- | Swiften/Client/UnitTest/ClientSessionTest.cpp | 7 | ||||
| -rw-r--r-- | Swiften/Session/BasicSessionStream.cpp | 6 | ||||
| -rw-r--r-- | Swiften/Session/BasicSessionStream.h | 4 | ||||
| -rw-r--r-- | Swiften/Session/SessionStream.h | 2 |
10 files changed, 45 insertions, 3 deletions
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index 22d71e5..d94cadc 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -217,118 +217,119 @@ void MainController::sendPresence(boost::shared_ptr<Presence> presence) { if (presence->getType() == Presence::Unavailable) { logout(); } } void MainController::handleInputIdleChanged(bool idle) { if (!client_ || !client_->isAvailable()) { return; } if (idle) { preIdlePresence_ = lastSentPresence_; boost::shared_ptr<Presence> presence(new Presence()); presence->setShow(StatusShow::Away); presence->setStatus("Auto-away"); sendPresence(presence); } else { if (client_) { sendPresence(preIdlePresence_); } else { queuedPresence_ = preIdlePresence_; } } } void MainController::handleIncomingPresence(boost::shared_ptr<Presence> presence) { //FIXME: subscribe, subscribed rosterController_->handleIncomingPresence(presence); } void MainController::handleLoginRequest(const String &username, const String &password, const String& certificateFile, bool remember) { loginWindow_->setMessage(""); ProfileSettingsProvider* profileSettings = new ProfileSettingsProvider(username, settings_); profileSettings->storeString("jid", username); profileSettings->storeString("certificate", certificateFile); profileSettings->storeString("pass", remember ? password : ""); loginWindow_->addAvailableAccount(profileSettings->getStringSetting("jid"), profileSettings->getStringSetting("pass"), profileSettings->getStringSetting("certificate")); delete profileSettings; jid_ = JID(username); password_ = password; certificateFile_ = certificateFile; performLoginFromCachedCredentials(); } void MainController::performLoginFromCachedCredentials() { if (!client_) { client_ = new Swift::Client(jid_, password_); presenceSender_ = new PresenceSender(client_); - //client_->onDataRead.connect(&printIncomingData); - //client_->onDataWritten.connect(&printOutgoingData); + client_->onDataRead.connect(&printIncomingData); + client_->onDataWritten.connect(&printOutgoingData); if (!certificateFile_.isEmpty()) { client_->setCertificate(certificateFile_); } client_->onError.connect(boost::bind(&MainController::handleError, this, _1)); client_->onConnected.connect(boost::bind(&MainController::handleConnected, this)); client_->onMessageReceived.connect(boost::bind(&MainController::handleIncomingMessage, this, _1)); } client_->connect(); } void MainController::handleError(const ClientError& error) { String message; switch(error.getType()) { case ClientError::UnknownError: message = "Unknown Error"; break; case ClientError::DomainNameResolveError: message = "Unable to find server"; break; case ClientError::ConnectionError: message = "Error connecting to server"; break; case ClientError::ConnectionReadError: message = "Error while receiving server data"; break; case ClientError::ConnectionWriteError: message = "Error while sending data to the server"; break; case ClientError::XMLError: message = "Error parsing server data"; break; case ClientError::AuthenticationFailedError: message = "Login/password invalid"; break; + case ClientError::CompressionFailedError: message = "Error while compressing stream"; break; case ClientError::ServerVerificationFailedError: message = "Server verification failed"; break; case ClientError::NoSupportedAuthMechanismsError: message = "Authentication mechanisms not supported"; break; case ClientError::UnexpectedElementError: message = "Unexpected response"; break; case ClientError::ResourceBindError: message = "Error binding resource"; break; case ClientError::SessionStartError: message = "Error starting session"; break; case ClientError::TLSError: message = "Encryption error"; break; case ClientError::ClientCertificateLoadError: message = "Error loading certificate (Invalid password?)"; break; case ClientError::ClientCertificateError: message = "Certificate not authorized"; break; } if (!rosterController_) { //hasn't been logged in yet signOut(); loginWindow_->setMessage(message); } logout(); if (rosterController_) { //reconnectAfterError(); } } void MainController::handleCancelLoginRequest() { signOut(); } void MainController::signOut() { logout(); loginWindow_->loggedOut(); foreach (JIDChatControllerPair controllerPair, chatControllers_) { delete controllerPair.second; } chatControllers_.clear(); foreach (JIDMUCControllerPair controllerPair, mucControllers_) { delete controllerPair.second; } mucControllers_.clear(); delete rosterController_; rosterController_ = NULL; resetClient(); } void MainController::logout() { if (client_ && client_->isAvailable()) { client_->disconnect(); } if (rosterController_) { rosterController_->getWindow()->setMyStatusType(StatusShow::None); rosterController_->getWindow()->setMyStatusText(""); } setManagersEnabled(false); diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index 800a009..42cf07a 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -1,72 +1,74 @@ import os, shutil, datetime import Version def generateDefaultTheme(env, target, source) : sourceDir = source[0].abspath output = open(target[0].abspath, "w") output.write("<RCC version =\"1.0\">") output.write("<qresource prefix=\"/themes/Default\">") for (path, dirs, files) in os.walk(sourceDir) : for file in files : filePath = os.path.join(path,file) output.write("<file alias=\"%(alias)s\">%(path)s</file>" % { "alias": filePath[len(sourceDir)+1:], "path": filePath }) output.write("</qresource>") output.write("</RCC>") Import("env") myenv = env.Clone() myenv.MergeFlags(env["SWIFT_CONTROLLERS_FLAGS"]) myenv.MergeFlags(env["SWIFTOOLS_FLAGS"]) +if myenv["HAVE_XSS"] : + myenv.MergeFlags(env["XSS_FLAGS"]) myenv.MergeFlags(env["SWIFTEN_FLAGS"]) myenv.MergeFlags(env["CPPUNIT_FLAGS"]) myenv.MergeFlags(env["LIBIDN_FLAGS"]) myenv.MergeFlags(env["BOOST_FLAGS"]) myenv.MergeFlags(env["SQLITE_FLAGS"]) myenv.MergeFlags(env["ZLIB_FLAGS"]) myenv.MergeFlags(env["OPENSSL_FLAGS"]) myenv.MergeFlags(env.get("LIBXML_FLAGS", "")) myenv.MergeFlags(env.get("EXPAT_FLAGS", "")) myenv.Tool("qt4", toolpath = ["#/BuildTools/SCons/Tools"]) myenv.Tool("nsis", toolpath = ["#/BuildTools/SCons/Tools"]) myenv.EnableQt4Modules(['QtCore', 'QtGui', 'QtWebKit'], debug = False) myenv.Append(CPPPATH = ["/usr/include/phonon"]) myenv.Append(CPPPATH = ["."]) if env["PLATFORM"] == "win32" : #myenv["LINKFLAGS"] = ["/SUBSYSTEM:CONSOLE"] myenv.Append(LINKFLAGS = ["/SUBSYSTEM:WINDOWS"]) myenv.Append(LIBS = "qtmain") myenv.Command("DefaultTheme.qrc", "../resources/themes/Default", Action(generateDefaultTheme, cmdstr = "$GENCOMSTR")) sources = [ "main.cpp", "QtAboutWidget.cpp", "QtAddContactDialog.cpp", "QtChatWindow.cpp", "QtChatWindowFactory.cpp", "QtJoinMUCDialog.cpp", "QtLoginWindow.cpp", "QtLoginWindowFactory.cpp", "QtMainWindow.cpp", "QtMainWindowFactory.cpp", "QtSettingsProvider.cpp", "QtStatusWidget.cpp", "QtSwift.cpp", "QtChatView.cpp", "QtChatTabs.cpp", "QtSoundPlayer.cpp", "QtSystemTray.cpp", "QtTabbable.cpp", "QtTextEdit.cpp", "ChatSnippet.cpp", "MessageSnippet.cpp", "SystemMessageSnippet.cpp", "Roster/RosterModel.cpp", diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp index 3962281..19f7ee5 100644 --- a/Swiften/Client/Client.cpp +++ b/Swiften/Client/Client.cpp @@ -100,96 +100,99 @@ void Client::sendIQ(boost::shared_ptr<IQ> iq) { send(iq); } void Client::sendMessage(boost::shared_ptr<Message> message) { send(message); } void Client::sendPresence(boost::shared_ptr<Presence> presence) { send(presence); } String Client::getNewIQID() { return idGenerator_.generateID(); } void Client::handleElement(boost::shared_ptr<Element> element) { boost::shared_ptr<Message> message = boost::dynamic_pointer_cast<Message>(element); if (message) { onMessageReceived(message); return; } boost::shared_ptr<Presence> presence = boost::dynamic_pointer_cast<Presence>(element); if (presence) { onPresenceReceived(presence); return; } boost::shared_ptr<IQ> iq = boost::dynamic_pointer_cast<IQ>(element); if (iq) { onIQReceived(iq); return; } } void Client::setCertificate(const String& certificate) { certificate_ = certificate; } void Client::handleSessionFinished(boost::shared_ptr<Error> error) { closeConnection(); if (error) { ClientError clientError; if (boost::shared_ptr<ClientSession::Error> actualError = boost::dynamic_pointer_cast<ClientSession::Error>(error)) { switch(actualError->type) { case ClientSession::Error::AuthenticationFailedError: clientError = ClientError(ClientError::AuthenticationFailedError); break; + case ClientSession::Error::CompressionFailedError: + clientError = ClientError(ClientError::CompressionFailedError); + break; case ClientSession::Error::ServerVerificationFailedError: clientError = ClientError(ClientError::ServerVerificationFailedError); break; case ClientSession::Error::NoSupportedAuthMechanismsError: clientError = ClientError(ClientError::NoSupportedAuthMechanismsError); break; case ClientSession::Error::UnexpectedElementError: clientError = ClientError(ClientError::UnexpectedElementError); break; case ClientSession::Error::ResourceBindError: clientError = ClientError(ClientError::ResourceBindError); break; case ClientSession::Error::SessionStartError: clientError = ClientError(ClientError::SessionStartError); break; case ClientSession::Error::TLSError: clientError = ClientError(ClientError::TLSError); break; case ClientSession::Error::TLSClientCertificateError: clientError = ClientError(ClientError::ClientCertificateError); break; } } else if (boost::shared_ptr<SessionStream::Error> actualError = boost::dynamic_pointer_cast<SessionStream::Error>(error)) { switch(actualError->type) { case SessionStream::Error::ParseError: clientError = ClientError(ClientError::XMLError); break; case SessionStream::Error::TLSError: clientError = ClientError(ClientError::TLSError); break; case SessionStream::Error::InvalidTLSCertificateError: clientError = ClientError(ClientError::ClientCertificateLoadError); break; case SessionStream::Error::ConnectionReadError: clientError = ClientError(ClientError::ConnectionReadError); break; case SessionStream::Error::ConnectionWriteError: clientError = ClientError(ClientError::ConnectionWriteError); break; } } onError(clientError); } session_.reset(); } void Client::handleNeedCredentials() { diff --git a/Swiften/Client/ClientError.h b/Swiften/Client/ClientError.h index 55c57fc..a0557d4 100644 --- a/Swiften/Client/ClientError.h +++ b/Swiften/Client/ClientError.h @@ -1,31 +1,32 @@ #pragma once namespace Swift { class ClientError { public: enum Type { UnknownError, DomainNameResolveError, ConnectionError, ConnectionReadError, ConnectionWriteError, XMLError, AuthenticationFailedError, + CompressionFailedError, ServerVerificationFailedError, NoSupportedAuthMechanismsError, UnexpectedElementError, ResourceBindError, SessionStartError, TLSError, ClientCertificateLoadError, ClientCertificateError }; ClientError(Type type = UnknownError) : type_(type) {} Type getType() const { return type_; } private: Type type_; }; } diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index 61ce8ef..8427d27 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -1,170 +1,187 @@ #include "Swiften/Client/ClientSession.h" #include <boost/bind.hpp> #include "Swiften/Elements/ProtocolHeader.h" #include "Swiften/Elements/StreamFeatures.h" #include "Swiften/Elements/StartTLSRequest.h" #include "Swiften/Elements/StartTLSFailure.h" #include "Swiften/Elements/TLSProceed.h" #include "Swiften/Elements/AuthRequest.h" #include "Swiften/Elements/AuthSuccess.h" #include "Swiften/Elements/AuthFailure.h" #include "Swiften/Elements/AuthChallenge.h" #include "Swiften/Elements/AuthResponse.h" +#include "Swiften/Elements/Compressed.h" +#include "Swiften/Elements/CompressFailure.h" +#include "Swiften/Elements/CompressRequest.h" #include "Swiften/Elements/StartSession.h" #include "Swiften/Elements/IQ.h" #include "Swiften/Elements/ResourceBind.h" #include "Swiften/SASL/PLAINClientAuthenticator.h" #include "Swiften/SASL/SCRAMSHA1ClientAuthenticator.h" #include "Swiften/Session/SessionStream.h" namespace Swift { ClientSession::ClientSession( const JID& jid, boost::shared_ptr<SessionStream> stream) : localJID(jid), state(Initial), stream(stream), needSessionStart(false), authenticator(NULL) { } void ClientSession::start() { stream->onStreamStartReceived.connect(boost::bind(&ClientSession::handleStreamStart, shared_from_this(), _1)); stream->onElementReceived.connect(boost::bind(&ClientSession::handleElement, shared_from_this(), _1)); stream->onError.connect(boost::bind(&ClientSession::handleStreamError, shared_from_this(), _1)); stream->onTLSEncrypted.connect(boost::bind(&ClientSession::handleTLSEncrypted, shared_from_this())); assert(state == Initial); state = WaitingForStreamStart; sendStreamHeader(); } void ClientSession::sendStreamHeader() { ProtocolHeader header; header.setTo(getRemoteJID()); stream->writeHeader(header); } void ClientSession::sendElement(boost::shared_ptr<Element> element) { stream->writeElement(element); } void ClientSession::handleStreamStart(const ProtocolHeader&) { checkState(WaitingForStreamStart); state = Negotiating; } void ClientSession::handleElement(boost::shared_ptr<Element> element) { if (getState() == Initialized) { onElementReceived(element); } else if (StreamFeatures* streamFeatures = dynamic_cast<StreamFeatures*>(element.get())) { if (!checkState(Negotiating)) { return; } if (streamFeatures->hasStartTLS() && stream->supportsTLSEncryption()) { state = WaitingForEncrypt; stream->writeElement(boost::shared_ptr<StartTLSRequest>(new StartTLSRequest())); } + else if (streamFeatures->hasCompressionMethod("zlib")) { + state = Compressing; + stream->writeElement(boost::shared_ptr<CompressRequest>(new CompressRequest("zlib"))); + } else if (streamFeatures->hasAuthenticationMechanisms()) { if (stream->hasTLSCertificate()) { if (streamFeatures->hasAuthenticationMechanism("EXTERNAL")) { state = Authenticating; stream->writeElement(boost::shared_ptr<Element>(new AuthRequest("EXTERNAL", ""))); } else { finishSession(Error::TLSClientCertificateError); } } else if (streamFeatures->hasAuthenticationMechanism("SCRAM-SHA-1")) { // FIXME: Use a real nonce authenticator = new SCRAMSHA1ClientAuthenticator("ClientNonce"); state = WaitingForCredentials; onNeedCredentials(); } else if (streamFeatures->hasAuthenticationMechanism("PLAIN")) { authenticator = new PLAINClientAuthenticator(); state = WaitingForCredentials; onNeedCredentials(); } else { finishSession(Error::NoSupportedAuthMechanismsError); } } else { // Start the session stream->setWhitespacePingEnabled(true); if (streamFeatures->hasSession()) { needSessionStart = true; } if (streamFeatures->hasResourceBind()) { state = BindingResource; boost::shared_ptr<ResourceBind> resourceBind(new ResourceBind()); if (!localJID.getResource().isEmpty()) { resourceBind->setResource(localJID.getResource()); } stream->writeElement(IQ::createRequest(IQ::Set, JID(), "session-bind", resourceBind)); } else if (needSessionStart) { sendSessionStart(); } else { state = Initialized; onInitialized(); } } } + else if (boost::dynamic_pointer_cast<Compressed>(element)) { + checkState(Compressing); + state = WaitingForStreamStart; + stream->addZLibCompression(); + stream->resetXMPPParser(); + sendStreamHeader(); + } + else if (boost::dynamic_pointer_cast<CompressFailure>(element)) { + finishSession(Error::CompressionFailedError); + } else if (AuthChallenge* challenge = dynamic_cast<AuthChallenge*>(element.get())) { checkState(Authenticating); assert(authenticator); if (authenticator->setChallenge(challenge->getValue())) { stream->writeElement(boost::shared_ptr<AuthResponse>(new AuthResponse(authenticator->getResponse()))); } else { finishSession(Error::AuthenticationFailedError); } } else if (AuthSuccess* authSuccess = dynamic_cast<AuthSuccess*>(element.get())) { checkState(Authenticating); if (authenticator && !authenticator->setChallenge(authSuccess->getValue())) { finishSession(Error::ServerVerificationFailedError); } else { state = WaitingForStreamStart; delete authenticator; authenticator = NULL; stream->resetXMPPParser(); sendStreamHeader(); } } else if (dynamic_cast<AuthFailure*>(element.get())) { delete authenticator; authenticator = NULL; finishSession(Error::AuthenticationFailedError); } else if (dynamic_cast<TLSProceed*>(element.get())) { checkState(WaitingForEncrypt); state = Encrypting; stream->addTLSEncryption(); } else if (dynamic_cast<StartTLSFailure*>(element.get())) { finishSession(Error::TLSError); } else if (IQ* iq = dynamic_cast<IQ*>(element.get())) { if (state == BindingResource) { boost::shared_ptr<ResourceBind> resourceBind(iq->getPayload<ResourceBind>()); if (iq->getType() == IQ::Error && iq->getID() == "session-bind") { finishSession(Error::ResourceBindError); } else if (!resourceBind) { finishSession(Error::UnexpectedElementError); } else if (iq->getType() == IQ::Result) { localJID = resourceBind->getJID(); if (!localJID.isValid()) { diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h index 5e5acbc..ef4d747 100644 --- a/Swiften/Client/ClientSession.h +++ b/Swiften/Client/ClientSession.h @@ -1,84 +1,85 @@ #pragma once #include <boost/signal.hpp> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include "Swiften/Base/Error.h" #include "Swiften/Session/SessionStream.h" #include "Swiften/Session/BasicSessionStream.h" #include "Swiften/Base/String.h" #include "Swiften/JID/JID.h" #include "Swiften/Elements/Element.h" namespace Swift { class ClientAuthenticator; class ClientSession : public boost::enable_shared_from_this<ClientSession> { public: enum State { Initial, WaitingForStreamStart, Negotiating, Compressing, WaitingForEncrypt, Encrypting, WaitingForCredentials, Authenticating, BindingResource, StartingSession, Initialized, Finished }; struct Error : public Swift::Error { enum Type { AuthenticationFailedError, + CompressionFailedError, ServerVerificationFailedError, NoSupportedAuthMechanismsError, UnexpectedElementError, ResourceBindError, SessionStartError, TLSClientCertificateError, TLSError, } type; Error(Type type) : type(type) {} }; static boost::shared_ptr<ClientSession> create(const JID& jid, boost::shared_ptr<SessionStream> stream) { return boost::shared_ptr<ClientSession>(new ClientSession(jid, stream)); } State getState() const { return state; } void start(); void finish(); void sendCredentials(const String& password); void sendElement(boost::shared_ptr<Element> element); public: boost::signal<void ()> onNeedCredentials; boost::signal<void ()> onInitialized; boost::signal<void (boost::shared_ptr<Swift::Error>)> onFinished; boost::signal<void (boost::shared_ptr<Element>)> onElementReceived; private: ClientSession( const JID& jid, boost::shared_ptr<SessionStream>); void finishSession(Error::Type error); void finishSession(boost::shared_ptr<Swift::Error> error); JID getRemoteJID() const { return JID("", localJID.getDomain()); } void sendStreamHeader(); void sendSessionStart(); void handleElement(boost::shared_ptr<Element>); void handleStreamStart(const ProtocolHeader&); diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp index 9fe2a3d..e035ba3 100644 --- a/Swiften/Client/UnitTest/ClientSessionTest.cpp +++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp @@ -128,209 +128,214 @@ class ClientSessionTest : public CppUnit::TestFixture { server->sendAuthFailure(); CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState()); CPPUNIT_ASSERT(sessionFinishedReceived); CPPUNIT_ASSERT(sessionFinishedError); } void testAuthenticate_NoValidAuthMechanisms() { boost::shared_ptr<ClientSession> session(createSession()); session->start(); server->receiveStreamStart(); server->sendStreamStart(); server->sendStreamFeaturesWithUnknownAuthentication(); CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState()); CPPUNIT_ASSERT(sessionFinishedReceived); CPPUNIT_ASSERT(sessionFinishedError); } private: boost::shared_ptr<ClientSession> createSession() { boost::shared_ptr<ClientSession> session = ClientSession::create(JID("me@foo.com"), server); session->onFinished.connect(boost::bind(&ClientSessionTest::handleSessionFinished, this, _1)); session->onNeedCredentials.connect(boost::bind(&ClientSessionTest::handleSessionNeedCredentials, this)); return session; } void handleSessionFinished(boost::shared_ptr<Error> error) { sessionFinishedReceived = true; sessionFinishedError = error; } void handleSessionNeedCredentials() { needCredentials = true; } class MockSessionStream : public SessionStream { public: struct Event { Event(boost::shared_ptr<Element> element) : element(element), footer(false) {} Event(const ProtocolHeader& header) : header(header), footer(false) {} Event() : footer(true) {} boost::shared_ptr<Element> element; boost::optional<ProtocolHeader> header; bool footer; }; - MockSessionStream() : available(true), canTLSEncrypt(true), tlsEncrypted(false), whitespacePingEnabled(false), resetCount(0) { + MockSessionStream() : available(true), canTLSEncrypt(true), tlsEncrypted(false), compressed(false), whitespacePingEnabled(false), resetCount(0) { } virtual bool isAvailable() { return available; } virtual void writeHeader(const ProtocolHeader& header) { receivedEvents.push_back(Event(header)); } virtual void writeFooter() { receivedEvents.push_back(Event()); } virtual void writeElement(boost::shared_ptr<Element> element) { receivedEvents.push_back(Event(element)); } virtual bool supportsTLSEncryption() { return canTLSEncrypt; } virtual void addTLSEncryption() { tlsEncrypted = true; } + virtual void addZLibCompression() { + compressed = true; + } + virtual void setWhitespacePingEnabled(bool enabled) { whitespacePingEnabled = enabled; } virtual void resetXMPPParser() { resetCount++; } void breakConnection() { onError(boost::shared_ptr<SessionStream::Error>(new SessionStream::Error(SessionStream::Error::ConnectionReadError))); } void breakTLS() { onError(boost::shared_ptr<SessionStream::Error>(new SessionStream::Error(SessionStream::Error::TLSError))); } void sendStreamStart() { ProtocolHeader header; header.setTo("foo.com"); return onStreamStartReceived(header); } void sendStreamFeaturesWithStartTLS() { boost::shared_ptr<StreamFeatures> streamFeatures(new StreamFeatures()); streamFeatures->setHasStartTLS(); onElementReceived(streamFeatures); } void sendTLSProceed() { onElementReceived(boost::shared_ptr<TLSProceed>(new TLSProceed())); } void sendTLSFailure() { onElementReceived(boost::shared_ptr<StartTLSFailure>(new StartTLSFailure())); } void sendStreamFeaturesWithPLAINAuthentication() { boost::shared_ptr<StreamFeatures> streamFeatures(new StreamFeatures()); streamFeatures->addAuthenticationMechanism("PLAIN"); onElementReceived(streamFeatures); } void sendStreamFeaturesWithUnknownAuthentication() { boost::shared_ptr<StreamFeatures> streamFeatures(new StreamFeatures()); streamFeatures->addAuthenticationMechanism("UNKNOWN"); onElementReceived(streamFeatures); } void sendAuthSuccess() { onElementReceived(boost::shared_ptr<AuthSuccess>(new AuthSuccess())); } void sendAuthFailure() { onElementReceived(boost::shared_ptr<AuthFailure>(new AuthFailure())); } void receiveStreamStart() { Event event = popEvent(); CPPUNIT_ASSERT(event.header); } void receiveStartTLS() { Event event = popEvent(); CPPUNIT_ASSERT(event.element); CPPUNIT_ASSERT(boost::dynamic_pointer_cast<StartTLSRequest>(event.element)); } void receiveAuthRequest(const String& mech) { Event event = popEvent(); CPPUNIT_ASSERT(event.element); boost::shared_ptr<AuthRequest> request(boost::dynamic_pointer_cast<AuthRequest>(event.element)); CPPUNIT_ASSERT(request); CPPUNIT_ASSERT_EQUAL(mech, request->getMechanism()); } Event popEvent() { CPPUNIT_ASSERT(receivedEvents.size() > 0); Event event = receivedEvents.front(); receivedEvents.pop_front(); return event; } bool available; bool canTLSEncrypt; bool tlsEncrypted; + bool compressed; bool whitespacePingEnabled; int resetCount; std::deque<Event> receivedEvents; }; boost::shared_ptr<MockSessionStream> server; bool sessionFinishedReceived; bool needCredentials; boost::shared_ptr<Error> sessionFinishedError; }; CPPUNIT_TEST_SUITE_REGISTRATION(ClientSessionTest); #if 0 void testAuthenticate() { boost::shared_ptr<MockSession> session(createSession("me@foo.com/Bar")); session->onNeedCredentials.connect(boost::bind(&ClientSessionTest::setNeedCredentials, this)); getMockServer()->expectStreamStart(); getMockServer()->sendStreamStart(); getMockServer()->sendStreamFeaturesWithAuthentication(); session->startSession(); processEvents(); CPPUNIT_ASSERT_EQUAL(ClientSession::WaitingForCredentials, session->getState()); CPPUNIT_ASSERT(needCredentials_); getMockServer()->expectAuth("me", "mypass"); getMockServer()->sendAuthSuccess(); getMockServer()->expectStreamStart(); getMockServer()->sendStreamStart(); session->sendCredentials("mypass"); CPPUNIT_ASSERT_EQUAL(ClientSession::Authenticating, session->getState()); processEvents(); CPPUNIT_ASSERT_EQUAL(ClientSession::Negotiating, session->getState()); } void testAuthenticate_Unauthorized() { boost::shared_ptr<MockSession> session(createSession("me@foo.com/Bar")); getMockServer()->expectStreamStart(); getMockServer()->sendStreamStart(); getMockServer()->sendStreamFeaturesWithAuthentication(); session->startSession(); processEvents(); getMockServer()->expectAuth("me", "mypass"); getMockServer()->sendAuthFailure(); session->sendCredentials("mypass"); processEvents(); diff --git a/Swiften/Session/BasicSessionStream.cpp b/Swiften/Session/BasicSessionStream.cpp index 0d0f49f..ed7f1eb 100644 --- a/Swiften/Session/BasicSessionStream.cpp +++ b/Swiften/Session/BasicSessionStream.cpp @@ -1,124 +1,130 @@ #include "Swiften/Session/BasicSessionStream.h" #include <boost/bind.hpp> #include "Swiften/StreamStack/XMPPLayer.h" #include "Swiften/StreamStack/StreamStack.h" #include "Swiften/StreamStack/ConnectionLayer.h" #include "Swiften/StreamStack/WhitespacePingLayer.h" +#include "Swiften/StreamStack/CompressionLayer.h" #include "Swiften/StreamStack/TLSLayer.h" #include "Swiften/StreamStack/TLSLayerFactory.h" namespace Swift { BasicSessionStream::BasicSessionStream(boost::shared_ptr<Connection> connection, PayloadParserFactoryCollection* payloadParserFactories, PayloadSerializerCollection* payloadSerializers, TLSLayerFactory* tlsLayerFactory, TimerFactory* timerFactory) : available(false), connection(connection), payloadParserFactories(payloadParserFactories), payloadSerializers(payloadSerializers), tlsLayerFactory(tlsLayerFactory), timerFactory(timerFactory) { } void BasicSessionStream::initialize() { xmppLayer = boost::shared_ptr<XMPPLayer>( new XMPPLayer(payloadParserFactories, payloadSerializers)); xmppLayer->onStreamStart.connect(boost::bind(&BasicSessionStream::handleStreamStartReceived, shared_from_this(), _1)); xmppLayer->onElement.connect(boost::bind(&BasicSessionStream::handleElementReceived, shared_from_this(), _1)); xmppLayer->onError.connect(boost::bind( &BasicSessionStream::handleXMPPError, shared_from_this())); xmppLayer->onDataRead.connect(boost::bind(&BasicSessionStream::handleDataRead, shared_from_this(), _1)); xmppLayer->onWriteData.connect(boost::bind(&BasicSessionStream::handleDataWritten, shared_from_this(), _1)); connection->onDisconnected.connect(boost::bind(&BasicSessionStream::handleConnectionError, shared_from_this(), _1)); connectionLayer = boost::shared_ptr<ConnectionLayer>( new ConnectionLayer(connection)); streamStack = new StreamStack(xmppLayer, connectionLayer); available = true; } BasicSessionStream::~BasicSessionStream() { delete streamStack; } void BasicSessionStream::writeHeader(const ProtocolHeader& header) { assert(available); xmppLayer->writeHeader(header); } void BasicSessionStream::writeElement(boost::shared_ptr<Element> element) { assert(available); xmppLayer->writeElement(element); } void BasicSessionStream::writeFooter() { assert(available); xmppLayer->writeFooter(); } bool BasicSessionStream::isAvailable() { return available; } bool BasicSessionStream::supportsTLSEncryption() { return tlsLayerFactory && tlsLayerFactory->canCreate(); } void BasicSessionStream::addTLSEncryption() { assert(available); tlsLayer = tlsLayerFactory->createTLSLayer(); if (hasTLSCertificate() && !tlsLayer->setClientCertificate(getTLSCertificate())) { onError(boost::shared_ptr<Error>(new Error(Error::InvalidTLSCertificateError))); } else { streamStack->addLayer(tlsLayer); tlsLayer->onError.connect(boost::bind(&BasicSessionStream::handleTLSError, shared_from_this())); tlsLayer->onConnected.connect(boost::bind(&BasicSessionStream::handleTLSConnected, shared_from_this())); tlsLayer->connect(); } } +void BasicSessionStream::addZLibCompression() { + boost::shared_ptr<CompressionLayer> compressionLayer(new CompressionLayer()); + streamStack->addLayer(compressionLayer); +} + void BasicSessionStream::setWhitespacePingEnabled(bool enabled) { if (enabled) { if (!whitespacePingLayer) { whitespacePingLayer = boost::shared_ptr<WhitespacePingLayer>(new WhitespacePingLayer(timerFactory)); streamStack->addLayer(whitespacePingLayer); } whitespacePingLayer->setActive(); } else if (whitespacePingLayer) { whitespacePingLayer->setInactive(); } } void BasicSessionStream::resetXMPPParser() { xmppLayer->resetParser(); } void BasicSessionStream::handleStreamStartReceived(const ProtocolHeader& header) { onStreamStartReceived(header); } void BasicSessionStream::handleElementReceived(boost::shared_ptr<Element> element) { onElementReceived(element); } void BasicSessionStream::handleXMPPError() { available = false; onError(boost::shared_ptr<Error>(new Error(Error::ParseError))); } void BasicSessionStream::handleTLSConnected() { onTLSEncrypted(); } void BasicSessionStream::handleTLSError() { available = false; onError(boost::shared_ptr<Error>(new Error(Error::TLSError))); } void BasicSessionStream::handleConnectionError(const boost::optional<Connection::Error>& error) { available = false; if (error == Connection::ReadError) { onError(boost::shared_ptr<Error>(new Error(Error::ConnectionReadError))); } else { onError(boost::shared_ptr<Error>(new Error(Error::ConnectionWriteError))); } } diff --git a/Swiften/Session/BasicSessionStream.h b/Swiften/Session/BasicSessionStream.h index f36df83..8618458 100644 --- a/Swiften/Session/BasicSessionStream.h +++ b/Swiften/Session/BasicSessionStream.h @@ -1,71 +1,75 @@ #pragma once #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include "Swiften/Network/Connection.h" #include "Swiften/Session/SessionStream.h" namespace Swift { class TLSLayerFactory; class TLSLayer; class TimerFactory; class WhitespacePingLayer; class PayloadParserFactoryCollection; class PayloadSerializerCollection; class StreamStack; class XMPPLayer; class ConnectionLayer; + class CompressionLayer; class BasicSessionStream : public SessionStream, public boost::enable_shared_from_this<BasicSessionStream> { public: BasicSessionStream( boost::shared_ptr<Connection> connection, PayloadParserFactoryCollection* payloadParserFactories, PayloadSerializerCollection* payloadSerializers, TLSLayerFactory* tlsLayerFactory, TimerFactory* whitespacePingLayerFactory ); ~BasicSessionStream(); void initialize(); virtual bool isAvailable(); virtual void writeHeader(const ProtocolHeader& header); virtual void writeElement(boost::shared_ptr<Element>); virtual void writeFooter(); + virtual void addZLibCompression(); + virtual bool supportsTLSEncryption(); virtual void addTLSEncryption(); virtual void setWhitespacePingEnabled(bool); virtual void resetXMPPParser(); private: void handleConnectionError(const boost::optional<Connection::Error>& error); void handleXMPPError(); void handleTLSConnected(); void handleTLSError(); void handleStreamStartReceived(const ProtocolHeader&); void handleElementReceived(boost::shared_ptr<Element>); void handleDataRead(const ByteArray& data); void handleDataWritten(const ByteArray& data); private: bool available; boost::shared_ptr<Connection> connection; PayloadParserFactoryCollection* payloadParserFactories; PayloadSerializerCollection* payloadSerializers; TLSLayerFactory* tlsLayerFactory; TimerFactory* timerFactory; boost::shared_ptr<XMPPLayer> xmppLayer; boost::shared_ptr<ConnectionLayer> connectionLayer; StreamStack* streamStack; + boost::shared_ptr<CompressionLayer> compressionLayer; boost::shared_ptr<TLSLayer> tlsLayer; boost::shared_ptr<WhitespacePingLayer> whitespacePingLayer; }; } diff --git a/Swiften/Session/SessionStream.h b/Swiften/Session/SessionStream.h index 1252c5a..8c64ccf 100644 --- a/Swiften/Session/SessionStream.h +++ b/Swiften/Session/SessionStream.h @@ -1,67 +1,69 @@ #pragma once #include <boost/signal.hpp> #include <boost/shared_ptr.hpp> #include "Swiften/Elements/ProtocolHeader.h" #include "Swiften/Elements/Element.h" #include "Swiften/Base/Error.h" #include "Swiften/TLS/PKCS12Certificate.h" namespace Swift { class SessionStream { public: class Error : public Swift::Error { public: enum Type { ParseError, TLSError, InvalidTLSCertificateError, ConnectionReadError, ConnectionWriteError }; Error(Type type) : type(type) {} Type type; }; virtual ~SessionStream(); virtual bool isAvailable() = 0; virtual void writeHeader(const ProtocolHeader& header) = 0; virtual void writeFooter() = 0; virtual void writeElement(boost::shared_ptr<Element>) = 0; + virtual void addZLibCompression() = 0; + virtual bool supportsTLSEncryption() = 0; virtual void addTLSEncryption() = 0; virtual void setWhitespacePingEnabled(bool enabled) = 0; virtual void resetXMPPParser() = 0; void setTLSCertificate(const PKCS12Certificate& cert) { certificate = cert; } virtual bool hasTLSCertificate() { return !certificate.isNull(); } boost::signal<void (const ProtocolHeader&)> onStreamStartReceived; boost::signal<void (boost::shared_ptr<Element>)> onElementReceived; boost::signal<void (boost::shared_ptr<Error>)> onError; boost::signal<void ()> onTLSEncrypted; boost::signal<void (const String&)> onDataRead; boost::signal<void (const String&)> onDataWritten; protected: const PKCS12Certificate& getTLSCertificate() const { return certificate; } private: PKCS12Certificate certificate; }; } |
Swift