X-Git-Url: https://git.quassel-irc.org/?a=blobdiff_plain;f=src%2Fcore%2Fcorenetwork.cpp;h=6a8bc71f989498256aed026585ea8362e504bba1;hb=refs%2Fheads%2F0.12;hp=cab2a447dda4da3488c363b5525fc05417eb9585;hpb=106d151d994fb26fd4586c6adf60a165075961a9;p=quassel.git diff --git a/src/core/corenetwork.cpp b/src/core/corenetwork.cpp index cab2a447..6a8bc71f 100644 --- a/src/core/corenetwork.cpp +++ b/src/core/corenetwork.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2015 by the Quassel Project * + * Copyright (C) 2005-2018 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -36,6 +36,7 @@ CoreNetwork::CoreNetwork(const NetworkId &networkid, CoreSession *session) _userInputHandler(new CoreUserInputHandler(this)), _autoReconnectCount(0), _quitRequested(false), + _disconnectExpected(false), _previousConnectionAttemptFailed(false), _lastUsedServerIndex(0), @@ -89,13 +90,39 @@ CoreNetwork::CoreNetwork(const NetworkId &networkid, CoreSession *session) CoreNetwork::~CoreNetwork() { - if (connectionState() != Disconnected && connectionState() != Network::Reconnecting) - disconnectFromIrc(false); // clean up, but this does not count as requested disconnect! + // Request a proper disconnect, but don't count as user-requested disconnect + if (socketConnected()) { + // Only try if the socket's fully connected (not initializing or disconnecting). + // Force an immediate disconnect, jumping the command queue. Ensures the proper QUIT is + // shown even if other messages are queued. + disconnectFromIrc(false, QString(), false, true); + // Process the putCmd events that trigger the quit. Without this, shutting down the core + // results in abrubtly closing the socket rather than sending the QUIT as expected. + QCoreApplication::processEvents(); + // Wait briefly for each network to disconnect. Sometimes it takes a little while to send. + if (!forceDisconnect()) { + qWarning() << "Timed out quitting network" << networkName() << + "(user ID " << userId() << ")"; + } + } disconnect(&socket, 0, this, 0); // this keeps the socket from triggering events during clean up delete _userInputHandler; } +bool CoreNetwork::forceDisconnect(int msecs) +{ + if (socket.state() == QAbstractSocket::UnconnectedState) { + // Socket already disconnected. + return true; + } + // Request a socket-level disconnect if not already happened + socket.disconnectFromHost(); + // Return the result of waiting for disconnect; true if successful, otherwise false + return socket.waitForDisconnected(msecs); +} + + QString CoreNetwork::channelDecode(const QString &bufferName, const QByteArray &string) const { if (!bufferName.isEmpty()) { @@ -164,12 +191,16 @@ void CoreNetwork::connectToIrc(bool reconnecting) } else if (_previousConnectionAttemptFailed) { // cycle to next server if previous connection attempt failed + _previousConnectionAttemptFailed = false; displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Connection failed. Cycling to next Server")); if (++_lastUsedServerIndex >= serverList().size()) { _lastUsedServerIndex = 0; } } - _previousConnectionAttemptFailed = false; + else { + // Start out with the top server in the list + _lastUsedServerIndex = 0; + } Server server = usedServer(); displayStatusMsg(tr("Connecting to %1:%2...").arg(server.host).arg(server.port)); @@ -187,8 +218,11 @@ void CoreNetwork::connectToIrc(bool reconnecting) // Qt caches DNS entries for a minute, resulting in round-robin (e.g. for chat.freenode.net) not working if several users // connect at a similar time. QHostInfo::fromName(), however, always performs a fresh lookup, overwriting the cache entry. - QHostInfo::fromName(server.host); - + if (! server.useProxy) { + //Avoid hostname lookups when a proxy is specified. The lookups won't use the proxy and may therefore leak the DNS + //hostname of the server. Qt's DNS cache also isn't used by the proxy so we don't need to refresh the entry. + QHostInfo::fromName(server.host); + } #ifdef HAVE_SSL if (server.useSsl) { CoreIdentity *identity = identityPtr(); @@ -207,8 +241,11 @@ void CoreNetwork::connectToIrc(bool reconnecting) } -void CoreNetwork::disconnectFromIrc(bool requested, const QString &reason, bool withReconnect) +void CoreNetwork::disconnectFromIrc(bool requested, const QString &reason, bool withReconnect, + bool forceImmediate) { + // Disconnecting from the network, should expect a socket close or error + _disconnectExpected = true; _quitRequested = requested; // see socketDisconnected(); if (!withReconnect) { _autoReconnectTimer.stop(); @@ -235,7 +272,7 @@ void CoreNetwork::disconnectFromIrc(bool requested, const QString &reason, bool socketDisconnected(); } else { if (socket.state() == QAbstractSocket::ConnectedState) { - userInputHandler()->issueQuit(_quitReason); + userInputHandler()->issueQuit(_quitReason, forceImmediate); } else { socket.close(); } @@ -439,8 +476,10 @@ void CoreNetwork::socketHasData() void CoreNetwork::socketError(QAbstractSocket::SocketError error) { - if (_quitRequested && error == QAbstractSocket::RemoteHostClosedError) + // Ignore socket closed errors if expected + if (_disconnectExpected && error == QAbstractSocket::RemoteHostClosedError) { return; + } _previousConnectionAttemptFailed = true; qWarning() << qPrintable(tr("Could not connect to %1 (%2)").arg(networkName(), socket.errorString())); @@ -529,6 +568,8 @@ void CoreNetwork::socketDisconnected() setConnected(false); emit disconnected(networkId()); emit socketDisconnected(identityPtr(), localAddress(), localPort(), peerAddress(), peerPort()); + // Reset disconnect expectations + _disconnectExpected = false; if (_quitRequested) { _quitRequested = false; setConnectionState(Network::Disconnected); @@ -573,6 +614,7 @@ void CoreNetwork::networkInitialized() { setConnectionState(Network::Initialized); setConnected(true); + _disconnectExpected = false; _quitRequested = false; if (useAutoReconnect()) {