/* * 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. */ #include "squid.h" #include "acl/Gadgets.h" #include "CachePeer.h" #include "defines.h" #include "neighbors.h" #include "NeighborTypeDomainList.h" #include "pconn.h" #include "PeerPoolMgr.h" #include "SquidConfig.h" #include "util.h" CBDATA_CLASS_INIT(CachePeer); CachePeer::CachePeer(const char * const hostname): name(xstrdup(hostname)), host(xstrdup(hostname)) { Tolower(host); // but .name preserves original spelling } CachePeer::~CachePeer() { xfree(name); xfree(host); while (NeighborTypeDomainList *l = typelist) { typelist = l->next; xfree(l->domain); xfree(l); } aclDestroyAccessList(&access); #if USE_CACHE_DIGESTS cbdataReferenceDone(digest); xfree(digest_url); #endif delete next; xfree(login); delete standby.pool; // the mgr job will notice that its owner is gone and stop PeerPoolMgr::Checkpoint(standby.mgr, "peer gone"); xfree(domain); } void CachePeer::noteSuccess() { if (!tcp_up) { debugs(15, 2, "connection to " << *this << " succeeded"); tcp_up = connect_fail_limit; // NP: so peerAlive() works properly. peerAlive(this); } else { tcp_up = connect_fail_limit; } } void CachePeer::noteFailure(const Http::StatusCode code) { if (Http::Is4xx(code)) return; // this failure is not our fault countFailure(); } // TODO: Require callers to detail failures instead of using one (and often // misleading!) "connection failed" phrase for all of them. /// noteFailure() helper for handling failures attributed to this peer void CachePeer::countFailure() { stats.last_connect_failure = squid_curtime; if (tcp_up > 0) --tcp_up; const auto consideredAliveByAdmin = (stats.logged_state == PEER_ALIVE); const auto level = consideredAliveByAdmin ? DBG_IMPORTANT : 2; debugs(15, level, "ERROR: Connection to " << *this << " failed"); if (consideredAliveByAdmin) { if (!tcp_up) { debugs(15, DBG_IMPORTANT, "Detected DEAD " << neighborTypeStr(this) << ": " << name); stats.logged_state = PEER_DEAD; } else { debugs(15, 2, "additional failures needed to mark this cache_peer DEAD: " << tcp_up); } } else { assert(!tcp_up); debugs(15, 2, "cache_peer " << *this << " is still DEAD"); } } void CachePeer::rename(const char * const newName) { if (!newName || !*newName) throw TextException("cache_peer name=value cannot be empty", Here()); xfree(name); name = xstrdup(newName); } time_t CachePeer::connectTimeout() const { if (connect_timeout_raw > 0) return connect_timeout_raw; return Config.Timeout.peer_connect; } std::ostream & operator <<(std::ostream &os, const CachePeer &p) { return os << p.name; }