]>
Commit | Line | Data |
---|---|---|
55622953 CT |
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 ¤tPeer) | |
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 ¤tPeer) | |
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 | auto found = 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 | if (found != paths_.end() && peerToMatch == (*found)->getPeer()) | |
74 | return found; | |
75 | return paths_.end(); | |
76 | } | |
77 | ||
78 | Comm::ConnectionPointer | |
79 | ResolvedPeers::extractSpare(const Comm::Connection ¤tPeer) | |
80 | { | |
81 | auto found = findSpareOrNextPeer(currentPeer); | |
82 | if (found != paths_.end() && currentPeer.getPeer() == (*found)->getPeer()) | |
83 | return extractFound("same-peer different-family match: ", found); | |
84 | ||
85 | debugs(17, 7, "no same-peer different-family paths"); | |
86 | return nullptr; | |
87 | } | |
88 | ||
89 | /// convenience method to finish a successful extract*() call | |
90 | Comm::ConnectionPointer | |
91 | ResolvedPeers::extractFound(const char *description, const Comm::ConnectionList::iterator &found) | |
92 | { | |
93 | const auto path = *found; | |
94 | paths_.erase(found); | |
95 | debugs(17, 7, description << path); | |
96 | return path; | |
97 | } | |
98 | ||
99 | bool | |
100 | ResolvedPeers::haveSpare(const Comm::Connection ¤tPeer) | |
101 | { | |
102 | const auto found = findSpareOrNextPeer(currentPeer); | |
103 | return found != paths_.end() && | |
104 | currentPeer.getPeer() == (*found)->getPeer(); | |
105 | } | |
106 | ||
107 | bool | |
108 | ResolvedPeers::doneWithSpares(const Comm::Connection ¤tPeer) | |
109 | { | |
110 | const auto found = findSpareOrNextPeer(currentPeer); | |
111 | if (found == paths_.end()) | |
112 | return destinationsFinalized; | |
113 | return currentPeer.getPeer() != (*found)->getPeer(); | |
114 | } | |
115 | ||
116 | bool | |
117 | ResolvedPeers::doneWithPrimes(const Comm::Connection ¤tPeer) const | |
118 | { | |
119 | const auto first = paths_.begin(); | |
120 | if (first == paths_.end()) | |
121 | return destinationsFinalized; | |
122 | return currentPeer.getPeer() != (*first)->getPeer() || | |
123 | ConnectionFamily(currentPeer) != ConnectionFamily(**first); | |
124 | } | |
125 | ||
126 | bool | |
127 | ResolvedPeers::doneWithPeer(const Comm::Connection ¤tPeer) const | |
128 | { | |
129 | const auto first = paths_.begin(); | |
130 | if (first == paths_.end()) | |
131 | return destinationsFinalized; | |
132 | return currentPeer.getPeer() != (*first)->getPeer(); | |
133 | } | |
134 | ||
135 | int | |
136 | ResolvedPeers::ConnectionFamily(const Comm::Connection &conn) | |
137 | { | |
138 | return conn.remote.isIPv4() ? AF_INET : AF_INET6; | |
139 | } | |
140 | ||
141 | std::ostream & | |
142 | operator <<(std::ostream &os, const ResolvedPeers &peers) | |
143 | { | |
144 | if (peers.empty()) | |
145 | return os << "[no paths]"; | |
146 | return os << peers.size() << (peers.destinationsFinalized ? "" : "+") << " paths"; | |
147 | } | |
148 |