/* * 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_RESOLVEDPEERS_H #define SQUID_SRC_RESOLVEDPEERS_H #include "base/RefCount.h" #include "comm/forward.h" #include #include #include class ResolvedPeerPath { public: explicit ResolvedPeerPath(const Comm::ConnectionPointer &conn) : connection(conn), available(true) {} Comm::ConnectionPointer connection; ///< (the address of) a path bool available; ///< whether this path may be used (i.e., has not been tried already) }; class PeerConnectionPointer; /// cache_peer and origin server addresses (a.k.a. paths) /// selected and resolved by the peering code class ResolvedPeers: public RefCountable { MEMPROXY_CLASS(ResolvedPeers); public: // ResolvedPeerPaths in addPath() call order typedef std::vector Paths; using size_type = Paths::size_type; typedef RefCount Pointer; ResolvedPeers(); /// whether we lack any known candidate paths bool empty() const { return !availablePaths; } /// add a candidate path to try after all the existing paths void addPath(const Comm::ConnectionPointer &); /// makes the previously extracted path available for extraction at its /// original position void reinstatePath(const PeerConnectionPointer &); /// extracts and returns the first queued address PeerConnectionPointer extractFront(); /// extracts and returns the first same-peer same-family address /// \returns nil if it cannot find the requested address PeerConnectionPointer extractPrime(const Comm::Connection ¤tPeer); /// extracts and returns the first same-peer different-family address /// \returns nil if it cannot find the requested address PeerConnectionPointer extractSpare(const Comm::Connection ¤tPeer); /// whether extractSpare() would return a non-nil path right now bool haveSpare(const Comm::Connection ¤tPeer); /// whether extractPrime() returns and will continue to return nil bool doneWithPrimes(const Comm::Connection ¤tPeer); /// whether extractSpare() returns and will continue to return nil bool doneWithSpares(const Comm::Connection ¤tPeer); /// whether doneWithPrimes() and doneWithSpares() are true for currentPeer bool doneWithPeer(const Comm::Connection ¤tPeer); /// the current number of candidate paths size_type size() const { return availablePaths; } /// whether all of the available candidate paths received from DNS bool destinationsFinalized = false; /// whether HappyConnOpener::noteCandidatesChange() is scheduled to fire bool notificationPending = false; private: /// A find*() result: An iterator of the found path (or paths_.end()) and /// whether the "other" path was found instead. typedef std::pair Finding; /// The protocol family of the given path, AF_INET or AF_INET6 static int ConnectionFamily(const Comm::Connection &conn); Paths::iterator start(); Finding findSpare(const Comm::Connection ¤tPeer); Finding findPrime(const Comm::Connection ¤tPeer); Finding findPeer(const Comm::Connection ¤tPeer); PeerConnectionPointer extractFound(const char *description, const Paths::iterator &found); Finding makeFinding(const Paths::iterator &found, bool foundOther); bool doneWith(const Finding &findings) const; void increaseAvailability(); void decreaseAvailability(); Paths paths_; ///< resolved addresses in (peer, family) order /// the number of leading paths_ elements that are all currently unavailable /// i.e. the size of the front paths_ segment comprised of unavailable items /// i.e. the position of the first available path (or paths_.size()) size_type pathsToSkip = 0; /// the total number of currently available elements in paths_ size_type availablePaths = 0; }; /// An invasive reference-counting Comm::Connection pointer that also keeps an /// (optional) ResolvedPeers position for the ResolvedPeers::reinstatePath() usage. /// Reference counting mechanism is compatible with Comm::ConnectionPointer. class PeerConnectionPointer { public: using size_type = ResolvedPeers::size_type; PeerConnectionPointer() = default; PeerConnectionPointer(std::nullptr_t): PeerConnectionPointer() {} ///< implicit nullptr conversion PeerConnectionPointer(const Comm::ConnectionPointer &conn, const size_type pos): connection_(conn), position_(pos) {} /* read-only pointer API; for Connection assignment, see finalize() */ explicit operator bool() const { return static_cast(connection_); } Comm::Connection *operator->() const { assert(connection_); return connection_.getRaw(); } Comm::Connection &operator *() const { assert(connection_); return *connection_; } /// convenience conversion to Comm::ConnectionPointer operator const Comm::ConnectionPointer&() const { return connection_; } /// upgrade stored peer selection details with a matching actual connection void finalize(const Comm::ConnectionPointer &conn) { connection_ = conn; } /// debugging dump void print(std::ostream &) const; private: /// non-existent position for nil connection static constexpr auto npos = std::numeric_limits::max(); /// half-baked, open, failed, or closed Comm::Connection (or nil) Comm::ConnectionPointer connection_; /// ResolvedPeers-maintained membership index (or npos) size_type position_ = npos; friend class ResolvedPeers; }; /// summarized ResolvedPeers (for debugging) std::ostream &operator <<(std::ostream &, const ResolvedPeers &); inline std::ostream & operator <<(std::ostream &os, const PeerConnectionPointer &dest) { dest.print(os); return os; } #endif /* SQUID_SRC_RESOLVEDPEERS_H */