X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fcorenetwork.cpp;h=8506dea2a6df9840527a4fc689fce2bf3231bff2;hp=e6699c1251c77abeaba944c2cfdb50bd3bcc9620;hb=HEAD;hpb=3128dab675247b8505937b0bc22b4e2ad2dd61ff diff --git a/src/core/corenetwork.cpp b/src/core/corenetwork.cpp index e6699c12..618aaaec 100644 --- a/src/core/corenetwork.cpp +++ b/src/core/corenetwork.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2019 by the Quassel Project * + * Copyright (C) 2005-2022 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -20,8 +20,11 @@ #include "corenetwork.h" +#include + #include #include +#include #include "core.h" #include "coreidentity.h" @@ -37,6 +40,7 @@ CoreNetwork::CoreNetwork(const NetworkId& networkid, CoreSession* session) : Network(networkid, session) , _coreSession(session) , _userInputHandler(new CoreUserInputHandler(this)) + , _metricsServer(Core::instance()->metricsServer()) , _autoReconnectCount(0) , _quitRequested(false) , _disconnectExpected(false) @@ -82,10 +86,8 @@ CoreNetwork::CoreNetwork(const NetworkId& networkid, CoreSession* session) connect(&socket, selectOverload(&QAbstractSocket::error), this, &CoreNetwork::onSocketError); connect(&socket, &QAbstractSocket::stateChanged, this, &CoreNetwork::onSocketStateChanged); connect(&socket, &QIODevice::readyRead, this, &CoreNetwork::onSocketHasData); -#ifdef HAVE_SSL connect(&socket, &QSslSocket::encrypted, this, &CoreNetwork::onSocketInitialized); connect(&socket, selectOverload&>(&QSslSocket::sslErrors), this, &CoreNetwork::onSslErrors); -#endif connect(this, &CoreNetwork::newEvent, coreSession()->eventManager(), &EventManager::postEvent); // Custom rate limiting @@ -184,6 +186,10 @@ void CoreNetwork::connectToIrc(bool reconnecting) _socketId = Core::instance()->identServer()->addWaitingSocket(); } + if (_metricsServer) { + _metricsServer->addNetwork(userId()); + } + if (!reconnecting && useAutoReconnect() && _autoReconnectCount == 0) { _autoReconnectTimer.setInterval(autoReconnectInterval() * 1000); if (unlimitedReconnectRetries()) @@ -262,7 +268,6 @@ void CoreNetwork::connectToIrc(bool reconnecting) // 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(); if (identity) { @@ -274,9 +279,6 @@ void CoreNetwork::connectToIrc(bool reconnecting) else { socket.connectToHost(server.host, server.port); } -#else - socket.connectToHost(server.host, server.port); -#endif } void CoreNetwork::disconnectFromIrc(bool requested, const QString& reason, bool withReconnect) @@ -290,6 +292,9 @@ void CoreNetwork::disconnectFromIrc(bool requested, const QString& reason, bool } disablePingTimeout(); _msgQueue.clear(); + if (_metricsServer) { + _metricsServer->messageQueue(userId(), 0); + } IrcUser* me_ = me(); if (me_) { @@ -366,6 +371,9 @@ void CoreNetwork::putRawLine(const QByteArray& s, bool prepend) // Add to back, waiting in order _msgQueue.append(s); } + if (_metricsServer) { + _metricsServer->messageQueue(userId(), _msgQueue.size()); + } } } @@ -505,6 +513,9 @@ void CoreNetwork::onSocketHasData() { while (socket.canReadLine()) { QByteArray s = socket.readLine(); + if (_metricsServer) { + _metricsServer->receiveDataNetwork(userId(), s.size()); + } if (s.endsWith("\r\n")) s.chop(2); else if (s.endsWith("\n")) @@ -548,7 +559,6 @@ void CoreNetwork::onSocketInitialized() Server server = usedServer(); -#ifdef HAVE_SSL // Non-SSL connections enter here only once, always emit socketInitialized(...) in these cases // SSL connections call socketInitialized() twice, only emit socketInitialized(...) on the first (not yet encrypted) run if (!server.useSsl || !socket.isEncrypted()) { @@ -559,9 +569,6 @@ void CoreNetwork::onSocketInitialized() // We'll finish setup once we're encrypted, and called again return; } -#else - emit socketInitialized(identity, localAddress(), localPort(), peerAddress(), peerPort(), _socketId); -#endif socket.setSocketOption(QAbstractSocket::KeepAliveOption, true); @@ -605,6 +612,9 @@ void CoreNetwork::onSocketDisconnected() { disablePingTimeout(); _msgQueue.clear(); + if (_metricsServer) { + _metricsServer->messageQueue(userId(), 0); + } _autoWhoCycleTimer.stop(); _autoWhoTimer.stop(); @@ -644,6 +654,10 @@ void CoreNetwork::onSocketDisconnected() else _autoReconnectTimer.start(); } + + if (_metricsServer) { + _metricsServer->removeNetwork(userId()); + } } void CoreNetwork::onSocketStateChanged(QAbstractSocket::SocketState socketState) @@ -1063,12 +1077,18 @@ void CoreNetwork::resetTokenBucket() void CoreNetwork::serverCapAdded(const QString& capability) { + // Exclude skipped capabilities + if (skipCaps().contains(capability)) { + return; + } + // Check if it's a known capability; if so, add it to the list // Handle special cases first if (capability == IrcCap::SASL) { // Only request SASL if it's enabled - if (networkInfo().useSasl) + if (useSasl()) { queueCap(capability); + } } else if (IrcCap::knownCaps.contains(capability)) { // Handling for general known capabilities @@ -1087,12 +1107,11 @@ void CoreNetwork::serverCapAcknowledged(const QString& capability) } // Handle capabilities that require further messages sent to the IRC server - // If you change this list, ALSO change the list in CoreNetwork::capsRequiringServerMessages + // If you change this list, ALSO change the list in CoreNetwork::capsRequiringConfiguration if (capability == IrcCap::SASL) { // If SASL mechanisms specified, limit to what's accepted for authentication // if the current identity has a cert set, use SASL EXTERNAL // FIXME use event -#ifdef HAVE_SSL if (!identityPtr()->sslCert().isNull()) { if (saslMaybeSupports(IrcCap::SaslMech::EXTERNAL)) { // EXTERNAL authentication supported, send request @@ -1109,7 +1128,6 @@ void CoreNetwork::serverCapAcknowledged(const QString& capability) } } else { -#endif if (saslMaybeSupports(IrcCap::SaslMech::PLAIN)) { // PLAIN authentication supported, send request // Only working with PLAIN atm, blowfish later @@ -1124,9 +1142,7 @@ void CoreNetwork::serverCapAcknowledged(const QString& capability) )); sendNextCap(); } -#ifdef HAVE_SSL } -#endif } } @@ -1245,16 +1261,67 @@ void CoreNetwork::retryCapsIndividually() void CoreNetwork::beginCapNegotiation() { - // Don't begin negotiation if no capabilities are queued to request - if (!capNegotiationInProgress()) { - // If the server doesn't have any capabilities, but supports CAP LS, continue on with the - // normal connection. + // Check if any available capabilities have been disabled + QStringList capsSkipped; + if (!skipCaps().isEmpty() && !caps().isEmpty()) { + // Find the entries that are common to skipCaps() and caps(). This represents any + // capabilities supported by the server that were skipped. + + // Both skipCaps() and caps() are already lowercase + // std::set_intersection requires sorted lists, and we can't modify the original lists. + // + // skipCaps() should already be sorted. caps() is intentionally not sorted elsewhere so + // Quassel can show the capabilities in the order transmitted by the network. + auto sortedCaps = caps(); + sortedCaps.sort(); + + // Find the intersection between skipped caps and server-supplied caps + std::set_intersection(skipCaps().cbegin(), skipCaps().cend(), + sortedCaps.cbegin(), sortedCaps.cend(), + std::back_inserter(capsSkipped)); + } + + if (!capsPendingNegotiation()) { + // No capabilities are queued for request, determine the reason why + QString capStatusMsg; + if (caps().empty()) { + // The server doesn't provide any capabilities, but supports CAP LS + capStatusMsg = tr("No capabilities available"); + } + else if (capsEnabled().empty()) { + // The server supports capabilities (caps() is not empty) but Quassel doesn't support + // anything offered. This should be uncommon. + capStatusMsg = + tr("None of the capabilities provided by the server are supported (found: %1)") + .arg(caps().join(", ")); + } + else { + // Quassel has enabled some capabilities, but there are no further capabilities that can + // be negotiated. + // (E.g. the user has manually run "/cap ls 302" after initial negotiation.) + capStatusMsg = + tr("No additional capabilities are supported (found: %1; currently enabled: %2)") + .arg(caps().join(", "), capsEnabled().join(", ")); + } + // Inform the user of the situation showMessage(NetworkInternalMessage( Message::Server, BufferInfo::StatusBuffer, "", - tr("No capabilities available") + capStatusMsg )); + + if (!capsSkipped.isEmpty()) { + // Mention that some capabilities are skipped + showMessage(NetworkInternalMessage( + Message::Server, + BufferInfo::StatusBuffer, + "", + tr("Quassel is configured to ignore some capabilities (skipped: %1)").arg(capsSkipped.join(", ")) + )); + } + + // End any ongoing capability negotiation, allowing connection to continue endCapNegotiation(); return; } @@ -1267,6 +1334,16 @@ void CoreNetwork::beginCapNegotiation() tr("Ready to negotiate (found: %1)").arg(caps().join(", ")) )); + if (!capsSkipped.isEmpty()) { + // Mention that some capabilities are skipped + showMessage(NetworkInternalMessage( + Message::Server, + BufferInfo::StatusBuffer, + "", + tr("Quassel is configured to ignore some capabilities (skipped: %1)").arg(capsSkipped.join(", ")) + )); + } + // Build a list of queued capabilities, starting with individual, then bundled, only adding the // comma separator between the two if needed (both individual and bundled caps exist). QString queuedCapsDisplay = _capsQueuedIndividual.join(", ") @@ -1284,14 +1361,14 @@ void CoreNetwork::beginCapNegotiation() void CoreNetwork::sendNextCap() { - if (capNegotiationInProgress()) { + if (capsPendingNegotiation()) { // Request the next set of capabilities and remove them from the list putRawLine(serverEncode(QString("CAP REQ :%1").arg(takeQueuedCaps()))); } else { // No pending desired capabilities, capability negotiation finished // If SASL requested but not available, print a warning - if (networkInfo().useSasl && !capEnabled(IrcCap::SASL)) + if (useSasl() && !capEnabled(IrcCap::SASL)) showMessage(NetworkInternalMessage( Message::Error, BufferInfo::StatusBuffer, @@ -1433,7 +1510,6 @@ void CoreNetwork::sendAutoWho() } } -#ifdef HAVE_SSL void CoreNetwork::onSslErrors(const QList& sslErrors) { Server server = usedServer(); @@ -1476,8 +1552,6 @@ void CoreNetwork::onSslErrors(const QList& sslErrors) } } -#endif // HAVE_SSL - void CoreNetwork::checkTokenBucket() { if (_skipMessageRates) { @@ -1503,6 +1577,9 @@ void CoreNetwork::fillBucketAndProcessQueue() // As long as there's tokens available and messages remaining, sending messages from the queue while (!_msgQueue.empty() && _tokenBucket > 0) { writeToSocket(_msgQueue.takeFirst()); + if (_metricsServer) { + _metricsServer->messageQueue(userId(), _msgQueue.size()); + } } } @@ -1515,6 +1592,9 @@ void CoreNetwork::writeToSocket(const QByteArray& data) } socket.write(data); socket.write("\r\n"); + if (_metricsServer) { + _metricsServer->transmitDataNetwork(userId(), data.size() + 2); + } if (!_skipMessageRates) { // Only subtract from the token bucket if message rate limiting is enabled _tokenBucket--;