X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fcorenetwork.h;h=6ad77b6830f810934f36d64cd3828a41dd613490;hp=906f60ae0e3c674c80256b460d50cc23195d6de9;hb=f12d6496251729f7d21f4fbcb0814dec7fba4b75;hpb=5013eef8eb17221e8f5866977f02e970e30ec0ac diff --git a/src/core/corenetwork.h b/src/core/corenetwork.h index 906f60ae..6ad77b68 100644 --- a/src/core/corenetwork.h +++ b/src/core/corenetwork.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2016 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 * @@ -101,6 +101,34 @@ public: inline quint16 localPort() const { return socket.localPort(); } inline quint16 peerPort() const { return socket.peerPort(); } + /** + * Gets whether or not a disconnect was expected. + * + * Distinguishes desired quits from unexpected disconnections such as socket errors or timeouts. + * + * @return True if disconnect was requested, otherwise false. + */ + inline bool disconnectExpected() const { return _disconnectExpected; } + + /** + * Gets whether or not the server replies to automated PINGs with a valid timestamp + * + * Distinguishes between servers that reply by quoting the text sent, and those that respond + * with whatever they want. + * + * @return True if a valid timestamp has been received as a PONG, otherwise false. + */ + inline bool isPongTimestampValid() const { return _pongTimestampValid; } + + /** + * Gets whether or not an automated PING has been sent without any PONG received + * + * Reset whenever any PONG is received, not just the automated one sent. + * + * @return True if a PING has been sent without a PONG received, otherwise false. + */ + inline bool isPongReplyPending() const { return _pongReplyPending; } + QList> splitMessage(const QString &cmd, const QString &message, std::function(QString &)> cmdGenerator); // IRCv3 capability negotiation @@ -181,6 +209,17 @@ public slots: void setPingInterval(int interval); + /** + * Sets whether or not the IRC server has replied to PING with a valid timestamp + * + * This allows determining whether or not an IRC server responds to PING with a PONG that quotes + * what was sent, or if it does something else (and therefore PONGs should be more aggressively + * hidden). + * + * @param timestampValid If true, a valid timestamp has been received via PONG reply + */ + void setPongTimestampValid(bool validTimestamp); + void connectToIrc(bool reconnecting = false); /** * Disconnect from the IRC server. @@ -268,6 +307,40 @@ public slots: bool cipherUsesCBC(const QString &target); #endif + // Custom rate limiting (can be connected to signals) + + /** + * Update rate limiting according to Network configuration + * + * Updates the token bucket and message queue timer according to the network configuration, such + * as on first load, or after changing settings. + * + * Calling this will reset any ongoing queue delays. If messages exist in the queue when rate + * limiting is disabled, messages will be quickly sent (100 ms) with new messages queued to send + * until the queue is cleared. + * + * @see Network::useCustomMessageRate() + * @see Network::messageRateBurstSize() + * @see Network::messageRateDelay() + * @see Network::unlimitedMessageRate() + * + * @param[in] forceUnlimited + * @parmblock + * If true, override user settings to disable message rate limiting, otherwise apply rate limits + * set by the user. Use with caution and remember to re-enable configured limits when done. + * @endparmblock + */ + void updateRateLimiting(const bool forceUnlimited = false); + + /** + * Resets the token bucket up to the maximum + * + * Call this if the connection's been reset after calling updateRateLimiting() if needed. + * + * @see CoreNetwork::updateRateLimiting() + */ + void resetTokenBucket(); + // IRCv3 capability negotiation (can be connected to signals) /** @@ -329,6 +402,11 @@ public slots: inline void resetPingTimeout() { _pingCount = 0; } + /** + * Marks the network as no longer having a pending reply to an automated PING + */ + inline void resetPongReplyPending() { _pongReplyPending = false; } + inline void displayMsg(Message::Type msgType, BufferInfo::Type bufferType, const QString &target, const QString &text, const QString &sender = "", Message::Flags flags = Message::None) { emit displayMsg(networkId(), msgType, bufferType, target, text, sender, flags); @@ -346,8 +424,8 @@ signals: void sslErrors(const QVariant &errorData); void newEvent(Event *event); - void socketInitialized(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort); - void socketDisconnected(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort); + void socketInitialized(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort, qint64 socketId); + void socketDisconnected(const CoreIdentity *identity, const QHostAddress &localAddress, quint16 localPort, const QHostAddress &peerAddress, quint16 peerPort, qint64 socketId); protected: inline virtual IrcChannel *ircChannelFactory(const QString &channelname) { return new CoreIrcChannel(channelname, this); } @@ -381,6 +459,23 @@ private slots: void sslErrors(const QList &errors); #endif + /** + * Check the message token bucket + * + * If rate limiting is disabled and the message queue is empty, this disables the token bucket + * timer. Otherwise, a queued message will be sent. + * + * @see CoreNetwork::fillBucketAndProcessQueue() + */ + void checkTokenBucket(); + + /** + * Top up token bucket and send as many queued messages as possible + * + * If there's any room for more tokens, add to the token bucket. Separately, if there's any + * messages to send, send until there's no more tokens or the queue is empty, whichever comes + * first. + */ void fillBucketAndProcessQueue(); void writeToSocket(const QByteArray &data); @@ -393,6 +488,7 @@ private: #else QTcpSocket socket; #endif + qint64 _socketId{0}; CoreUserInputHandler *_userInputHandler; @@ -417,9 +513,13 @@ private: int _lastUsedServerIndex; QTimer _pingTimer; - uint _lastPingTime; - uint _pingCount; - bool _sendPings; + qint64 _lastPingTime = 0; ///< Unix time of most recently sent automatic ping + uint _pingCount = 0; ///< Unacknowledged automatic pings + bool _sendPings = false; ///< If true, pings should be periodically sent to server + bool _pongTimestampValid = false; ///< If true, IRC server responds to PING by quoting in PONG + // This tracks whether or not a server responds to PING with a PONG of what was sent, or if it + // does something else. If false, PING reply hiding should be more aggressive. + bool _pongReplyPending = false; ///< If true, at least one PING sent without a PONG reply QStringList _autoWhoQueue; QHash _autoWhoPending; @@ -463,10 +563,12 @@ private: const int maxCapRequestLength = 100; QTimer _tokenBucketTimer; - int _messageDelay; // token refill speed in ms - int _burstSize; // size of the token bucket - int _tokenBucket; // the virtual bucket that holds the tokens - QList _msgQueue; + // No need for int type as one cannot travel into the past (at least not yet, Doc) + quint32 _messageDelay; /// Token refill speed in ms + quint32 _burstSize; /// Size of the token bucket + quint32 _tokenBucket; /// The virtual bucket that holds the tokens + QList _msgQueue; /// Queue of messages waiting to be sent + bool _skipMessageRates; /// If true, skip all message rate limits QString _requestedUserModes; // 2 strings separated by a '-' character. first part are requested modes to add, the second to remove