diff options
author | Remko Tronçon <git@el-tramo.be> | 2010-10-07 21:37:48 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2010-10-07 21:39:40 (GMT) |
commit | 091f554f42dcdef534718fb759eb45b622adfd4f (patch) | |
tree | b8753f62884ef5ef46d04782bb38d8ef2ed38d01 /Swiften/Client | |
parent | 88eab3d1d9b722590da3837e3c79839189ea58d2 (diff) | |
download | swift-contrib-091f554f42dcdef534718fb759eb45b622adfd4f.zip swift-contrib-091f554f42dcdef534718fb759eb45b622adfd4f.tar.bz2 |
Fix crashes on disconnect during connect.
Resolves: #588
Diffstat (limited to 'Swiften/Client')
-rw-r--r-- | Swiften/Client/Client.cpp | 62 | ||||
-rw-r--r-- | Swiften/Client/Client.h | 5 | ||||
-rw-r--r-- | Swiften/Client/ClientSession.cpp | 37 | ||||
-rw-r--r-- | Swiften/Client/ClientSession.h | 5 |
4 files changed, 58 insertions, 51 deletions
diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp index 974e256..5b57672 100644 --- a/Swiften/Client/Client.cpp +++ b/Swiften/Client/Client.cpp @@ -21,7 +21,7 @@ namespace Swift { -Client::Client(const JID& jid, const String& password) : jid_(jid), password_(password) { +Client::Client(const JID& jid, const String& password) : jid_(jid), password_(password), disconnectRequested_(false) { iqRouter_ = new IQRouter(this); connectionFactory_ = new BoostConnectionFactory(&MainBoostIOServiceThread::getInstance().getIOService()); timerFactory_ = new BoostTimerFactory(&MainBoostIOServiceThread::getInstance().getIOService()); @@ -52,26 +52,20 @@ void Client::connect(const JID& jid) { } void Client::connect(const String& host) { - assert(!connector_); // Crash on reconnect is here. + assert(!connector_); connector_ = Connector::create(host, &resolver_, connectionFactory_, timerFactory_); - connector_->onConnectFinished.connect(boost::bind(&Client::handleConnectorFinished, this, _1, connector_)); + connector_->onConnectFinished.connect(boost::bind(&Client::handleConnectorFinished, this, _1)); connector_->setTimeoutMilliseconds(60*1000); connector_->start(); } -void Client::handleConnectorFinished(boost::shared_ptr<Connection> connection, Connector::ref connector) { - bool currentConnection = connector_ && (connector.get() == connector_.get()); - // TODO: Add domain name resolver error - if (!currentConnection) { - /* disconnect() was called, this connection should be thrown away*/ - if (connection) { - connection->disconnect(); - } - return; - } +void Client::handleConnectorFinished(boost::shared_ptr<Connection> connection) { + connector_->onConnectFinished.disconnect(boost::bind(&Client::handleConnectorFinished, this, _1)); connector_.reset(); if (!connection) { - onError(ClientError::ConnectionError); + if (!disconnectRequested_) { + onError(ClientError::ConnectionError); + } } else { assert(!connection_); @@ -97,25 +91,20 @@ void Client::handleConnectorFinished(boost::shared_ptr<Connection> connection, C } void Client::disconnect() { - if (connector_) { - connector_.reset(); - } + // 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 { - closeConnection(); - } -} - -void Client::closeConnection() { - if (sessionStream_) { - sessionStream_.reset(); - } - if (connection_) { - connection_->disconnect(); - connection_.reset(); + else if (connector_) { + connector_->stop(); + assert(!session_); } + assert(!session_); + assert(!sessionStream_); + assert(!connector_); + disconnectRequested_ = false; } void Client::send(boost::shared_ptr<Stanza> stanza) { @@ -167,9 +156,22 @@ void Client::setCertificate(const String& certificate) { } void Client::handleSessionFinished(boost::shared_ptr<Error> error) { + session_->onInitialized.disconnect(boost::bind(&Client::handleSessionInitialized, this)); + session_->onStanzaAcked.disconnect(boost::bind(&Client::handleStanzaAcked, this, _1)); + session_->onFinished.disconnect(boost::bind(&Client::handleSessionFinished, this, _1)); + session_->onNeedCredentials.disconnect(boost::bind(&Client::handleNeedCredentials, this)); + session_->onStanzaReceived.disconnect(boost::bind(&Client::handleStanza, this, _1)); session_.reset(); - closeConnection(); + + sessionStream_->onDataRead.disconnect(boost::bind(&Client::handleDataRead, this, _1)); + sessionStream_->onDataWritten.disconnect(boost::bind(&Client::handleDataWritten, this, _1)); + sessionStream_.reset(); + + connection_->disconnect(); + connection_.reset(); + onAvailableChanged(false); + if (error) { ClientError clientError; if (boost::shared_ptr<ClientSession::Error> actualError = boost::dynamic_pointer_cast<ClientSession::Error>(error)) { diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h index e046b3c..7e55289 100644 --- a/Swiften/Client/Client.h +++ b/Swiften/Client/Client.h @@ -70,7 +70,7 @@ namespace Swift { boost::signal<void (const String&)> onDataWritten; private: - void handleConnectorFinished(boost::shared_ptr<Connection>, Connector::ref); + void handleConnectorFinished(boost::shared_ptr<Connection>); void handleSessionInitialized(); void send(boost::shared_ptr<Stanza>); virtual String getNewIQID(); @@ -81,8 +81,6 @@ namespace Swift { void handleDataWritten(const String&); void handleStanzaAcked(boost::shared_ptr<Stanza>); - void closeConnection(); - private: PlatformDomainNameResolver resolver_; JID jid_; @@ -99,5 +97,6 @@ namespace Swift { boost::shared_ptr<BasicSessionStream> sessionStream_; boost::shared_ptr<ClientSession> session_; String certificate_; + bool disconnectRequested_; }; } diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index 17b3931..4c2be95 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -56,10 +56,10 @@ ClientSession::~ClientSession() { } void ClientSession::start() { - streamOnStreamStartReceivedConnection = stream->onStreamStartReceived.connect(boost::bind(&ClientSession::handleStreamStart, shared_from_this(), _1)); - streamOnElementReceivedConnection = stream->onElementReceived.connect(boost::bind(&ClientSession::handleElement, shared_from_this(), _1)); - streamOnErrorConnection = stream->onError.connect(boost::bind(&ClientSession::handleStreamError, shared_from_this(), _1)); - streamOnTLSEncryptedConnection = stream->onTLSEncrypted.connect(boost::bind(&ClientSession::handleTLSEncrypted, shared_from_this())); + 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; @@ -230,10 +230,10 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (boost::dynamic_pointer_cast<StreamManagementEnabled>(element)) { stanzaAckRequester_ = boost::shared_ptr<StanzaAckRequester>(new StanzaAckRequester()); - stanzaAckRequester_->onRequestAck.connect(boost::bind(&ClientSession::requestAck, this)); - stanzaAckRequester_->onStanzaAcked.connect(boost::bind(&ClientSession::handleStanzaAcked, this, _1)); + stanzaAckRequester_->onRequestAck.connect(boost::bind(&ClientSession::requestAck, shared_from_this())); + stanzaAckRequester_->onStanzaAcked.connect(boost::bind(&ClientSession::handleStanzaAcked, shared_from_this(), _1)); stanzaAckResponder_ = boost::shared_ptr<StanzaAckResponder>(new StanzaAckResponder()); - stanzaAckResponder_->onAck.connect(boost::bind(&ClientSession::ack, this, _1)); + stanzaAckResponder_->onAck.connect(boost::bind(&ClientSession::ack, shared_from_this(), _1)); needAcking = false; continueSessionInitialization(); } @@ -334,9 +334,6 @@ void ClientSession::handleStreamError(boost::shared_ptr<Swift::Error> error) { } void ClientSession::finish() { - if (stream->isAvailable()) { - stream->writeFooter(); - } finishSession(boost::shared_ptr<Error>()); } @@ -346,11 +343,23 @@ void ClientSession::finishSession(Error::Type error) { void ClientSession::finishSession(boost::shared_ptr<Swift::Error> error) { state = Finished; + if (stanzaAckRequester_) { + stanzaAckRequester_->onRequestAck.disconnect(boost::bind(&ClientSession::requestAck, shared_from_this())); + stanzaAckRequester_->onStanzaAcked.disconnect(boost::bind(&ClientSession::handleStanzaAcked, shared_from_this(), _1)); + stanzaAckRequester_.reset(); + } + if (stanzaAckResponder_) { + stanzaAckResponder_->onAck.disconnect(boost::bind(&ClientSession::ack, shared_from_this(), _1)); + stanzaAckResponder_.reset(); + } stream->setWhitespacePingEnabled(false); - streamOnStreamStartReceivedConnection.disconnect(); - streamOnElementReceivedConnection.disconnect(); - streamOnErrorConnection.disconnect(); - streamOnTLSEncryptedConnection.disconnect(); + stream->onStreamStartReceived.disconnect(boost::bind(&ClientSession::handleStreamStart, shared_from_this(), _1)); + stream->onElementReceived.disconnect(boost::bind(&ClientSession::handleElement, shared_from_this(), _1)); + stream->onError.disconnect(boost::bind(&ClientSession::handleStreamError, shared_from_this(), _1)); + stream->onTLSEncrypted.disconnect(boost::bind(&ClientSession::handleTLSEncrypted, shared_from_this())); + if (stream->isAvailable()) { + stream->writeFooter(); + } onFinished(error); } diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h index 2af9cab..2c1bda8 100644 --- a/Swiften/Client/ClientSession.h +++ b/Swiften/Client/ClientSession.h @@ -56,6 +56,7 @@ namespace Swift { }; ~ClientSession(); + static boost::shared_ptr<ClientSession> create(const JID& jid, boost::shared_ptr<SessionStream> stream) { return boost::shared_ptr<ClientSession>(new ClientSession(jid, stream)); } @@ -127,9 +128,5 @@ namespace Swift { ClientAuthenticator* authenticator; boost::shared_ptr<StanzaAckRequester> stanzaAckRequester_; boost::shared_ptr<StanzaAckResponder> stanzaAckResponder_; - boost::bsignals::connection streamOnStreamStartReceivedConnection; - boost::bsignals::connection streamOnElementReceivedConnection; - boost::bsignals::connection streamOnErrorConnection; - boost::bsignals::connection streamOnTLSEncryptedConnection; }; } |