From: Shane Synan Date: Mon, 5 Sep 2016 19:07:51 +0000 (-0500) Subject: Process events when destroying CoreNetwork X-Git-Tag: 0.12.5~86 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=418f497d996892ec16a31d3e282c4996e8677b3a Process events when destroying CoreNetwork During shutdown, process events in CoreNetwork, and wait for the socket to disconnect. This fixes the QUIT command not getting sent to IRC networks. Examples [Unreal 3.2] > Before <-- dcircuit_dev (quasseldev@hostmask.IP) has quit (Input/output error) > After <-- dcircuit_dev (quasseldev@hostmask.IP) has quit (Quit: My Message!) [Freenode] > Before <-- dcircuit_dev (~quasselde@hostmask) has quit (Remote host closed the connection) > After <-- dcircuit_dev (~quasselde@hostmask) has quit (Quit: My Message!) Where "My Message!" is specified in Configure Quassel -> IRC -> Identities -> Advanced -> Quit Reason Note: Freenode hides quit messages from clients that disconnect soon after connecting. Stay connected ~10 minutes before testing QUIT. (cherry picked from commit 59ed0127591f946a68a6ee7f30b23deb37d26821) --- diff --git a/src/core/corenetwork.cpp b/src/core/corenetwork.cpp index 65850c3e..ac69044d 100644 --- a/src/core/corenetwork.cpp +++ b/src/core/corenetwork.cpp @@ -90,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()) { diff --git a/src/core/corenetwork.h b/src/core/corenetwork.h index 51eb31a8..5a41b983 100644 --- a/src/core/corenetwork.h +++ b/src/core/corenetwork.h @@ -127,6 +127,17 @@ public slots: void disconnectFromIrc(bool requested = true, const QString &reason = QString(), bool withReconnect = false, bool forceImmediate = false); + /** + * Forcibly close the IRC server socket, waiting for it to close. + * + * Call CoreNetwork::disconnectFromIrc() first, allow the event loop to run, then if you need to + * be sure the network's disconencted (e.g. clean-up), call this. + * + * @param msecs Maximum time to wait for socket to close, in milliseconds. + * @return True if socket closes successfully; false if error occurs or timeout reached + */ + bool forceDisconnect(int msecs = 1000); + void userInput(BufferInfo bufferInfo, QString msg); /**