]>
Commit | Line | Data |
---|---|---|
062e2281 | 1 | /* |
ef57eb7b | 2 | * Copyright (C) 1996-2016 The Squid Software Foundation and contributors |
e25c139f | 3 | * |
bbc27441 AJ |
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. | |
062e2281 | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 44 Peer Selection Algorithm */ |
10 | ||
582c2af2 FC |
11 | #include "squid.h" |
12 | #include "acl/FilledChecklist.h" | |
a011edee | 13 | #include "CachePeer.h" |
21c22f04 | 14 | #include "carp.h" |
582c2af2 | 15 | #include "client_side.h" |
4a3b98d7 | 16 | #include "dns/LookupDetails.h" |
a37fdd8a | 17 | #include "errorpage.h" |
a553a5a3 | 18 | #include "event.h" |
eb13c21e | 19 | #include "FwdState.h" |
af69c635 | 20 | #include "globals.h" |
bbaf2685 | 21 | #include "hier_code.h" |
924f73bc | 22 | #include "htcp.h" |
8d664cb0 | 23 | #include "http/StreamContext.h" |
582c2af2 | 24 | #include "HttpRequest.h" |
9b5c4a9a | 25 | #include "icmp/net_db.h" |
582c2af2 | 26 | #include "ICP.h" |
c7a52e6d | 27 | #include "ip/tools.h" |
602d9612 | 28 | #include "ipcache.h" |
f0ba2534 | 29 | #include "neighbors.h" |
f795b373 | 30 | #include "peer_sourcehash.h" |
37236ba1 | 31 | #include "peer_userhash.h" |
582c2af2 | 32 | #include "PeerSelectState.h" |
4d5904f7 | 33 | #include "SquidConfig.h" |
582c2af2 FC |
34 | #include "SquidTime.h" |
35 | #include "Store.h" | |
769c64cc | 36 | #include "URL.h" |
062e2281 | 37 | |
26ac0430 | 38 | static struct { |
75e88d56 | 39 | int timeouts; |
2fadd50d | 40 | } PeerStats; |
062e2281 | 41 | |
26ac0430 AJ |
42 | static const char *DirectStr[] = { |
43 | "DIRECT_UNKNOWN", | |
44 | "DIRECT_NO", | |
45 | "DIRECT_MAYBE", | |
46 | "DIRECT_YES" | |
47 | }; | |
75e88d56 | 48 | |
f5b8bbc4 | 49 | static void peerSelectFoo(ps_state *); |
50 | static void peerPingTimeout(void *data); | |
86aebcda | 51 | static IRCB peerHandlePingReply; |
a3c6762c | 52 | static void peerIcpParentMiss(CachePeer *, icp_common_t *, ps_state *); |
44e237d0 | 53 | #if USE_HTCP |
fad2588a FC |
54 | static void peerHtcpParentMiss(CachePeer *, HtcpReplyData *, ps_state *); |
55 | static void peerHandleHtcpReply(CachePeer *, peer_t, HtcpReplyData *, void *); | |
44e237d0 | 56 | #endif |
f5b8bbc4 | 57 | static int peerCheckNetdbDirect(ps_state * psstate); |
db1cd23c | 58 | static void peerGetSomeNeighbor(ps_state *); |
59 | static void peerGetSomeNeighborReplies(ps_state *); | |
60 | static void peerGetSomeDirect(ps_state *); | |
61 | static void peerGetSomeParent(ps_state *); | |
168dfda9 | 62 | static void peerGetAllParents(ps_state *); |
a3c6762c | 63 | static void peerAddFwdServer(FwdServer **, CachePeer *, hier_code); |
d67acb4e | 64 | static void peerSelectPinned(ps_state * ps); |
4a3b98d7 | 65 | static void peerSelectDnsResults(const ipcache_addrs *ia, const Dns::LookupDetails &details, void *data); |
cfd66529 | 66 | |
aa839030 | 67 | CBDATA_CLASS_INIT(ps_state); |
68 | ||
029c8349 | 69 | ps_state::~ps_state() |
348b2031 | 70 | { |
36339742 AJ |
71 | while (servers) { |
72 | FwdServer *next = servers->next; | |
73 | cbdataReferenceDone(servers->_peer); | |
74 | memFree(servers, MEM_FWD_SERVER); | |
75 | servers = next; | |
76 | } | |
77 | ||
029c8349 AJ |
78 | if (entry) { |
79 | debugs(44, 3, entry->url()); | |
5ae21d99 | 80 | |
029c8349 AJ |
81 | if (entry->ping_status == PING_WAITING) |
82 | eventDelete(peerPingTimeout, this); | |
5ae21d99 | 83 | |
029c8349 | 84 | entry->ping_status = PING_DONE; |
5ae21d99 AJ |
85 | } |
86 | ||
029c8349 AJ |
87 | if (acl_checklist) { |
88 | debugs(44, DBG_IMPORTANT, "calling aclChecklistFree() from ps_state destructor"); | |
89 | delete acl_checklist; | |
348b2031 | 90 | } |
62e76326 | 91 | |
029c8349 | 92 | HTTPMSGUNLOCK(request); |
62e76326 | 93 | |
029c8349 AJ |
94 | if (entry) { |
95 | assert(entry->ping_status != PING_WAITING); | |
1f90fd4a | 96 | entry->unlock("peerSelect"); |
029c8349 | 97 | entry = NULL; |
73a201f8 | 98 | } |
62e76326 | 99 | |
029c8349 | 100 | delete lastError; |
348b2031 | 101 | } |
062e2281 | 102 | |
2d72d4fd | 103 | static int |
190154cf | 104 | peerSelectIcpPing(HttpRequest * request, int direct, StoreEntry * entry) |
062e2281 | 105 | { |
7b665aeb | 106 | int n; |
db1cd23c | 107 | assert(entry); |
108 | assert(entry->ping_status == PING_NONE); | |
9bd6a36d | 109 | assert(direct != DIRECT_YES); |
4d75742e | 110 | debugs(44, 3, "peerSelectIcpPing: " << entry->url()); |
62e76326 | 111 | |
45e5102d | 112 | if (!request->flags.hierarchical && direct != DIRECT_NO) |
62e76326 | 113 | return 0; |
114 | ||
d46a87a8 | 115 | if (EBIT_TEST(entry->flags, KEY_PRIVATE) && !neighbors_do_private_keys) |
62e76326 | 116 | if (direct != DIRECT_NO) |
117 | return 0; | |
118 | ||
7b665aeb | 119 | n = neighborsCount(request); |
62e76326 | 120 | |
bf8fe701 | 121 | debugs(44, 3, "peerSelectIcpPing: counted " << n << " neighbors"); |
62e76326 | 122 | |
7b665aeb | 123 | return n; |
062e2281 | 124 | } |
125 | ||
062e2281 | 126 | void |
00ae51e4 | 127 | peerSelect(Comm::ConnectionList * paths, |
cfd66529 | 128 | HttpRequest * request, |
d4806c91 | 129 | AccessLogEntry::Pointer const &al, |
62e76326 | 130 | StoreEntry * entry, |
131 | PSC * callback, | |
132 | void *callback_data) | |
75e88d56 | 133 | { |
28c60158 | 134 | ps_state *psstate; |
62e76326 | 135 | |
86b389fc | 136 | if (entry) |
7f06a3d8 | 137 | debugs(44, 3, *entry << ' ' << entry->url()); |
86b389fc | 138 | else |
7f06a3d8 | 139 | debugs(44, 3, request->method); |
62e76326 | 140 | |
b24880fe | 141 | psstate = new ps_state; |
62e76326 | 142 | |
b248c2a3 AJ |
143 | psstate->request = request; |
144 | HTTPMSGLOCK(psstate->request); | |
d4806c91 | 145 | psstate->al = al; |
62e76326 | 146 | |
b6c0e933 | 147 | psstate->entry = entry; |
cfd66529 AJ |
148 | psstate->paths = paths; |
149 | ||
b6c0e933 | 150 | psstate->callback = callback; |
62e76326 | 151 | |
fa80a8ef | 152 | psstate->callback_data = cbdataReference(callback_data); |
62e76326 | 153 | |
6cfa8966 | 154 | #if USE_CACHE_DIGESTS |
62e76326 | 155 | |
39edba21 | 156 | request->hier.peer_select_start = current_time; |
62e76326 | 157 | |
39edba21 | 158 | #endif |
62e76326 | 159 | |
2395cb21 | 160 | if (psstate->entry) |
1bfe9ade | 161 | psstate->entry->lock("peerSelect"); |
62e76326 | 162 | |
b6c0e933 | 163 | peerSelectFoo(psstate); |
75e88d56 | 164 | } |
165 | ||
166 | static void | |
2efeb0b7 | 167 | peerCheckNeverDirectDone(allow_t answer, void *data) |
75e88d56 | 168 | { |
e6ccf245 | 169 | ps_state *psstate = (ps_state *) data; |
348b2031 | 170 | psstate->acl_checklist = NULL; |
bf8fe701 | 171 | debugs(44, 3, "peerCheckNeverDirectDone: " << answer); |
2efeb0b7 | 172 | psstate->never_direct = answer; |
3985b3f8 | 173 | switch (answer) { |
ae026ec6 | 174 | case ACCESS_ALLOWED: |
f365d297 AJ |
175 | /** if never_direct says YES, do that. */ |
176 | psstate->direct = DIRECT_NO; | |
ae026ec6 AJ |
177 | debugs(44, 3, HERE << "direct = " << DirectStr[psstate->direct] << " (never_direct allow)"); |
178 | break; | |
179 | case ACCESS_DENIED: // not relevant. | |
1f585949 | 180 | case ACCESS_DUNNO: // not relevant. |
ae026ec6 | 181 | break; |
1f585949 | 182 | case ACCESS_AUTH_REQUIRED: |
ae026ec6 | 183 | debugs(44, DBG_IMPORTANT, "WARNING: never_direct resulted in " << answer << ". Username ACLs are not reliable here."); |
1f585949 | 184 | break; |
ae026ec6 | 185 | } |
b6c0e933 | 186 | peerSelectFoo(psstate); |
75e88d56 | 187 | } |
188 | ||
189 | static void | |
2efeb0b7 | 190 | peerCheckAlwaysDirectDone(allow_t answer, void *data) |
75e88d56 | 191 | { |
e6ccf245 | 192 | ps_state *psstate = (ps_state *)data; |
348b2031 | 193 | psstate->acl_checklist = NULL; |
bf8fe701 | 194 | debugs(44, 3, "peerCheckAlwaysDirectDone: " << answer); |
2efeb0b7 | 195 | psstate->always_direct = answer; |
3985b3f8 | 196 | switch (answer) { |
ae026ec6 AJ |
197 | case ACCESS_ALLOWED: |
198 | /** if always_direct says YES, do that. */ | |
199 | psstate->direct = DIRECT_YES; | |
200 | debugs(44, 3, HERE << "direct = " << DirectStr[psstate->direct] << " (always_direct allow)"); | |
201 | break; | |
202 | case ACCESS_DENIED: // not relevant. | |
1f585949 | 203 | case ACCESS_DUNNO: // not relevant. |
ae026ec6 | 204 | break; |
1f585949 | 205 | case ACCESS_AUTH_REQUIRED: |
ae026ec6 | 206 | debugs(44, DBG_IMPORTANT, "WARNING: always_direct resulted in " << answer << ". Username ACLs are not reliable here."); |
1f585949 | 207 | break; |
ae026ec6 | 208 | } |
b6c0e933 | 209 | peerSelectFoo(psstate); |
75e88d56 | 210 | } |
211 | ||
cfd66529 AJ |
212 | void |
213 | peerSelectDnsPaths(ps_state *psstate) | |
214 | { | |
215 | FwdServer *fs = psstate->servers; | |
216 | ||
36339742 AJ |
217 | if (!cbdataReferenceValid(psstate->callback_data)) { |
218 | debugs(44, 3, "Aborting peer selection. Parent Job went away."); | |
219 | delete psstate; | |
220 | return; | |
221 | } | |
222 | ||
7177edfb AJ |
223 | // Bug 3243: CVE 2009-0801 |
224 | // Bypass of browser same-origin access control in intercepted communication | |
225 | // To resolve this we must use only the original client destination when going DIRECT | |
226 | // on intercepted traffic which failed Host verification | |
227 | const HttpRequest *req = psstate->request; | |
45e5102d | 228 | const bool isIntercepted = !req->flags.redirected && |
0d901ef4 | 229 | (req->flags.intercepted || req->flags.interceptTproxy); |
45e5102d | 230 | const bool useOriginalDst = Config.onoff.client_dst_passthru || !req->flags.hostVerified; |
7177edfb AJ |
231 | const bool choseDirect = fs && fs->code == HIER_DIRECT; |
232 | if (isIntercepted && useOriginalDst && choseDirect) { | |
d9371d7b AJ |
233 | // check the client is still around before using any of its details |
234 | if (req->clientConnectionManager.valid()) { | |
235 | // construct a "result" adding the ORIGINAL_DST to the set instead of DIRECT | |
236 | Comm::ConnectionPointer p = new Comm::Connection(); | |
237 | p->remote = req->clientConnectionManager->clientConnection->local; | |
e7605be9 | 238 | p->peerType = ORIGINAL_DST; // fs->code is DIRECT. This fixes the display. |
d9371d7b AJ |
239 | p->setPeer(fs->_peer); |
240 | ||
241 | // check for a configured outgoing address for this destination... | |
242 | getOutgoingAddress(psstate->request, p); | |
243 | psstate->paths->push_back(p); | |
244 | } | |
7177edfb AJ |
245 | |
246 | // clear the used fs and continue | |
247 | psstate->servers = fs->next; | |
248 | cbdataReferenceDone(fs->_peer); | |
249 | memFree(fs, MEM_FWD_SERVER); | |
250 | peerSelectDnsPaths(psstate); | |
251 | return; | |
252 | } | |
253 | ||
cfd66529 | 254 | // convert the list of FwdServer destinations into destinations IP addresses |
d6327017 | 255 | if (fs && psstate->paths->size() < (unsigned int)Config.forward_max_tries) { |
cfd66529 | 256 | // send the next one off for DNS lookup. |
5c51bffb | 257 | const char *host = fs->_peer ? fs->_peer->host : psstate->request->url.host(); |
4d75742e | 258 | debugs(44, 2, "Find IP destination for: " << psstate->url() << "' via " << host); |
cfd66529 AJ |
259 | ipcache_nbgethostbyname(host, peerSelectDnsResults, psstate); |
260 | return; | |
261 | } | |
262 | ||
c2f4e9cc AJ |
263 | // Bug 3605: clear any extra listed FwdServer destinations, when the options exceeds max_foward_tries. |
264 | // due to the allocation method of fs, we must deallocate each manually. | |
265 | // TODO: use a std::list so we can get the size and abort adding whenever the selection loops reach Config.forward_max_tries | |
266 | if (fs && psstate->paths->size() >= (unsigned int)Config.forward_max_tries) { | |
07636178 | 267 | assert(fs == psstate->servers); |
9bc68187 | 268 | while (fs) { |
07636178 | 269 | psstate->servers = fs->next; |
c2f4e9cc AJ |
270 | cbdataReferenceDone(fs->_peer); |
271 | memFree(fs, MEM_FWD_SERVER); | |
07636178 | 272 | fs = psstate->servers; |
c2f4e9cc AJ |
273 | } |
274 | } | |
275 | ||
cfd66529 | 276 | // done with DNS lookups. pass back to caller |
3dfe8371 | 277 | PSC *callback = psstate->callback; |
fa80a8ef | 278 | psstate->callback = NULL; |
62e76326 | 279 | |
769c64cc AJ |
280 | debugs(44, 2, (psstate->paths->size()<1?"Failed to select source":"Found sources") << " for '" << psstate->url() << "'"); |
281 | debugs(44, 2, " always_direct = " << psstate->always_direct); | |
282 | debugs(44, 2, " never_direct = " << psstate->never_direct); | |
283 | if (psstate->paths) { | |
5db6bf73 | 284 | for (size_t i = 0; i < psstate->paths->size(); ++i) { |
ce63af7f AJ |
285 | if ((*psstate->paths)[i]->peerType == HIER_DIRECT) |
286 | debugs(44, 2, " DIRECT = " << (*psstate->paths)[i]); | |
7177edfb AJ |
287 | else if ((*psstate->paths)[i]->peerType == ORIGINAL_DST) |
288 | debugs(44, 2, " ORIGINAL_DST = " << (*psstate->paths)[i]); | |
289 | else if ((*psstate->paths)[i]->peerType == PINNED) | |
290 | debugs(44, 2, " PINNED = " << (*psstate->paths)[i]); | |
ce63af7f AJ |
291 | else |
292 | debugs(44, 2, " cache_peer = " << (*psstate->paths)[i]); | |
efbd2436 | 293 | } |
5ae21d99 | 294 | } |
769c64cc | 295 | debugs(44, 2, " timedout = " << psstate->ping.timedout); |
5ae21d99 AJ |
296 | |
297 | psstate->ping.stop = current_time; | |
298 | psstate->request->hier.ping = psstate->ping; | |
3dfe8371 | 299 | |
cfd66529 | 300 | void *cbdata; |
fa80a8ef | 301 | if (cbdataReferenceValidDone(psstate->callback_data, &cbdata)) { |
a37fdd8a AJ |
302 | callback(psstate->paths, psstate->lastError, cbdata); |
303 | psstate->lastError = NULL; // FwdState has taken control over the ErrorState object. | |
db1cd23c | 304 | } |
62e76326 | 305 | |
029c8349 | 306 | delete psstate; |
93775f90 | 307 | } |
308 | ||
cfd66529 | 309 | static void |
4a3b98d7 | 310 | peerSelectDnsResults(const ipcache_addrs *ia, const Dns::LookupDetails &details, void *data) |
cfd66529 AJ |
311 | { |
312 | ps_state *psstate = (ps_state *)data; | |
313 | ||
36339742 AJ |
314 | if (!cbdataReferenceValid(psstate->callback_data)) { |
315 | debugs(44, 3, "Aborting peer selection. Parent Job went away."); | |
316 | delete psstate; | |
317 | return; | |
318 | } | |
319 | ||
cfd66529 AJ |
320 | psstate->request->recordLookup(details); |
321 | ||
322 | FwdServer *fs = psstate->servers; | |
323 | if (ia != NULL) { | |
324 | ||
325 | assert(ia->cur < ia->count); | |
326 | ||
327 | // loop over each result address, adding to the possible destinations. | |
cfd66529 | 328 | int ip = ia->cur; |
5db6bf73 | 329 | for (int n = 0; n < ia->count; ++n, ++ip) { |
5229395c AJ |
330 | Comm::ConnectionPointer p; |
331 | ||
cfd66529 AJ |
332 | if (ip >= ia->count) ip = 0; // looped back to zero. |
333 | ||
27d1f0a0 | 334 | // Enforce forward_max_tries configuration. |
d6327017 | 335 | if (psstate->paths->size() >= (unsigned int)Config.forward_max_tries) |
27d1f0a0 AJ |
336 | break; |
337 | ||
0d901ef4 | 338 | // for TPROXY spoofing we must skip unusable addresses. |
450fe1cb | 339 | if (psstate->request->flags.spoofClientIp && !(fs->_peer && fs->_peer->options.no_tproxy) ) { |
b43f9931 | 340 | if (ia->in_addrs[ip].isIPv4() != psstate->request->client_addr.isIPv4()) { |
cfd66529 AJ |
341 | // we CAN'T spoof the address on this link. find another. |
342 | continue; | |
343 | } | |
344 | } | |
345 | ||
346 | p = new Comm::Connection(); | |
b43f9931 | 347 | p->remote = ia->in_addrs[ip]; |
c7a52e6d AJ |
348 | |
349 | // when IPv6 is disabled we cannot use it | |
4dd643d5 | 350 | if (!Ip::EnableIpv6 && p->remote.isIPv6()) { |
5c51bffb | 351 | const char *host = (fs->_peer ? fs->_peer->host : psstate->request->url.host()); |
c7a52e6d AJ |
352 | ipcacheMarkBadAddr(host, p->remote); |
353 | continue; | |
354 | } | |
355 | ||
5c51bffb | 356 | p->remote.port(fs->_peer ? fs->_peer->http_port : psstate->request->url.port()); |
5229395c | 357 | p->peerType = fs->code; |
ce63af7f | 358 | p->setPeer(fs->_peer); |
cfd66529 AJ |
359 | |
360 | // check for a configured outgoing address for this destination... | |
361 | getOutgoingAddress(psstate->request, p); | |
07f889c1 | 362 | psstate->paths->push_back(p); |
cfd66529 AJ |
363 | } |
364 | } else { | |
5c51bffb | 365 | debugs(44, 3, "Unknown host: " << (fs->_peer ? fs->_peer->host : psstate->request->url.host())); |
a37fdd8a AJ |
366 | // discard any previous error. |
367 | delete psstate->lastError; | |
368 | psstate->lastError = NULL; | |
369 | if (fs->code == HIER_DIRECT) { | |
955394ce | 370 | psstate->lastError = new ErrorState(ERR_DNS_FAIL, Http::scServiceUnavailable, psstate->request); |
a37fdd8a AJ |
371 | psstate->lastError->dnsError = details.error; |
372 | } | |
cfd66529 AJ |
373 | } |
374 | ||
375 | psstate->servers = fs->next; | |
376 | cbdataReferenceDone(fs->_peer); | |
377 | memFree(fs, MEM_FWD_SERVER); | |
378 | ||
379 | // see if more paths can be found | |
380 | peerSelectDnsPaths(psstate); | |
381 | } | |
382 | ||
b3264694 | 383 | static int |
384 | peerCheckNetdbDirect(ps_state * psstate) | |
385 | { | |
9b5c4a9a | 386 | #if USE_ICMP |
a3c6762c | 387 | CachePeer *p; |
b3264694 | 388 | int myrtt; |
389 | int myhops; | |
62e76326 | 390 | |
0886a797 | 391 | if (psstate->direct == DIRECT_NO) |
62e76326 | 392 | return 0; |
393 | ||
9b5c4a9a AJ |
394 | /* base lookup on RTT and Hops if ICMP NetDB is enabled. */ |
395 | ||
5c51bffb AJ |
396 | myrtt = netdbHostRtt(psstate->request->url.host()); |
397 | debugs(44, 3, "MY RTT = " << myrtt << " msec"); | |
398 | debugs(44, 3, "minimum_direct_rtt = " << Config.minDirectRtt << " msec"); | |
62e76326 | 399 | |
5f84d830 | 400 | if (myrtt && myrtt <= Config.minDirectRtt) |
62e76326 | 401 | return 1; |
402 | ||
5c51bffb | 403 | myhops = netdbHostHops(psstate->request->url.host()); |
62e76326 | 404 | |
bf8fe701 | 405 | debugs(44, 3, "peerCheckNetdbDirect: MY hops = " << myhops); |
406 | debugs(44, 3, "peerCheckNetdbDirect: minimum_direct_hops = " << Config.minDirectHops); | |
62e76326 | 407 | |
b3264694 | 408 | if (myhops && myhops <= Config.minDirectHops) |
62e76326 | 409 | return 1; |
410 | ||
cc192b50 | 411 | p = whichPeer(psstate->closest_parent_miss); |
62e76326 | 412 | |
5f84d830 | 413 | if (p == NULL) |
62e76326 | 414 | return 0; |
415 | ||
bf8fe701 | 416 | debugs(44, 3, "peerCheckNetdbDirect: closest_parent_miss RTT = " << psstate->ping.p_rtt << " msec"); |
62e76326 | 417 | |
5f84d830 | 418 | if (myrtt && myrtt <= psstate->ping.p_rtt) |
62e76326 | 419 | return 1; |
420 | ||
9b5c4a9a AJ |
421 | #endif /* USE_ICMP */ |
422 | ||
b3264694 | 423 | return 0; |
424 | } | |
425 | ||
93775f90 | 426 | static void |
511f47bb | 427 | peerSelectFoo(ps_state * ps) |
062e2281 | 428 | { |
36339742 AJ |
429 | if (!cbdataReferenceValid(ps->callback_data)) { |
430 | debugs(44, 3, "Aborting peer selection. Parent Job went away."); | |
431 | delete ps; | |
432 | return; | |
433 | } | |
434 | ||
511f47bb | 435 | StoreEntry *entry = ps->entry; |
190154cf | 436 | HttpRequest *request = ps->request; |
5c51bffb | 437 | debugs(44, 3, request->method << ' ' << request->url.host()); |
62e76326 | 438 | |
45e5102d | 439 | /** If we don't know whether DIRECT is permitted ... */ |
511f47bb | 440 | if (ps->direct == DIRECT_UNKNOWN) { |
ae026ec6 AJ |
441 | if (ps->always_direct == ACCESS_DUNNO) { |
442 | debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct] << " (always_direct to be checked)"); | |
45e5102d | 443 | /** check always_direct; */ |
d4806c91 CT |
444 | ACLFilledChecklist *ch = new ACLFilledChecklist(Config.accessList.AlwaysDirect, request, NULL); |
445 | ch->al = ps->al; | |
446 | ps->acl_checklist = ch; | |
b50e327b | 447 | ps->acl_checklist->nonBlockingCheck(peerCheckAlwaysDirectDone, ps); |
62e76326 | 448 | return; |
ae026ec6 AJ |
449 | } else if (ps->never_direct == ACCESS_DUNNO) { |
450 | debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct] << " (never_direct to be checked)"); | |
45e5102d | 451 | /** check never_direct; */ |
d4806c91 CT |
452 | ACLFilledChecklist *ch = new ACLFilledChecklist(Config.accessList.NeverDirect, request, NULL); |
453 | ch->al = ps->al; | |
454 | ps->acl_checklist = ch; | |
ae026ec6 | 455 | ps->acl_checklist->nonBlockingCheck(peerCheckNeverDirectDone, ps); |
62e76326 | 456 | return; |
450fe1cb | 457 | } else if (request->flags.noDirect) { |
45e5102d | 458 | /** if we are accelerating, direct is not an option. */ |
62e76326 | 459 | ps->direct = DIRECT_NO; |
ae026ec6 | 460 | debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct] << " (forced non-direct)"); |
450fe1cb | 461 | } else if (request->flags.loopDetected) { |
45e5102d | 462 | /** if we are in a forwarding-loop, direct is not an option. */ |
62e76326 | 463 | ps->direct = DIRECT_YES; |
ae026ec6 | 464 | debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct] << " (forwarding loop detected)"); |
62e76326 | 465 | } else if (peerCheckNetdbDirect(ps)) { |
466 | ps->direct = DIRECT_YES; | |
ae026ec6 | 467 | debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct] << " (checkNetdbDirect)"); |
62e76326 | 468 | } else { |
469 | ps->direct = DIRECT_MAYBE; | |
ae026ec6 | 470 | debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct] << " (default)"); |
62e76326 | 471 | } |
472 | ||
bf8fe701 | 473 | debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct]); |
db1cd23c | 474 | } |
62e76326 | 475 | |
d67acb4e AJ |
476 | if (!entry || entry->ping_status == PING_NONE) |
477 | peerSelectPinned(ps); | |
df503d6c | 478 | if (entry == NULL) { |
62e76326 | 479 | (void) 0; |
df503d6c | 480 | } else if (entry->ping_status == PING_NONE) { |
62e76326 | 481 | peerGetSomeNeighbor(ps); |
482 | ||
483 | if (entry->ping_status == PING_WAITING) | |
484 | return; | |
db1cd23c | 485 | } else if (entry->ping_status == PING_WAITING) { |
62e76326 | 486 | peerGetSomeNeighborReplies(ps); |
487 | entry->ping_status = PING_DONE; | |
db1cd23c | 488 | } |
62e76326 | 489 | |
168dfda9 | 490 | switch (ps->direct) { |
62e76326 | 491 | |
168dfda9 | 492 | case DIRECT_YES: |
62e76326 | 493 | peerGetSomeDirect(ps); |
494 | break; | |
495 | ||
168dfda9 | 496 | case DIRECT_NO: |
62e76326 | 497 | peerGetSomeParent(ps); |
498 | peerGetAllParents(ps); | |
499 | break; | |
500 | ||
168dfda9 | 501 | default: |
62e76326 | 502 | |
503 | if (Config.onoff.prefer_direct) | |
504 | peerGetSomeDirect(ps); | |
505 | ||
45e5102d | 506 | if (request->flags.hierarchical || !Config.onoff.nonhierarchical_direct) { |
62e76326 | 507 | peerGetSomeParent(ps); |
8b9a89c9 AJ |
508 | peerGetAllParents(ps); |
509 | } | |
62e76326 | 510 | |
511 | if (!Config.onoff.prefer_direct) | |
512 | peerGetSomeDirect(ps); | |
513 | ||
514 | break; | |
168dfda9 | 515 | } |
62e76326 | 516 | |
3dfe8371 AJ |
517 | // resolve the possible peers |
518 | peerSelectDnsPaths(ps); | |
db1cd23c | 519 | } |
520 | ||
a3c6762c | 521 | bool peerAllowedToUse(const CachePeer * p, HttpRequest * request); |
cfd66529 | 522 | |
27774cee | 523 | /** |
d67acb4e AJ |
524 | * peerSelectPinned |
525 | * | |
27774cee | 526 | * Selects a pinned connection. |
d67acb4e | 527 | */ |
d67acb4e AJ |
528 | static void |
529 | peerSelectPinned(ps_state * ps) | |
530 | { | |
531 | HttpRequest *request = ps->request; | |
d67acb4e AJ |
532 | if (!request->pinnedConnection()) |
533 | return; | |
a3c6762c | 534 | CachePeer *pear = request->pinnedConnection()->pinnedPeer(); |
e3a4aecc AJ |
535 | if (Comm::IsConnOpen(request->pinnedConnection()->validatePinnedConnection(request, pear))) { |
536 | if (pear && peerAllowedToUse(pear, request)) { | |
537 | peerAddFwdServer(&ps->servers, pear, PINNED); | |
d67acb4e AJ |
538 | if (ps->entry) |
539 | ps->entry->ping_status = PING_DONE; /* Skip ICP */ | |
e3a4aecc | 540 | } else if (!pear && ps->direct != DIRECT_NO) { |
d67acb4e AJ |
541 | peerAddFwdServer(&ps->servers, NULL, PINNED); |
542 | if (ps->entry) | |
543 | ps->entry->ping_status = PING_DONE; /* Skip ICP */ | |
544 | } | |
545 | } | |
546 | } | |
547 | ||
27774cee | 548 | /** |
db1cd23c | 549 | * peerGetSomeNeighbor |
26ac0430 | 550 | * |
db1cd23c | 551 | * Selects a neighbor (parent or sibling) based on one of the |
552 | * following methods: | |
553 | * Cache Digests | |
554 | * CARP | |
9b5c4a9a | 555 | * ICMP Netdb RTT estimates |
db1cd23c | 556 | * ICP/HTCP queries |
557 | */ | |
558 | static void | |
559 | peerGetSomeNeighbor(ps_state * ps) | |
560 | { | |
561 | StoreEntry *entry = ps->entry; | |
190154cf | 562 | HttpRequest *request = ps->request; |
a3c6762c | 563 | CachePeer *p; |
db1cd23c | 564 | hier_code code = HIER_NONE; |
565 | assert(entry->ping_status == PING_NONE); | |
62e76326 | 566 | |
db1cd23c | 567 | if (ps->direct == DIRECT_YES) { |
62e76326 | 568 | entry->ping_status = PING_DONE; |
569 | return; | |
124511e5 | 570 | } |
62e76326 | 571 | |
6cfa8966 | 572 | #if USE_CACHE_DIGESTS |
f66a9ef4 | 573 | if ((p = neighborsDigestSelect(request))) { |
5c51bffb | 574 | if (neighborType(p, request->url) == PEER_PARENT) |
62e76326 | 575 | code = CD_PARENT_HIT; |
576 | else | |
577 | code = CD_SIBLING_HIT; | |
db1cd23c | 578 | } else |
c127134a | 579 | #endif |
62e76326 | 580 | if ((p = netdbClosestParent(request))) { |
581 | code = CLOSEST_PARENT; | |
582 | } else if (peerSelectIcpPing(request, ps->direct, entry)) { | |
bf8fe701 | 583 | debugs(44, 3, "peerSelect: Doing ICP pings"); |
62e76326 | 584 | ps->ping.start = current_time; |
585 | ps->ping.n_sent = neighborsUdpPing(request, | |
586 | entry, | |
587 | peerHandlePingReply, | |
588 | ps, | |
589 | &ps->ping.n_replies_expected, | |
590 | &ps->ping.timeout); | |
591 | ||
592 | if (ps->ping.n_sent == 0) | |
fa84c01d | 593 | debugs(44, DBG_CRITICAL, "WARNING: neighborsUdpPing returned 0"); |
26ac0430 AJ |
594 | debugs(44, 3, "peerSelect: " << ps->ping.n_replies_expected << |
595 | " ICP replies expected, RTT " << ps->ping.timeout << | |
596 | " msec"); | |
62e76326 | 597 | |
62e76326 | 598 | if (ps->ping.n_replies_expected > 0) { |
599 | entry->ping_status = PING_WAITING; | |
600 | eventAdd("peerPingTimeout", | |
601 | peerPingTimeout, | |
602 | ps, | |
603 | 0.001 * ps->ping.timeout, | |
604 | 0); | |
605 | return; | |
606 | } | |
607 | } | |
608 | ||
db1cd23c | 609 | if (code != HIER_NONE) { |
62e76326 | 610 | assert(p); |
4b981814 | 611 | debugs(44, 3, "peerSelect: " << hier_code_str[code] << "/" << p->host); |
62e76326 | 612 | peerAddFwdServer(&ps->servers, p, code); |
db1cd23c | 613 | } |
62e76326 | 614 | |
db1cd23c | 615 | entry->ping_status = PING_DONE; |
616 | } | |
617 | ||
618 | /* | |
619 | * peerGetSomeNeighborReplies | |
26ac0430 | 620 | * |
db1cd23c | 621 | * Selects a neighbor (parent or sibling) based on ICP/HTCP replies. |
622 | */ | |
623 | static void | |
624 | peerGetSomeNeighborReplies(ps_state * ps) | |
625 | { | |
190154cf | 626 | HttpRequest *request = ps->request; |
a3c6762c | 627 | CachePeer *p = NULL; |
db1cd23c | 628 | hier_code code = HIER_NONE; |
4c5a1592 | 629 | assert(ps->entry->ping_status == PING_WAITING); |
db1cd23c | 630 | assert(ps->direct != DIRECT_YES); |
62e76326 | 631 | |
db1cd23c | 632 | if (peerCheckNetdbDirect(ps)) { |
62e76326 | 633 | code = CLOSEST_DIRECT; |
5c51bffb | 634 | debugs(44, 3, hier_code_str[code] << "/" << request->url.host()); |
62e76326 | 635 | peerAddFwdServer(&ps->servers, NULL, code); |
636 | return; | |
db1cd23c | 637 | } |
62e76326 | 638 | |
db1cd23c | 639 | if ((p = ps->hit)) { |
62e76326 | 640 | code = ps->hit_type == PEER_PARENT ? PARENT_HIT : SIBLING_HIT; |
26ac0430 | 641 | } else { |
4dd643d5 | 642 | if (!ps->closest_parent_miss.isAnyAddr()) { |
cc192b50 | 643 | p = whichPeer(ps->closest_parent_miss); |
644 | code = CLOSEST_PARENT_MISS; | |
4dd643d5 | 645 | } else if (!ps->first_parent_miss.isAnyAddr()) { |
cc192b50 | 646 | p = whichPeer(ps->first_parent_miss); |
647 | code = FIRST_PARENT_MISS; | |
648 | } | |
649 | } | |
db1cd23c | 650 | if (p && code != HIER_NONE) { |
5c51bffb | 651 | debugs(44, 3, hier_code_str[code] << "/" << p->host); |
62e76326 | 652 | peerAddFwdServer(&ps->servers, p, code); |
db1cd23c | 653 | } |
654 | } | |
655 | ||
db1cd23c | 656 | /* |
657 | * peerGetSomeDirect | |
26ac0430 | 658 | * |
db1cd23c | 659 | * Simply adds a 'direct' entry to the FwdServers list if this |
660 | * request can be forwarded directly to the origin server | |
661 | */ | |
662 | static void | |
663 | peerGetSomeDirect(ps_state * ps) | |
664 | { | |
665 | if (ps->direct == DIRECT_NO) | |
62e76326 | 666 | return; |
667 | ||
db80e881 | 668 | /* WAIS is not implemented natively */ |
4e3f4dc7 | 669 | if (ps->request->url.getScheme() == AnyP::PROTO_WAIS) |
26ac0430 | 670 | return; |
db80e881 | 671 | |
672 | peerAddFwdServer(&ps->servers, NULL, HIER_DIRECT); | |
db1cd23c | 673 | } |
674 | ||
675 | static void | |
676 | peerGetSomeParent(ps_state * ps) | |
677 | { | |
a3c6762c | 678 | CachePeer *p; |
190154cf | 679 | HttpRequest *request = ps->request; |
db1cd23c | 680 | hier_code code = HIER_NONE; |
5c51bffb | 681 | debugs(44, 3, request->method << ' ' << request->url.host()); |
62e76326 | 682 | |
6b8e7481 | 683 | if (ps->direct == DIRECT_YES) |
62e76326 | 684 | return; |
685 | ||
b4ab8666 AJ |
686 | if ((p = peerSourceHashSelectParent(request))) { |
687 | code = SOURCEHASH_PARENT; | |
2f1431ea | 688 | #if USE_AUTH |
f7e1d9ce HN |
689 | } else if ((p = peerUserHashSelectParent(request))) { |
690 | code = USERHASH_PARENT; | |
2f1431ea | 691 | #endif |
b3995439 | 692 | } else if ((p = carpSelectParent(request))) { |
62e76326 | 693 | code = CARP; |
db1cd23c | 694 | } else if ((p = getRoundRobinParent(request))) { |
62e76326 | 695 | code = ROUNDROBIN_PARENT; |
d1b63fc8 | 696 | } else if ((p = getWeightedRoundRobinParent(request))) { |
62e76326 | 697 | code = ROUNDROBIN_PARENT; |
db1cd23c | 698 | } else if ((p = getFirstUpParent(request))) { |
62e76326 | 699 | code = FIRSTUP_PARENT; |
b4ab8666 AJ |
700 | } else if ((p = getDefaultParent(request))) { |
701 | code = DEFAULT_PARENT; | |
db1cd23c | 702 | } |
62e76326 | 703 | |
db1cd23c | 704 | if (code != HIER_NONE) { |
4b981814 | 705 | debugs(44, 3, "peerSelect: " << hier_code_str[code] << "/" << p->host); |
62e76326 | 706 | peerAddFwdServer(&ps->servers, p, code); |
062e2281 | 707 | } |
708 | } | |
709 | ||
168dfda9 | 710 | /* Adds alive parents. Used as a last resort for never_direct. |
711 | */ | |
712 | static void | |
713 | peerGetAllParents(ps_state * ps) | |
714 | { | |
a3c6762c | 715 | CachePeer *p; |
190154cf | 716 | HttpRequest *request = ps->request; |
168dfda9 | 717 | /* Add all alive parents */ |
62e76326 | 718 | |
168dfda9 | 719 | for (p = Config.peers; p; p = p->next) { |
62e76326 | 720 | /* XXX: neighbors.c lacks a public interface for enumerating |
721 | * parents to a request so we have to dig some here.. | |
722 | */ | |
723 | ||
5c51bffb | 724 | if (neighborType(p, request->url) != PEER_PARENT) |
62e76326 | 725 | continue; |
726 | ||
727 | if (!peerHTTPOkay(p, request)) | |
728 | continue; | |
729 | ||
bf8fe701 | 730 | debugs(15, 3, "peerGetAllParents: adding alive parent " << p->host); |
62e76326 | 731 | |
732 | peerAddFwdServer(&ps->servers, p, ANY_OLD_PARENT); | |
168dfda9 | 733 | } |
62e76326 | 734 | |
168dfda9 | 735 | /* XXX: should add dead parents here, but it is currently |
736 | * not possible to find out which parents are dead or which | |
737 | * simply are not configured to handle the request. | |
738 | */ | |
739 | /* Add default parent as a last resort */ | |
740 | if ((p = getDefaultParent(request))) { | |
62e76326 | 741 | peerAddFwdServer(&ps->servers, p, DEFAULT_PARENT); |
168dfda9 | 742 | } |
743 | } | |
744 | ||
d9586c3c | 745 | static void |
93775f90 | 746 | peerPingTimeout(void *data) |
062e2281 | 747 | { |
e6ccf245 | 748 | ps_state *psstate = (ps_state *)data; |
b6c0e933 | 749 | StoreEntry *entry = psstate->entry; |
62e76326 | 750 | |
fefb0227 | 751 | if (entry) |
cfd861ab | 752 | debugs(44, 3, psstate->url()); |
62e76326 | 753 | |
fa80a8ef | 754 | if (!cbdataReferenceValid(psstate->callback_data)) { |
62e76326 | 755 | /* request aborted */ |
cfd861ab AJ |
756 | if (entry) |
757 | entry->ping_status = PING_DONE; | |
62e76326 | 758 | cbdataReferenceDone(psstate->callback_data); |
029c8349 | 759 | delete psstate; |
62e76326 | 760 | return; |
73a201f8 | 761 | } |
62e76326 | 762 | |
5db6bf73 | 763 | ++PeerStats.timeouts; |
44e237d0 | 764 | psstate->ping.timedout = 1; |
b6c0e933 | 765 | peerSelectFoo(psstate); |
85034133 | 766 | } |
767 | ||
768 | void | |
769 | peerSelectInit(void) | |
770 | { | |
75e88d56 | 771 | memset(&PeerStats, '\0', sizeof(PeerStats)); |
cfd66529 | 772 | memDataInit(MEM_FWD_SERVER, "FwdServer", sizeof(FwdServer), 0); |
062e2281 | 773 | } |
93775f90 | 774 | |
b3264694 | 775 | static void |
a3c6762c | 776 | peerIcpParentMiss(CachePeer * p, icp_common_t * header, ps_state * ps) |
b3264694 | 777 | { |
778 | int rtt; | |
62e76326 | 779 | |
9b5c4a9a | 780 | #if USE_ICMP |
b3264694 | 781 | if (Config.onoff.query_icmp) { |
62e76326 | 782 | if (header->flags & ICP_FLAG_SRC_RTT) { |
783 | rtt = header->pad & 0xFFFF; | |
9b5c4a9a | 784 | int hops = (header->pad >> 16) & 0xFFFF; |
62e76326 | 785 | |
786 | if (rtt > 0 && rtt < 0xFFFF) | |
5c51bffb | 787 | netdbUpdatePeer(ps->request->url, p, rtt, hops); |
62e76326 | 788 | |
789 | if (rtt && (ps->ping.p_rtt == 0 || rtt < ps->ping.p_rtt)) { | |
790 | ps->closest_parent_miss = p->in_addr; | |
791 | ps->ping.p_rtt = rtt; | |
792 | } | |
793 | } | |
b3264694 | 794 | } |
9b5c4a9a | 795 | #endif /* USE_ICMP */ |
62e76326 | 796 | |
18ec72b2 | 797 | /* if closest-only is set, then don't allow FIRST_PARENT_MISS */ |
cd196bc8 | 798 | if (p->options.closest_only) |
62e76326 | 799 | return; |
800 | ||
85223cd7 | 801 | /* set FIRST_MISS if there is no CLOSEST parent */ |
4dd643d5 | 802 | if (!ps->closest_parent_miss.isAnyAddr()) |
62e76326 | 803 | return; |
804 | ||
d1b63fc8 | 805 | rtt = (tvSubMsec(ps->ping.start, current_time) - p->basetime) / p->weight; |
62e76326 | 806 | |
d1b63fc8 | 807 | if (rtt < 1) |
62e76326 | 808 | rtt = 1; |
809 | ||
4dd643d5 | 810 | if (ps->first_parent_miss.isAnyAddr() || rtt < ps->ping.w_rtt) { |
62e76326 | 811 | ps->first_parent_miss = p->in_addr; |
812 | ps->ping.w_rtt = rtt; | |
b3264694 | 813 | } |
814 | } | |
93775f90 | 815 | |
b6c0e933 | 816 | static void |
a3c6762c | 817 | peerHandleIcpReply(CachePeer * p, peer_t type, icp_common_t * header, void *data) |
93775f90 | 818 | { |
e6ccf245 | 819 | ps_state *psstate = (ps_state *)data; |
820 | icp_opcode op = header->getOpCode(); | |
4d75742e | 821 | debugs(44, 3, "peerHandleIcpReply: " << icp_opcode_str[op] << " " << psstate->url() ); |
69c95dd3 | 822 | #if USE_CACHE_DIGESTS && 0 |
26b164ac | 823 | /* do cd lookup to count false misses */ |
62e76326 | 824 | |
3ab66981 | 825 | if (p && request) |
62e76326 | 826 | peerNoteDigestLookup(request, p, |
827 | peerDigestLookup(p, request, psstate->entry)); | |
828 | ||
26b164ac | 829 | #endif |
62e76326 | 830 | |
5db6bf73 | 831 | ++ psstate->ping.n_recv; |
62e76326 | 832 | |
27cd7235 | 833 | if (op == ICP_MISS || op == ICP_DECHO) { |
62e76326 | 834 | if (type == PEER_PARENT) |
835 | peerIcpParentMiss(p, header, psstate); | |
a7c05555 | 836 | } else if (op == ICP_HIT) { |
62e76326 | 837 | psstate->hit = p; |
838 | psstate->hit_type = type; | |
839 | peerSelectFoo(psstate); | |
840 | return; | |
db1cd23c | 841 | } |
62e76326 | 842 | |
44e237d0 | 843 | if (psstate->ping.n_recv < psstate->ping.n_replies_expected) |
62e76326 | 844 | return; |
845 | ||
b6c0e933 | 846 | peerSelectFoo(psstate); |
93775f90 | 847 | } |
86aebcda | 848 | |
849 | #if USE_HTCP | |
850 | static void | |
fad2588a | 851 | peerHandleHtcpReply(CachePeer * p, peer_t type, HtcpReplyData * htcp, void *data) |
86aebcda | 852 | { |
e6ccf245 | 853 | ps_state *psstate = (ps_state *)data; |
4d75742e | 854 | debugs(44, 3, "" << (htcp->hit ? "HIT" : "MISS") << " " << psstate->url()); |
5db6bf73 | 855 | ++ psstate->ping.n_recv; |
62e76326 | 856 | |
44e237d0 | 857 | if (htcp->hit) { |
62e76326 | 858 | psstate->hit = p; |
859 | psstate->hit_type = type; | |
860 | peerSelectFoo(psstate); | |
861 | return; | |
44e237d0 | 862 | } |
62e76326 | 863 | |
44e237d0 | 864 | if (type == PEER_PARENT) |
62e76326 | 865 | peerHtcpParentMiss(p, htcp, psstate); |
866 | ||
44e237d0 | 867 | if (psstate->ping.n_recv < psstate->ping.n_replies_expected) |
62e76326 | 868 | return; |
869 | ||
44e237d0 | 870 | peerSelectFoo(psstate); |
871 | } | |
872 | ||
873 | static void | |
fad2588a | 874 | peerHtcpParentMiss(CachePeer * p, HtcpReplyData * htcp, ps_state * ps) |
44e237d0 | 875 | { |
876 | int rtt; | |
62e76326 | 877 | |
9b5c4a9a | 878 | #if USE_ICMP |
44e237d0 | 879 | if (Config.onoff.query_icmp) { |
62e76326 | 880 | if (htcp->cto.rtt > 0) { |
881 | rtt = (int) htcp->cto.rtt * 1000; | |
9b5c4a9a | 882 | int hops = (int) htcp->cto.hops * 1000; |
5c51bffb | 883 | netdbUpdatePeer(ps->request->url, p, rtt, hops); |
62e76326 | 884 | |
885 | if (rtt && (ps->ping.p_rtt == 0 || rtt < ps->ping.p_rtt)) { | |
886 | ps->closest_parent_miss = p->in_addr; | |
887 | ps->ping.p_rtt = rtt; | |
888 | } | |
889 | } | |
44e237d0 | 890 | } |
9b5c4a9a | 891 | #endif /* USE_ICMP */ |
62e76326 | 892 | |
44e237d0 | 893 | /* if closest-only is set, then don't allow FIRST_PARENT_MISS */ |
cd196bc8 | 894 | if (p->options.closest_only) |
62e76326 | 895 | return; |
896 | ||
44e237d0 | 897 | /* set FIRST_MISS if there is no CLOSEST parent */ |
4dd643d5 | 898 | if (!ps->closest_parent_miss.isAnyAddr()) |
62e76326 | 899 | return; |
900 | ||
d1b63fc8 | 901 | rtt = (tvSubMsec(ps->ping.start, current_time) - p->basetime) / p->weight; |
62e76326 | 902 | |
d1b63fc8 | 903 | if (rtt < 1) |
62e76326 | 904 | rtt = 1; |
905 | ||
4dd643d5 | 906 | if (ps->first_parent_miss.isAnyAddr() || rtt < ps->ping.w_rtt) { |
62e76326 | 907 | ps->first_parent_miss = p->in_addr; |
908 | ps->ping.w_rtt = rtt; | |
44e237d0 | 909 | } |
86aebcda | 910 | } |
62e76326 | 911 | |
86aebcda | 912 | #endif |
913 | ||
914 | static void | |
a3c6762c | 915 | peerHandlePingReply(CachePeer * p, peer_t type, AnyP::ProtocolType proto, void *pingdata, void *data) |
86aebcda | 916 | { |
0c3d3f65 | 917 | if (proto == AnyP::PROTO_ICP) |
62e76326 | 918 | peerHandleIcpReply(p, type, (icp_common_t *)pingdata, data); |
919 | ||
86aebcda | 920 | #if USE_HTCP |
62e76326 | 921 | |
0c3d3f65 | 922 | else if (proto == AnyP::PROTO_HTCP) |
fad2588a | 923 | peerHandleHtcpReply(p, type, (HtcpReplyData *)pingdata, data); |
62e76326 | 924 | |
86aebcda | 925 | #endif |
62e76326 | 926 | |
86aebcda | 927 | else |
e0236918 | 928 | debugs(44, DBG_IMPORTANT, "peerHandlePingReply: unknown protocol " << proto); |
86aebcda | 929 | } |
db1cd23c | 930 | |
931 | static void | |
a3c6762c | 932 | peerAddFwdServer(FwdServer ** FSVR, CachePeer * p, hier_code code) |
db1cd23c | 933 | { |
e6ccf245 | 934 | FwdServer *fs = (FwdServer *)memAllocate(MEM_FWD_SERVER); |
26ac0430 AJ |
935 | debugs(44, 5, "peerAddFwdServer: adding " << |
936 | (p ? p->host : "DIRECT") << " " << | |
4b981814 | 937 | hier_code_str[code] ); |
29b8d8d6 | 938 | fs->_peer = cbdataReference(p); |
db1cd23c | 939 | fs->code = code; |
62e76326 | 940 | |
b73f343e | 941 | while (*FSVR) |
942 | FSVR = &(*FSVR)->next; | |
62e76326 | 943 | |
b73f343e | 944 | *FSVR = fs; |
db1cd23c | 945 | } |
b24880fe | 946 | |
b24880fe | 947 | ps_state::ps_state() : request (NULL), |
f53969cc SM |
948 | entry (NULL), |
949 | always_direct(Config.accessList.AlwaysDirect?ACCESS_DUNNO:ACCESS_DENIED), | |
950 | never_direct(Config.accessList.NeverDirect?ACCESS_DUNNO:ACCESS_DENIED), | |
951 | direct(DIRECT_UNKNOWN), | |
952 | callback (NULL), | |
953 | callback_data (NULL), | |
954 | lastError(NULL), | |
09c7fb54 | 955 | paths(NULL), |
f53969cc SM |
956 | servers (NULL), |
957 | first_parent_miss(), | |
958 | closest_parent_miss(), | |
959 | hit(NULL), | |
960 | hit_type(PEER_NONE), | |
961 | acl_checklist (NULL) | |
b24880fe | 962 | { |
cc192b50 | 963 | ; // no local defaults. |
b24880fe | 964 | } |
965 | ||
851feda6 | 966 | const SBuf |
769c64cc AJ |
967 | ps_state::url() const |
968 | { | |
969 | if (entry) | |
851feda6 | 970 | return SBuf(entry->url()); |
769c64cc AJ |
971 | |
972 | if (request) | |
851feda6 | 973 | return request->effectiveRequestUri(); |
769c64cc | 974 | |
851feda6 AJ |
975 | static const SBuf noUrl("[no URL]"); |
976 | return noUrl; | |
769c64cc AJ |
977 | } |
978 | ||
b24880fe | 979 | ping_data::ping_data() : |
f53969cc SM |
980 | n_sent(0), |
981 | n_recv(0), | |
982 | n_replies_expected(0), | |
983 | timeout(0), | |
984 | timedout(0), | |
985 | w_rtt(0), | |
986 | p_rtt(0) | |
b24880fe | 987 | { |
988 | start.tv_sec = 0; | |
989 | start.tv_usec = 0; | |
990 | stop.tv_sec = 0; | |
991 | stop.tv_usec = 0; | |
992 | } | |
f53969cc | 993 |