/* * Copyright (C) 1996-2023 The Squid Software Foundation and contributors * * Squid software is distributed under GPLv2+ license and includes * contributions from numerous individuals and organizations. * Please see the COPYING and CONTRIBUTORS files for details. */ #ifndef SQUID_SRC_CLIENTINFO_H #define SQUID_SRC_CLIENTINFO_H #if USE_DELAY_POOLS #include "BandwidthBucket.h" #endif #include "base/ByteCounter.h" #include "cbdata.h" #include "enums.h" #include "hash.h" #include "ip/Address.h" #include "LogTags.h" #include "mem/forward.h" #include "typedefs.h" #include #if USE_DELAY_POOLS class CommQuotaQueue; #endif class ClientInfo : public hash_link #if USE_DELAY_POOLS , public BandwidthBucket #endif { MEMPROXY_CLASS(ClientInfo); public: explicit ClientInfo(const Ip::Address &); #if USE_DELAY_POOLS ~ClientInfo() override; #else ~ClientInfo(); #endif Ip::Address addr; struct Protocol { Protocol() : n_requests(0) { memset(result_hist, 0, sizeof(result_hist)); } int result_hist[LOG_TYPE_MAX]; int n_requests; ByteCounter kbytes_in; ByteCounter kbytes_out; ByteCounter hit_kbytes_out; } Http, Icp; struct Cutoff { Cutoff() : time(0), n_req(0), n_denied(0) {} time_t time; int n_req; int n_denied; } cutoff; int n_established; /* number of current established connections */ time_t last_seen; #if USE_DELAY_POOLS bool writeLimitingActive; ///< Is write limiter active bool firstTimeConnection;///< is this first time connection for this client CommQuotaQueue *quotaQueue; ///< clients waiting for more write quota int rationedQuota; ///< precomputed quota preserving fairness among clients int rationedCount; ///< number of clients that will receive rationedQuota bool eventWaiting; ///< waiting for commHandleWriteHelper event to fire // all those functions access Comm fd_table and are defined in comm.cc bool hasQueue() const; ///< whether any clients are waiting for write quota bool hasQueue(const CommQuotaQueue*) const; ///< has a given queue unsigned int quotaEnqueue(int fd); ///< client starts waiting in queue; create the queue if necessary int quotaPeekFd() const; ///< returns the next fd reservation unsigned int quotaPeekReserv() const; ///< returns the next reserv. to pop void quotaDequeue(); ///< pops queue head from queue void kickQuotaQueue(); ///< schedule commHandleWriteHelper call /// either selects the head descriptor for writing or calls quotaDequeue() void writeOrDequeue(); /* BandwidthBucket API */ int quota() override; ///< allocate quota for a just dequeued client bool applyQuota(int &nleft, Comm::IoCallback *state) override; void scheduleWrite(Comm::IoCallback *state) override; void onFdClosed() override; void reduceBucket(int len) override; void quotaDumpQueue(); ///< dumps quota queue for debugging /** * Configure client write limiting (note:"client" here means - IP). It is called * by httpAccept in client_side.cc, where the initial bucket size (anInitialBurst) * computed, using the configured maximum bucket value and configured initial * bucket value(50% by default). * * \param writeSpeedLimit is speed limit configured in config for this pool * \param initialBurst is initial bucket size to use for this client(i.e. client can burst at first) * \param highWatermark is maximum bucket value */ void setWriteLimiter(const int aWriteSpeedLimit, const double anInitialBurst, const double aHighWatermark); #endif /* USE_DELAY_POOLS */ }; #if USE_DELAY_POOLS // a queue of Comm clients waiting for I/O quota controlled by delay pools class CommQuotaQueue { CBDATA_CLASS(CommQuotaQueue); public: CommQuotaQueue(ClientInfo *info); ~CommQuotaQueue(); bool empty() const { return fds.empty(); } size_t size() const { return fds.size(); } int front() const { return fds.front(); } unsigned int enqueue(int fd); void dequeue(); ClientInfo *clientInfo; ///< bucket responsible for quota maintenance // these counters might overflow; that is OK because they are for IDs only int ins; ///< number of enqueue calls, used to generate a "reservation" ID int outs; ///< number of dequeue calls, used to check the "reservation" ID private: // TODO: optimize using a Ring- or List-based store? typedef std::deque Store; Store fds; ///< descriptor queue }; #endif /* USE_DELAY_POOLS */ #endif /* SQUID_SRC_CLIENTINFO_H */