]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ResolvedPeers.cc
f7620134e2b704599abc2ab50166d67839c91e1e
[thirdparty/squid.git] / src / ResolvedPeers.cc
1 /*
2 * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
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
16 ResolvedPeers::ResolvedPeers()
17 {
18 if (Config.forward_max_tries > 0)
19 paths_.reserve(Config.forward_max_tries);
20 }
21
22 void
23 ResolvedPeers::retryPath(const Comm::ConnectionPointer &path)
24 {
25 debugs(17, 4, path);
26 assert(path);
27 paths_.emplace(paths_.begin(), path);
28 }
29
30 void
31 ResolvedPeers::addPath(const Comm::ConnectionPointer &path)
32 {
33 paths_.emplace_back(path);
34 }
35
36 Comm::ConnectionPointer
37 ResolvedPeers::extractFront()
38 {
39 Must(!empty());
40 return extractFound("first: ", paths_.begin());
41 }
42
43 Comm::ConnectionPointer
44 ResolvedPeers::extractPrime(const Comm::Connection &currentPeer)
45 {
46 if (!empty()) {
47 const auto peerToMatch = currentPeer.getPeer();
48 const auto familyToMatch = ConnectionFamily(currentPeer);
49 const auto &conn = paths_.front();
50 if (conn->getPeer() == peerToMatch && familyToMatch == ConnectionFamily(*conn))
51 return extractFound("same-peer same-family match: ", paths_.begin());
52 }
53
54 debugs(17, 7, "no same-peer same-family paths");
55 return nullptr;
56 }
57
58 /// If spare paths exist for currentPeer, returns the first spare path iterator.
59 /// Otherwise, if there are paths for other peers, returns one of those.
60 /// Otherwise, returns the end() iterator.
61 Comm::ConnectionList::iterator
62 ResolvedPeers::findSpareOrNextPeer(const Comm::Connection &currentPeer)
63 {
64 const auto peerToMatch = currentPeer.getPeer();
65 const auto familyToAvoid = ConnectionFamily(currentPeer);
66 // Optimization: Also stop at the first mismatching peer because all
67 // same-peer paths are grouped together.
68 return std::find_if(paths_.begin(), paths_.end(),
69 [peerToMatch, familyToAvoid](const Comm::ConnectionPointer &conn) {
70 return peerToMatch != conn->getPeer() ||
71 familyToAvoid != ConnectionFamily(*conn);
72 });
73 }
74
75 Comm::ConnectionPointer
76 ResolvedPeers::extractSpare(const Comm::Connection &currentPeer)
77 {
78 auto found = findSpareOrNextPeer(currentPeer);
79 if (found != paths_.end() && currentPeer.getPeer() == (*found)->getPeer())
80 return extractFound("same-peer different-family match: ", found);
81
82 debugs(17, 7, "no same-peer different-family paths");
83 return nullptr;
84 }
85
86 /// convenience method to finish a successful extract*() call
87 Comm::ConnectionPointer
88 ResolvedPeers::extractFound(const char *description, const Comm::ConnectionList::iterator &found)
89 {
90 const auto path = *found;
91 paths_.erase(found);
92 debugs(17, 7, description << path);
93 return path;
94 }
95
96 bool
97 ResolvedPeers::haveSpare(const Comm::Connection &currentPeer)
98 {
99 const auto found = findSpareOrNextPeer(currentPeer);
100 return found != paths_.end() &&
101 currentPeer.getPeer() == (*found)->getPeer();
102 }
103
104 bool
105 ResolvedPeers::doneWithSpares(const Comm::Connection &currentPeer)
106 {
107 const auto found = findSpareOrNextPeer(currentPeer);
108 if (found == paths_.end())
109 return destinationsFinalized;
110 return currentPeer.getPeer() != (*found)->getPeer();
111 }
112
113 bool
114 ResolvedPeers::doneWithPrimes(const Comm::Connection &currentPeer) const
115 {
116 const auto first = paths_.begin();
117 if (first == paths_.end())
118 return destinationsFinalized;
119 return currentPeer.getPeer() != (*first)->getPeer() ||
120 ConnectionFamily(currentPeer) != ConnectionFamily(**first);
121 }
122
123 bool
124 ResolvedPeers::doneWithPeer(const Comm::Connection &currentPeer) const
125 {
126 const auto first = paths_.begin();
127 if (first == paths_.end())
128 return destinationsFinalized;
129 return currentPeer.getPeer() != (*first)->getPeer();
130 }
131
132 int
133 ResolvedPeers::ConnectionFamily(const Comm::Connection &conn)
134 {
135 return conn.remote.isIPv4() ? AF_INET : AF_INET6;
136 }
137
138 std::ostream &
139 operator <<(std::ostream &os, const ResolvedPeers &peers)
140 {
141 if (peers.empty())
142 return os << "[no paths]";
143 return os << peers.size() << (peers.destinationsFinalized ? "" : "+") << " paths";
144 }
145