]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ResolvedPeers.cc
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / ResolvedPeers.cc
CommitLineData
55622953 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
55622953
CT
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9#include "squid.h"
10#include "CachePeer.h"
11#include "comm/Connection.h"
12#include "comm/ConnOpener.h"
13#include "ResolvedPeers.h"
14#include "SquidConfig.h"
15
16ResolvedPeers::ResolvedPeers()
17{
18 if (Config.forward_max_tries > 0)
19 paths_.reserve(Config.forward_max_tries);
20}
21
22void
9b7992d9 23ResolvedPeers::reinstatePath(const PeerConnectionPointer &path)
55622953
CT
24{
25 debugs(17, 4, path);
26 assert(path);
9b7992d9
EB
27
28 const auto pos = path.position_;
29 assert(pos < paths_.size());
30
31 assert(!paths_[pos].available);
32 paths_[pos].available = true;
a4d576de
EB
33 increaseAvailability();
34
35 // if we restored availability of a path that we used to skip, update
9b7992d9 36 const auto pathsToTheLeft = pos;
a4d576de
EB
37 if (pathsToTheLeft < pathsToSkip) {
38 pathsToSkip = pathsToTheLeft;
39 } else {
40 // *found was unavailable so pathsToSkip could not end at it
41 Must(pathsToTheLeft != pathsToSkip);
42 }
55622953
CT
43}
44
45void
46ResolvedPeers::addPath(const Comm::ConnectionPointer &path)
47{
48 paths_.emplace_back(path);
a4d576de
EB
49 Must(paths_.back().available); // no pathsToSkip updates are needed
50 increaseAvailability();
51}
52
53/// \returns the beginning iterator for any available-path search
54ResolvedPeers::Paths::iterator
55ResolvedPeers::start()
56{
57 Must(pathsToSkip <= paths_.size());
58 return paths_.begin() + pathsToSkip; // may return end()
59}
60
61/// finalizes the iterator part of the given preliminary find*() result
62ResolvedPeers::Finding
63ResolvedPeers::makeFinding(const Paths::iterator &path, bool foundOther)
64{
65 return std::make_pair((foundOther ? paths_.end() : path), foundOther);
66}
67
68/// \returns the first available same-peer same-family Finding or <end,...>
69ResolvedPeers::Finding
70ResolvedPeers::findPrime(const Comm::Connection &currentPeer)
71{
72 const auto path = start();
73 const auto foundNextOrSpare = path != paths_.end() &&
70ac5b29 74 (currentPeer.getPeer() != path->connection->getPeer() || // next peer
75 ConnectionFamily(currentPeer) != ConnectionFamily(*path->connection));
a4d576de
EB
76 return makeFinding(path, foundNextOrSpare);
77}
78
79/// \returns the first available same-peer different-family Finding or <end,...>
80ResolvedPeers::Finding
81ResolvedPeers::findSpare(const Comm::Connection &currentPeer)
82{
83 const auto primeFamily = ConnectionFamily(currentPeer);
84 const auto primePeer = currentPeer.getPeer();
85 const auto path = std::find_if(start(), paths_.end(),
86 [primeFamily, primePeer](const ResolvedPeerPath &candidate) {
87 if (!candidate.available)
88 return false;
89 if (primePeer != candidate.connection->getPeer())
90 return true; // found next peer
91 if (primeFamily != ConnectionFamily(*candidate.connection))
92 return true; // found spare
93 return false;
94 });
95 const auto foundNext = path != paths_.end() &&
70ac5b29 96 primePeer != path->connection->getPeer();
a4d576de
EB
97 return makeFinding(path, foundNext);
98}
99
100/// \returns the first available same-peer Finding or <end,...>
101ResolvedPeers::Finding
102ResolvedPeers::findPeer(const Comm::Connection &currentPeer)
103{
104 const auto path = start();
105 const auto foundNext = path != paths_.end() &&
70ac5b29 106 currentPeer.getPeer() != path->connection->getPeer();
a4d576de 107 return makeFinding(path, foundNext);
55622953
CT
108}
109
9b7992d9 110PeerConnectionPointer
55622953
CT
111ResolvedPeers::extractFront()
112{
113 Must(!empty());
a4d576de 114 return extractFound("first: ", start());
55622953
CT
115}
116
9b7992d9 117PeerConnectionPointer
55622953
CT
118ResolvedPeers::extractPrime(const Comm::Connection &currentPeer)
119{
a4d576de
EB
120 const auto found = findPrime(currentPeer).first;
121 if (found != paths_.end())
122 return extractFound("same-peer same-family match: ", found);
55622953
CT
123
124 debugs(17, 7, "no same-peer same-family paths");
125 return nullptr;
126}
127
9b7992d9 128PeerConnectionPointer
55622953
CT
129ResolvedPeers::extractSpare(const Comm::Connection &currentPeer)
130{
a4d576de
EB
131 const auto found = findSpare(currentPeer).first;
132 if (found != paths_.end())
55622953
CT
133 return extractFound("same-peer different-family match: ", found);
134
135 debugs(17, 7, "no same-peer different-family paths");
136 return nullptr;
137}
138
139/// convenience method to finish a successful extract*() call
9b7992d9 140PeerConnectionPointer
a4d576de 141ResolvedPeers::extractFound(const char *description, const Paths::iterator &found)
55622953 142{
a4d576de
EB
143 auto &path = *found;
144 debugs(17, 7, description << path.connection);
145 assert(path.available);
146 path.available = false;
147 decreaseAvailability();
148
149 // if we extracted the left-most available path, find the next one
150 if (static_cast<size_type>(found - paths_.begin()) == pathsToSkip) {
151 while (++pathsToSkip < paths_.size() && !paths_[pathsToSkip].available) {}
152 }
153
2b6b1bcb 154 const auto cleanPath = path.connection->cloneProfile();
9b7992d9 155 return PeerConnectionPointer(cleanPath, found - paths_.begin());
55622953
CT
156}
157
158bool
159ResolvedPeers::haveSpare(const Comm::Connection &currentPeer)
160{
a4d576de
EB
161 return findSpare(currentPeer).first != paths_.end();
162}
163
164/// whether paths_ have no (and will have no) Xs for the current peer based on
165/// the given findX(current peer) result
166bool
167ResolvedPeers::doneWith(const Finding &findings) const
168{
169 if (findings.first != paths_.end())
170 return false; // not done because the caller found a viable path X
171
172 // The caller did not find any path X. If the caller found any "other"
173 // paths, then we are done with paths X. If there are no "other" paths,
174 // then destinationsFinalized is the answer.
175 return findings.second ? true : destinationsFinalized;
55622953
CT
176}
177
178bool
179ResolvedPeers::doneWithSpares(const Comm::Connection &currentPeer)
180{
a4d576de 181 return doneWith(findSpare(currentPeer));
55622953
CT
182}
183
184bool
a4d576de 185ResolvedPeers::doneWithPrimes(const Comm::Connection &currentPeer)
55622953 186{
a4d576de 187 return doneWith(findPrime(currentPeer));
55622953
CT
188}
189
190bool
a4d576de 191ResolvedPeers::doneWithPeer(const Comm::Connection &currentPeer)
55622953 192{
a4d576de 193 return doneWith(findPeer(currentPeer));
55622953
CT
194}
195
196int
197ResolvedPeers::ConnectionFamily(const Comm::Connection &conn)
198{
199 return conn.remote.isIPv4() ? AF_INET : AF_INET6;
200}
201
a4d576de
EB
202/// increments the number of available paths
203void
204ResolvedPeers::increaseAvailability()
205{
206 ++availablePaths;
207 assert(availablePaths <= paths_.size());
208}
209
210/// decrements the number of available paths
211void
212ResolvedPeers::decreaseAvailability()
213{
214 assert(availablePaths > 0);
215 --availablePaths;
216}
217
55622953
CT
218std::ostream &
219operator <<(std::ostream &os, const ResolvedPeers &peers)
220{
221 if (peers.empty())
222 return os << "[no paths]";
223 return os << peers.size() << (peers.destinationsFinalized ? "" : "+") << " paths";
224}
225
9b7992d9
EB
226/* PeerConnectionPointer */
227
228void
229PeerConnectionPointer::print(std::ostream &os) const
230{
231 // We should see no combinations of a nil connection and a set position
232 // because assigning nullptr (to our smart pointer) naturally erases both
233 // fields. We report such unexpected combinations for debugging sake, but do
234 // not complicate this code to report them beautifully.
235
236 if (connection_)
237 os << connection_;
238
239 if (position_ != npos)
240 os << " @" << position_;
241}
70ac5b29 242