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