]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ResolvedPeers.cc
Bug 3552 pt3: Happy Eyeballs: Parallel TCP connection attempts (#386)
[thirdparty/squid.git] / src / ResolvedPeers.cc
CommitLineData
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
16ResolvedPeers::ResolvedPeers()
17{
18 if (Config.forward_max_tries > 0)
19 paths_.reserve(Config.forward_max_tries);
20}
21
22void
23ResolvedPeers::retryPath(const Comm::ConnectionPointer &path)
24{
25 debugs(17, 4, path);
26 assert(path);
27 paths_.emplace(paths_.begin(), path);
28}
29
30void
31ResolvedPeers::addPath(const Comm::ConnectionPointer &path)
32{
33 paths_.emplace_back(path);
34}
35
36Comm::ConnectionPointer
37ResolvedPeers::extractFront()
38{
39 Must(!empty());
40 return extractFound("first: ", paths_.begin());
41}
42
43Comm::ConnectionPointer
44ResolvedPeers::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.
61Comm::ConnectionList::iterator
62ResolvedPeers::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 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
78Comm::ConnectionPointer
79ResolvedPeers::extractSpare(const Comm::Connection &currentPeer)
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
90Comm::ConnectionPointer
91ResolvedPeers::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
99bool
100ResolvedPeers::haveSpare(const Comm::Connection &currentPeer)
101{
102 const auto found = findSpareOrNextPeer(currentPeer);
103 return found != paths_.end() &&
104 currentPeer.getPeer() == (*found)->getPeer();
105}
106
107bool
108ResolvedPeers::doneWithSpares(const Comm::Connection &currentPeer)
109{
110 const auto found = findSpareOrNextPeer(currentPeer);
111 if (found == paths_.end())
112 return destinationsFinalized;
113 return currentPeer.getPeer() != (*found)->getPeer();
114}
115
116bool
117ResolvedPeers::doneWithPrimes(const Comm::Connection &currentPeer) 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
126bool
127ResolvedPeers::doneWithPeer(const Comm::Connection &currentPeer) const
128{
129 const auto first = paths_.begin();
130 if (first == paths_.end())
131 return destinationsFinalized;
132 return currentPeer.getPeer() != (*first)->getPeer();
133}
134
135int
136ResolvedPeers::ConnectionFamily(const Comm::Connection &conn)
137{
138 return conn.remote.isIPv4() ? AF_INET : AF_INET6;
139}
140
141std::ostream &
142operator <<(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