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