diff options
Diffstat (limited to 'Swiften/Client')
-rw-r--r-- | Swiften/Client/Client.cpp | 205 | ||||
-rw-r--r-- | Swiften/Client/Client.h | 99 | ||||
-rw-r--r-- | Swiften/Client/CoreClient.cpp | 217 | ||||
-rw-r--r-- | Swiften/Client/CoreClient.h | 111 |
4 files changed, 331 insertions, 301 deletions
diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp index 120a8fb..44804be 100644 --- a/Swiften/Client/Client.cpp +++ b/Swiften/Client/Client.cpp @@ -6,212 +6,9 @@ #include "Swiften/Client/Client.h" -#include <boost/bind.hpp> - -#include "Swiften/Network/MainBoostIOServiceThread.h" -#include "Swiften/Network/BoostIOServiceThread.h" -#include "Swiften/Client/ClientSession.h" -#include "Swiften/StreamStack/PlatformTLSLayerFactory.h" -#include "Swiften/Network/Connector.h" -#include "Swiften/Network/BoostConnectionFactory.h" -#include "Swiften/Network/BoostTimerFactory.h" -#include "Swiften/TLS/PKCS12Certificate.h" -#include "Swiften/Session/BasicSessionStream.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Base/IDGenerator.h" -#include "Swiften/Client/ClientSessionStanzaChannel.h" - namespace Swift { -Client::Client(const JID& jid, const String& password) : jid_(jid), password_(password), disconnectRequested_(false) { - stanzaChannel_ = new ClientSessionStanzaChannel(); - stanzaChannel_->onMessageReceived.connect(boost::ref(onMessageReceived)); - stanzaChannel_->onPresenceReceived.connect(boost::ref(onPresenceReceived)); - stanzaChannel_->onStanzaAcked.connect(boost::ref(onStanzaAcked)); - stanzaChannel_->onAvailableChanged.connect(boost::bind(&Client::handleStanzaChannelAvailableChanged, this, _1)); - - iqRouter_ = new IQRouter(stanzaChannel_); - connectionFactory_ = new BoostConnectionFactory(&MainBoostIOServiceThread::getInstance().getIOService()); - timerFactory_ = new BoostTimerFactory(&MainBoostIOServiceThread::getInstance().getIOService()); - tlsLayerFactory_ = new PlatformTLSLayerFactory(); -} - -Client::~Client() { - if (session_ || connection_) { - std::cerr << "Warning: Client not disconnected properly" << std::endl; - } - delete tlsLayerFactory_; - delete timerFactory_; - delete connectionFactory_; - delete iqRouter_; - - stanzaChannel_->onAvailableChanged.disconnect(boost::bind(&Client::handleStanzaChannelAvailableChanged, this, _1)); - stanzaChannel_->onMessageReceived.disconnect(boost::ref(onMessageReceived)); - stanzaChannel_->onPresenceReceived.disconnect(boost::ref(onPresenceReceived)); - stanzaChannel_->onStanzaAcked.disconnect(boost::ref(onStanzaAcked)); - delete stanzaChannel_; -} - -void Client::connect() { - connect(jid_.getDomain()); -} - -void Client::connect(const JID& jid) { - jid_ = jid; - connect(); -} - -void Client::connect(const String& host) { - assert(!connector_); - connector_ = Connector::create(host, &resolver_, connectionFactory_, timerFactory_); - connector_->onConnectFinished.connect(boost::bind(&Client::handleConnectorFinished, this, _1)); - connector_->setTimeoutMilliseconds(60*1000); - connector_->start(); -} - -void Client::handleConnectorFinished(boost::shared_ptr<Connection> connection) { - connector_->onConnectFinished.disconnect(boost::bind(&Client::handleConnectorFinished, this, _1)); - connector_.reset(); - if (!connection) { - if (!disconnectRequested_) { - onError(ClientError::ConnectionError); - } - } - else { - assert(!connection_); - connection_ = connection; - - assert(!sessionStream_); - sessionStream_ = boost::shared_ptr<BasicSessionStream>(new BasicSessionStream(connection_, &payloadParserFactories_, &payloadSerializers_, tlsLayerFactory_, timerFactory_)); - if (!certificate_.isEmpty()) { - sessionStream_->setTLSCertificate(PKCS12Certificate(certificate_, password_)); - } - sessionStream_->onDataRead.connect(boost::bind(&Client::handleDataRead, this, _1)); - sessionStream_->onDataWritten.connect(boost::bind(&Client::handleDataWritten, this, _1)); - sessionStream_->initialize(); - - session_ = ClientSession::create(jid_, sessionStream_); - stanzaChannel_->setSession(session_); - session_->onFinished.connect(boost::bind(&Client::handleSessionFinished, this, _1)); - session_->onNeedCredentials.connect(boost::bind(&Client::handleNeedCredentials, this)); - session_->start(); - } -} - -void Client::disconnect() { - // FIXME: We should be able to do without this boolean. We just have to make sure we can tell the difference between - // connector finishing without a connection due to an error or because of a disconnect. - disconnectRequested_ = true; - if (session_) { - session_->finish(); - } - else if (connector_) { - connector_->stop(); - assert(!session_); - } - assert(!session_); - assert(!sessionStream_); - assert(!connector_); - disconnectRequested_ = false; -} - -void Client::setCertificate(const String& certificate) { - certificate_ = certificate; -} - -void Client::handleSessionFinished(boost::shared_ptr<Error> error) { - session_->onFinished.disconnect(boost::bind(&Client::handleSessionFinished, this, _1)); - session_->onNeedCredentials.disconnect(boost::bind(&Client::handleNeedCredentials, this)); - session_.reset(); - - sessionStream_->onDataRead.disconnect(boost::bind(&Client::handleDataRead, this, _1)); - sessionStream_->onDataWritten.disconnect(boost::bind(&Client::handleDataWritten, this, _1)); - sessionStream_.reset(); - - connection_->disconnect(); - connection_.reset(); - - 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); - } -} - -void Client::handleNeedCredentials() { - assert(session_); - session_->sendCredentials(password_); -} - -void Client::handleDataRead(const String& data) { - onDataRead(data); -} - -void Client::handleDataWritten(const String& data) { - onDataWritten(data); -} - -void Client::handleStanzaChannelAvailableChanged(bool available) { - if (available) { - onConnected(); - } -} - -void Client::sendMessage(boost::shared_ptr<Message> message) { - stanzaChannel_->sendMessage(message); -} - -void Client::sendPresence(boost::shared_ptr<Presence> presence) { - stanzaChannel_->sendPresence(presence); +Client::Client(const JID& jid, const String& password) : CoreClient(jid, password) { } } diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h index 4319eaa..7609eb8 100644 --- a/Swiften/Client/Client.h +++ b/Swiften/Client/Client.h @@ -6,106 +6,11 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" -#include <boost/shared_ptr.hpp> - -#include "Swiften/Network/PlatformDomainNameResolver.h" -#include "Swiften/Network/Connector.h" -#include "Swiften/Base/Error.h" -#include "Swiften/Client/ClientSession.h" -#include "Swiften/Client/ClientError.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/JID/JID.h" -#include "Swiften/Base/String.h" -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" -#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" -#include "Swiften/Base/Shared.h" -#include "Swiften/Client/ClientSessionStanzaChannel.h" +#include "Swiften/Client/CoreClient.h" namespace Swift { - class IQRouter; - class TLSLayerFactory; - class ConnectionFactory; - class TimerFactory; - class ClientSession; - class BasicSessionStream; - - class Client { + class Client : public CoreClient { public: Client(const JID& jid, const String& password); - ~Client(); - - void setCertificate(const String& certificate); - - void connect(); - void connect(const JID& jid); - void connect(const String& host); - void disconnect(); - - void sendMessage(boost::shared_ptr<Message>); - void sendPresence(boost::shared_ptr<Presence>); - - IQRouter* getIQRouter() const { - return iqRouter_; - } - - StanzaChannel* getStanzaChannel() const { - return stanzaChannel_; - } - - bool isAvailable() const { - return stanzaChannel_->isAvailable(); - } - - /** - * Returns the JID of the client. - * After the session was initialized, this returns the bound JID. - */ - const JID& getJID() const { - if (session_) { - return session_->getLocalJID(); - } - else { - return jid_; - } - } - - public: - boost::signal<void (const ClientError&)> onError; - boost::signal<void ()> onConnected; - boost::signal<void (const String&)> onDataRead; - boost::signal<void (const String&)> onDataWritten; - - boost::signal<void (boost::shared_ptr<Message>)> onMessageReceived; - boost::signal<void (boost::shared_ptr<Presence>) > onPresenceReceived; - boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaAcked; - - private: - void handleConnectorFinished(boost::shared_ptr<Connection>); - void handleStanzaChannelAvailableChanged(bool available); - void handleSessionFinished(boost::shared_ptr<Error>); - void handleNeedCredentials(); - void handleDataRead(const String&); - void handleDataWritten(const String&); - - private: - PlatformDomainNameResolver resolver_; - JID jid_; - String password_; - ClientSessionStanzaChannel* stanzaChannel_; - IQRouter* iqRouter_; - Connector::ref connector_; - ConnectionFactory* connectionFactory_; - TimerFactory* timerFactory_; - TLSLayerFactory* tlsLayerFactory_; - FullPayloadParserFactoryCollection payloadParserFactories_; - FullPayloadSerializerCollection payloadSerializers_; - boost::shared_ptr<Connection> connection_; - boost::shared_ptr<BasicSessionStream> sessionStream_; - boost::shared_ptr<ClientSession> session_; - String certificate_; - bool disconnectRequested_; }; } diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp new file mode 100644 index 0000000..c80acb5 --- /dev/null +++ b/Swiften/Client/CoreClient.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Client/CoreClient.h" + +#include <boost/bind.hpp> + +#include "Swiften/Network/MainBoostIOServiceThread.h" +#include "Swiften/Network/BoostIOServiceThread.h" +#include "Swiften/Client/ClientSession.h" +#include "Swiften/StreamStack/PlatformTLSLayerFactory.h" +#include "Swiften/Network/Connector.h" +#include "Swiften/Network/BoostConnectionFactory.h" +#include "Swiften/Network/BoostTimerFactory.h" +#include "Swiften/TLS/PKCS12Certificate.h" +#include "Swiften/Session/BasicSessionStream.h" +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/Base/IDGenerator.h" +#include "Swiften/Client/ClientSessionStanzaChannel.h" + +namespace Swift { + +CoreClient::CoreClient(const JID& jid, const String& password) : jid_(jid), password_(password), disconnectRequested_(false) { + stanzaChannel_ = new ClientSessionStanzaChannel(); + stanzaChannel_->onMessageReceived.connect(boost::ref(onMessageReceived)); + stanzaChannel_->onPresenceReceived.connect(boost::ref(onPresenceReceived)); + stanzaChannel_->onStanzaAcked.connect(boost::ref(onStanzaAcked)); + stanzaChannel_->onAvailableChanged.connect(boost::bind(&CoreClient::handleStanzaChannelAvailableChanged, this, _1)); + + iqRouter_ = new IQRouter(stanzaChannel_); + connectionFactory_ = new BoostConnectionFactory(&MainBoostIOServiceThread::getInstance().getIOService()); + timerFactory_ = new BoostTimerFactory(&MainBoostIOServiceThread::getInstance().getIOService()); + tlsLayerFactory_ = new PlatformTLSLayerFactory(); +} + +CoreClient::~CoreClient() { + if (session_ || connection_) { + std::cerr << "Warning: Client not disconnected properly" << std::endl; + } + delete tlsLayerFactory_; + delete timerFactory_; + delete connectionFactory_; + delete iqRouter_; + + stanzaChannel_->onAvailableChanged.disconnect(boost::bind(&CoreClient::handleStanzaChannelAvailableChanged, this, _1)); + stanzaChannel_->onMessageReceived.disconnect(boost::ref(onMessageReceived)); + stanzaChannel_->onPresenceReceived.disconnect(boost::ref(onPresenceReceived)); + stanzaChannel_->onStanzaAcked.disconnect(boost::ref(onStanzaAcked)); + delete stanzaChannel_; +} + +void CoreClient::connect() { + connect(jid_.getDomain()); +} + +void CoreClient::connect(const JID& jid) { + jid_ = jid; + connect(); +} + +void CoreClient::connect(const String& host) { + assert(!connector_); + connector_ = Connector::create(host, &resolver_, connectionFactory_, timerFactory_); + connector_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1)); + connector_->setTimeoutMilliseconds(60*1000); + connector_->start(); +} + +void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connection) { + connector_->onConnectFinished.disconnect(boost::bind(&CoreClient::handleConnectorFinished, this, _1)); + connector_.reset(); + if (!connection) { + if (!disconnectRequested_) { + onError(ClientError::ConnectionError); + } + } + else { + assert(!connection_); + connection_ = connection; + + assert(!sessionStream_); + sessionStream_ = boost::shared_ptr<BasicSessionStream>(new BasicSessionStream(connection_, &payloadParserFactories_, &payloadSerializers_, tlsLayerFactory_, timerFactory_)); + if (!certificate_.isEmpty()) { + sessionStream_->setTLSCertificate(PKCS12Certificate(certificate_, password_)); + } + sessionStream_->onDataRead.connect(boost::bind(&CoreClient::handleDataRead, this, _1)); + sessionStream_->onDataWritten.connect(boost::bind(&CoreClient::handleDataWritten, this, _1)); + sessionStream_->initialize(); + + session_ = ClientSession::create(jid_, sessionStream_); + stanzaChannel_->setSession(session_); + session_->onFinished.connect(boost::bind(&CoreClient::handleSessionFinished, this, _1)); + session_->onNeedCredentials.connect(boost::bind(&CoreClient::handleNeedCredentials, this)); + session_->start(); + } +} + +void CoreClient::disconnect() { + // FIXME: We should be able to do without this boolean. We just have to make sure we can tell the difference between + // connector finishing without a connection due to an error or because of a disconnect. + disconnectRequested_ = true; + if (session_) { + session_->finish(); + } + else if (connector_) { + connector_->stop(); + assert(!session_); + } + assert(!session_); + assert(!sessionStream_); + assert(!connector_); + disconnectRequested_ = false; +} + +void CoreClient::setCertificate(const String& certificate) { + certificate_ = certificate; +} + +void CoreClient::handleSessionFinished(boost::shared_ptr<Error> error) { + session_->onFinished.disconnect(boost::bind(&CoreClient::handleSessionFinished, this, _1)); + session_->onNeedCredentials.disconnect(boost::bind(&CoreClient::handleNeedCredentials, this)); + session_.reset(); + + sessionStream_->onDataRead.disconnect(boost::bind(&CoreClient::handleDataRead, this, _1)); + sessionStream_->onDataWritten.disconnect(boost::bind(&CoreClient::handleDataWritten, this, _1)); + sessionStream_.reset(); + + connection_->disconnect(); + connection_.reset(); + + 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); + } +} + +void CoreClient::handleNeedCredentials() { + assert(session_); + session_->sendCredentials(password_); +} + +void CoreClient::handleDataRead(const String& data) { + onDataRead(data); +} + +void CoreClient::handleDataWritten(const String& data) { + onDataWritten(data); +} + +void CoreClient::handleStanzaChannelAvailableChanged(bool available) { + if (available) { + onConnected(); + } +} + +void CoreClient::sendMessage(boost::shared_ptr<Message> message) { + stanzaChannel_->sendMessage(message); +} + +void CoreClient::sendPresence(boost::shared_ptr<Presence> presence) { + stanzaChannel_->sendPresence(presence); +} + +} diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h new file mode 100644 index 0000000..704cf3b --- /dev/null +++ b/Swiften/Client/CoreClient.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swiften/Base/boost_bsignals.h" +#include <boost/shared_ptr.hpp> + +#include "Swiften/Network/PlatformDomainNameResolver.h" +#include "Swiften/Network/Connector.h" +#include "Swiften/Base/Error.h" +#include "Swiften/Client/ClientSession.h" +#include "Swiften/Client/ClientError.h" +#include "Swiften/Elements/Presence.h" +#include "Swiften/Elements/Message.h" +#include "Swiften/JID/JID.h" +#include "Swiften/Base/String.h" +#include "Swiften/Client/StanzaChannel.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" +#include "Swiften/Base/Shared.h" +#include "Swiften/Client/ClientSessionStanzaChannel.h" + +namespace Swift { + class IQRouter; + class TLSLayerFactory; + class ConnectionFactory; + class TimerFactory; + class ClientSession; + class BasicSessionStream; + + class CoreClient { + public: + CoreClient(const JID& jid, const String& password); + ~CoreClient(); + + void setCertificate(const String& certificate); + + void connect(); + void connect(const JID& jid); + void connect(const String& host); + void disconnect(); + + void sendMessage(boost::shared_ptr<Message>); + void sendPresence(boost::shared_ptr<Presence>); + + IQRouter* getIQRouter() const { + return iqRouter_; + } + + StanzaChannel* getStanzaChannel() const { + return stanzaChannel_; + } + + bool isAvailable() const { + return stanzaChannel_->isAvailable(); + } + + /** + * Returns the JID of the client. + * After the session was initialized, this returns the bound JID. + */ + const JID& getJID() const { + if (session_) { + return session_->getLocalJID(); + } + else { + return jid_; + } + } + + public: + boost::signal<void (const ClientError&)> onError; + boost::signal<void ()> onConnected; + boost::signal<void (const String&)> onDataRead; + boost::signal<void (const String&)> onDataWritten; + + boost::signal<void (boost::shared_ptr<Message>)> onMessageReceived; + boost::signal<void (boost::shared_ptr<Presence>) > onPresenceReceived; + boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaAcked; + + private: + void handleConnectorFinished(boost::shared_ptr<Connection>); + void handleStanzaChannelAvailableChanged(bool available); + void handleSessionFinished(boost::shared_ptr<Error>); + void handleNeedCredentials(); + void handleDataRead(const String&); + void handleDataWritten(const String&); + + private: + PlatformDomainNameResolver resolver_; + JID jid_; + String password_; + ClientSessionStanzaChannel* stanzaChannel_; + IQRouter* iqRouter_; + Connector::ref connector_; + ConnectionFactory* connectionFactory_; + TimerFactory* timerFactory_; + TLSLayerFactory* tlsLayerFactory_; + FullPayloadParserFactoryCollection payloadParserFactories_; + FullPayloadSerializerCollection payloadSerializers_; + boost::shared_ptr<Connection> connection_; + boost::shared_ptr<BasicSessionStream> sessionStream_; + boost::shared_ptr<ClientSession> session_; + String certificate_; + bool disconnectRequested_; + }; +} |