]> git.ipfire.org Git - thirdparty/squid.git/blame - src/peer_select.cc
Sync store meta assignments with Squid-2.
[thirdparty/squid.git] / src / peer_select.cc
CommitLineData
641941c0 1
062e2281 2/*
4a7a3d56 3 * $Id: peer_select.cc,v 1.147 2007/04/30 16:56:09 wessels Exp $
062e2281 4 *
5 * DEBUG: section 44 Peer Selection Algorithm
6 * AUTHOR: Duane Wessels
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
062e2281 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
062e2281 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
062e2281 34 */
35
36#include "squid.h"
a553a5a3 37#include "event.h"
b24880fe 38#include "PeerSelectState.h"
e6ccf245 39#include "Store.h"
40#include "ICP.h"
528b2c61 41#include "HttpRequest.h"
8000a965 42#include "ACLChecklist.h"
924f73bc 43#include "htcp.h"
b6b6f466 44#include "forward.h"
062e2281 45
429fdbec 46const char *hier_strings[] =
62e76326 47 {
48 "NONE",
49 "DIRECT",
50 "SIBLING_HIT",
51 "PARENT_HIT",
52 "DEFAULT_PARENT",
53 "SINGLE_PARENT",
54 "FIRST_UP_PARENT",
55 "FIRST_PARENT_MISS",
56 "CLOSEST_PARENT_MISS",
57 "CLOSEST_PARENT",
58 "CLOSEST_DIRECT",
59 "NO_DIRECT_FAIL",
60 "SOURCE_FASTEST",
61 "ROUNDROBIN_PARENT",
6cfa8966 62#if USE_CACHE_DIGESTS
62e76326 63 "CD_PARENT_HIT",
64 "CD_SIBLING_HIT",
afd88fbe 65#endif
66#if USE_CARP
62e76326 67 "CARP",
c127134a 68#endif
62e76326 69 "ANY_PARENT",
70 "INVALID CODE"
71 };
429fdbec 72
62e76326 73static struct
74{
75e88d56 75 int timeouts;
62e76326 76}
77
78PeerStats;
062e2281 79
a2c963ae 80static const char *DirectStr[] =
62e76326 81 {
82 "DIRECT_UNKNOWN",
83 "DIRECT_NO",
84 "DIRECT_MAYBE",
85 "DIRECT_YES"
86 };
75e88d56 87
f5b8bbc4 88static void peerSelectFoo(ps_state *);
89static void peerPingTimeout(void *data);
db1cd23c 90static void peerSelectCallback(ps_state * psstate);
86aebcda 91static IRCB peerHandlePingReply;
f5b8bbc4 92static void peerSelectStateFree(ps_state * psstate);
93static void peerIcpParentMiss(peer *, icp_common_t *, ps_state *);
44e237d0 94#if USE_HTCP
95static void peerHtcpParentMiss(peer *, htcpReplyData *, ps_state *);
96static void peerHandleHtcpReply(peer *, peer_t, htcpReplyData *, void *);
97#endif
f5b8bbc4 98static int peerCheckNetdbDirect(ps_state * psstate);
db1cd23c 99static void peerGetSomeNeighbor(ps_state *);
100static void peerGetSomeNeighborReplies(ps_state *);
101static void peerGetSomeDirect(ps_state *);
102static void peerGetSomeParent(ps_state *);
168dfda9 103static void peerGetAllParents(ps_state *);
db1cd23c 104static void peerAddFwdServer(FwdServer **, peer *, hier_code);
348b2031 105
aa839030 106CBDATA_CLASS_INIT(ps_state);
107
348b2031 108static void
109peerSelectStateFree(ps_state * psstate)
110{
111 if (psstate->acl_checklist) {
bf8fe701 112 debugs(44, 1, "calling aclChecklistFree() from peerSelectStateFree");
62e76326 113 delete (psstate->acl_checklist);
348b2031 114 }
62e76326 115
6dd9f4bd 116 HTTPMSGUNLOCK(psstate->request);
62e76326 117
73a201f8 118 if (psstate->entry) {
62e76326 119 assert(psstate->entry->ping_status != PING_WAITING);
97b5e68f 120 psstate->entry->unlock();
62e76326 121 psstate->entry = NULL;
73a201f8 122 }
62e76326 123
8407afee 124 cbdataFree(psstate);
348b2031 125}
062e2281 126
2d72d4fd 127static int
190154cf 128peerSelectIcpPing(HttpRequest * request, int direct, StoreEntry * entry)
062e2281 129{
7b665aeb 130 int n;
db1cd23c 131 assert(entry);
132 assert(entry->ping_status == PING_NONE);
9bd6a36d 133 assert(direct != DIRECT_YES);
bf8fe701 134 debugs(44, 3, "peerSelectIcpPing: " << entry->url() );
62e76326 135
92695e5e 136 if (!request->flags.hierarchical && direct != DIRECT_NO)
62e76326 137 return 0;
138
d46a87a8 139 if (EBIT_TEST(entry->flags, KEY_PRIVATE) && !neighbors_do_private_keys)
62e76326 140 if (direct != DIRECT_NO)
141 return 0;
142
7b665aeb 143 n = neighborsCount(request);
62e76326 144
bf8fe701 145 debugs(44, 3, "peerSelectIcpPing: counted " << n << " neighbors");
62e76326 146
7b665aeb 147 return n;
062e2281 148}
149
150
062e2281 151void
190154cf 152peerSelect(HttpRequest * request,
62e76326 153 StoreEntry * entry,
154 PSC * callback,
155 void *callback_data)
75e88d56 156{
28c60158 157 ps_state *psstate;
62e76326 158
86b389fc 159 if (entry)
bf8fe701 160 debugs(44, 3, "peerSelect: " << entry->url() );
86b389fc 161 else
bf8fe701 162 debugs(44, 3, "peerSelect: " << RequestMethodStr[request->method]);
62e76326 163
b24880fe 164 psstate = new ps_state;
62e76326 165
6dd9f4bd 166 psstate->request = HTTPMSGLOCK(request);
62e76326 167
b6c0e933 168 psstate->entry = entry;
62e76326 169
b6c0e933 170 psstate->callback = callback;
62e76326 171
fa80a8ef 172 psstate->callback_data = cbdataReference(callback_data);
62e76326 173
db1cd23c 174 psstate->direct = DIRECT_UNKNOWN;
62e76326 175
6cfa8966 176#if USE_CACHE_DIGESTS
62e76326 177
39edba21 178 request->hier.peer_select_start = current_time;
62e76326 179
39edba21 180#endif
62e76326 181
2395cb21 182 if (psstate->entry)
34266cde 183 psstate->entry->lock()
184
185 ;
62e76326 186
b6c0e933 187 peerSelectFoo(psstate);
75e88d56 188}
189
190static void
191peerCheckNeverDirectDone(int answer, void *data)
192{
e6ccf245 193 ps_state *psstate = (ps_state *) data;
348b2031 194 psstate->acl_checklist = NULL;
bf8fe701 195 debugs(44, 3, "peerCheckNeverDirectDone: " << answer);
b6c0e933 196 psstate->never_direct = answer ? 1 : -1;
197 peerSelectFoo(psstate);
75e88d56 198}
199
200static void
201peerCheckAlwaysDirectDone(int answer, void *data)
202{
e6ccf245 203 ps_state *psstate = (ps_state *)data;
348b2031 204 psstate->acl_checklist = NULL;
bf8fe701 205 debugs(44, 3, "peerCheckAlwaysDirectDone: " << answer);
7b665aeb 206 psstate->always_direct = answer ? 1 : -1;
b6c0e933 207 peerSelectFoo(psstate);
75e88d56 208}
209
93775f90 210static void
db1cd23c 211peerSelectCallback(ps_state * psstate)
93775f90 212{
b6c0e933 213 StoreEntry *entry = psstate->entry;
db1cd23c 214 FwdServer *fs = psstate->servers;
fa80a8ef 215 PSC *callback;
216 void *cbdata;
62e76326 217
b6c0e933 218 if (entry) {
bf8fe701 219 debugs(44, 3, "peerSelectCallback: " << entry->url() );
62e76326 220
221 if (entry->ping_status == PING_WAITING)
222 eventDelete(peerPingTimeout, psstate);
223
224 entry->ping_status = PING_DONE;
b6c0e933 225 }
62e76326 226
db1cd23c 227 if (fs == NULL) {
bf8fe701 228 debugs(44, 1, "Failed to select source for '" << entry->url() << "'" );
229 debugs(44, 1, " always_direct = " << psstate->always_direct );
230 debugs(44, 1, " never_direct = " << psstate->never_direct );
231 debugs(44, 1, " timedout = " << psstate->ping.timedout );
db1cd23c 232 }
62e76326 233
44e237d0 234 psstate->ping.stop = current_time;
0bdf2621 235 psstate->request->hier.ping = psstate->ping;
fa80a8ef 236 callback = psstate->callback;
237 psstate->callback = NULL;
62e76326 238
fa80a8ef 239 if (cbdataReferenceValidDone(psstate->callback_data, &cbdata)) {
62e76326 240 psstate->servers = NULL;
241 callback(fs, cbdata);
db1cd23c 242 }
62e76326 243
348b2031 244 peerSelectStateFree(psstate);
93775f90 245}
246
b3264694 247static int
248peerCheckNetdbDirect(ps_state * psstate)
249{
5f84d830 250 peer *p;
b3264694 251 int myrtt;
252 int myhops;
62e76326 253
0886a797 254 if (psstate->direct == DIRECT_NO)
62e76326 255 return 0;
256
b3264694 257 myrtt = netdbHostRtt(psstate->request->host);
62e76326 258
bf8fe701 259 debugs(44, 3, "peerCheckNetdbDirect: MY RTT = " << myrtt << " msec");
260 debugs(44, 3, "peerCheckNetdbDirect: minimum_direct_rtt = " << Config.minDirectRtt << " msec");
62e76326 261
62e76326 262
5f84d830 263 if (myrtt && myrtt <= Config.minDirectRtt)
62e76326 264 return 1;
265
b3264694 266 myhops = netdbHostHops(psstate->request->host);
62e76326 267
bf8fe701 268 debugs(44, 3, "peerCheckNetdbDirect: MY hops = " << myhops);
269 debugs(44, 3, "peerCheckNetdbDirect: minimum_direct_hops = " << Config.minDirectHops);
62e76326 270
62e76326 271
b3264694 272 if (myhops && myhops <= Config.minDirectHops)
62e76326 273 return 1;
274
5f84d830 275 p = whichPeer(&psstate->closest_parent_miss);
62e76326 276
5f84d830 277 if (p == NULL)
62e76326 278 return 0;
279
bf8fe701 280 debugs(44, 3, "peerCheckNetdbDirect: closest_parent_miss RTT = " << psstate->ping.p_rtt << " msec");
62e76326 281
5f84d830 282 if (myrtt && myrtt <= psstate->ping.p_rtt)
62e76326 283 return 1;
284
b3264694 285 return 0;
286}
287
93775f90 288static void
511f47bb 289peerSelectFoo(ps_state * ps)
062e2281 290{
511f47bb 291 StoreEntry *entry = ps->entry;
190154cf 292 HttpRequest *request = ps->request;
bf8fe701 293 debugs(44, 3, "peerSelectFoo: '" << RequestMethodStr[request->method] << " " << request->host << "'");
62e76326 294
511f47bb 295 if (ps->direct == DIRECT_UNKNOWN) {
62e76326 296 if (ps->always_direct == 0 && Config.accessList.AlwaysDirect) {
297 ps->acl_checklist = aclChecklistCreate(
298 Config.accessList.AlwaysDirect,
299 request,
300 NULL); /* ident */
301 ps->acl_checklist->nonBlockingCheck(peerCheckAlwaysDirectDone,
302 ps);
303 return;
304 } else if (ps->always_direct > 0) {
305 ps->direct = DIRECT_YES;
306 } else if (ps->never_direct == 0 && Config.accessList.NeverDirect) {
307 ps->acl_checklist = aclChecklistCreate(
308 Config.accessList.NeverDirect,
309 request,
310 NULL); /* ident */
311 ps->acl_checklist->nonBlockingCheck(peerCheckNeverDirectDone,
312 ps);
313 return;
314 } else if (ps->never_direct > 0) {
315 ps->direct = DIRECT_NO;
316 } else if (request->flags.accelerated) {
317 ps->direct = DIRECT_NO;
318 } else if (request->flags.loopdetect) {
319 ps->direct = DIRECT_YES;
320 } else if (peerCheckNetdbDirect(ps)) {
321 ps->direct = DIRECT_YES;
322 } else {
323 ps->direct = DIRECT_MAYBE;
324 }
325
bf8fe701 326 debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct]);
db1cd23c 327 }
62e76326 328
df503d6c 329 if (entry == NULL) {
62e76326 330 (void) 0;
df503d6c 331 } else if (entry->ping_status == PING_NONE) {
62e76326 332 peerGetSomeNeighbor(ps);
333
334 if (entry->ping_status == PING_WAITING)
335 return;
db1cd23c 336 } else if (entry->ping_status == PING_WAITING) {
62e76326 337 peerGetSomeNeighborReplies(ps);
338 entry->ping_status = PING_DONE;
db1cd23c 339 }
62e76326 340
168dfda9 341 switch (ps->direct) {
62e76326 342
168dfda9 343 case DIRECT_YES:
62e76326 344 peerGetSomeDirect(ps);
345 break;
346
168dfda9 347 case DIRECT_NO:
62e76326 348 peerGetSomeParent(ps);
349 peerGetAllParents(ps);
350 break;
351
168dfda9 352 default:
62e76326 353
354 if (Config.onoff.prefer_direct)
355 peerGetSomeDirect(ps);
356
357 if (request->flags.hierarchical || !Config.onoff.nonhierarchical_direct)
358 peerGetSomeParent(ps);
359
360 if (!Config.onoff.prefer_direct)
361 peerGetSomeDirect(ps);
362
363 break;
168dfda9 364 }
62e76326 365
511f47bb 366 peerSelectCallback(ps);
db1cd23c 367}
368
369/*
370 * peerGetSomeNeighbor
371 *
372 * Selects a neighbor (parent or sibling) based on one of the
373 * following methods:
374 * Cache Digests
375 * CARP
376 * Netdb RTT estimates
377 * ICP/HTCP queries
378 */
379static void
380peerGetSomeNeighbor(ps_state * ps)
381{
382 StoreEntry *entry = ps->entry;
190154cf 383 HttpRequest *request = ps->request;
db1cd23c 384 peer *p;
385 hier_code code = HIER_NONE;
386 assert(entry->ping_status == PING_NONE);
62e76326 387
db1cd23c 388 if (ps->direct == DIRECT_YES) {
62e76326 389 entry->ping_status = PING_DONE;
390 return;
124511e5 391 }
62e76326 392
6cfa8966 393#if USE_CACHE_DIGESTS
f66a9ef4 394 if ((p = neighborsDigestSelect(request))) {
62e76326 395 if (neighborType(p, request) == PEER_PARENT)
396 code = CD_PARENT_HIT;
397 else
398 code = CD_SIBLING_HIT;
db1cd23c 399 } else
c127134a 400#endif
62e76326 401 if ((p = netdbClosestParent(request))) {
402 code = CLOSEST_PARENT;
403 } else if (peerSelectIcpPing(request, ps->direct, entry)) {
bf8fe701 404 debugs(44, 3, "peerSelect: Doing ICP pings");
62e76326 405 ps->ping.start = current_time;
406 ps->ping.n_sent = neighborsUdpPing(request,
407 entry,
408 peerHandlePingReply,
409 ps,
410 &ps->ping.n_replies_expected,
411 &ps->ping.timeout);
412
413 if (ps->ping.n_sent == 0)
bf8fe701 414 debugs(44, 0, "WARNING: neighborsUdpPing returned 0");
415 debugs(44, 3, "peerSelect: " << ps->ping.n_replies_expected <<
416 " ICP replies expected, RTT " << ps->ping.timeout <<
417 " msec");
62e76326 418
62e76326 419
420 if (ps->ping.n_replies_expected > 0) {
421 entry->ping_status = PING_WAITING;
422 eventAdd("peerPingTimeout",
423 peerPingTimeout,
424 ps,
425 0.001 * ps->ping.timeout,
426 0);
427 return;
428 }
429 }
430
db1cd23c 431 if (code != HIER_NONE) {
62e76326 432 assert(p);
bf8fe701 433 debugs(44, 3, "peerSelect: " << hier_strings[code] << "/" << p->host);
62e76326 434 peerAddFwdServer(&ps->servers, p, code);
db1cd23c 435 }
62e76326 436
db1cd23c 437 entry->ping_status = PING_DONE;
438}
439
440/*
441 * peerGetSomeNeighborReplies
442 *
443 * Selects a neighbor (parent or sibling) based on ICP/HTCP replies.
444 */
445static void
446peerGetSomeNeighborReplies(ps_state * ps)
447{
190154cf 448 HttpRequest *request = ps->request;
db1cd23c 449 peer *p = NULL;
450 hier_code code = HIER_NONE;
4c5a1592 451 assert(ps->entry->ping_status == PING_WAITING);
db1cd23c 452 assert(ps->direct != DIRECT_YES);
62e76326 453
db1cd23c 454 if (peerCheckNetdbDirect(ps)) {
62e76326 455 code = CLOSEST_DIRECT;
bf8fe701 456 debugs(44, 3, "peerSelect: " << hier_strings[code] << "/" << request->host);
62e76326 457 peerAddFwdServer(&ps->servers, NULL, code);
458 return;
db1cd23c 459 }
62e76326 460
db1cd23c 461 if ((p = ps->hit)) {
62e76326 462 code = ps->hit_type == PEER_PARENT ? PARENT_HIT : SIBLING_HIT;
db1cd23c 463 } else
464#if ALLOW_SOURCE_PING
62e76326 465 if ((p = ps->secho)) {
466 code = SOURCE_FASTEST;
467 } else
db1cd23c 468#endif
62e76326 469 if (ps->closest_parent_miss.sin_addr.s_addr != any_addr.s_addr) {
470 p = whichPeer(&ps->closest_parent_miss);
471 code = CLOSEST_PARENT_MISS;
472 } else if (ps->first_parent_miss.sin_addr.s_addr != any_addr.s_addr) {
473 p = whichPeer(&ps->first_parent_miss);
474 code = FIRST_PARENT_MISS;
475 }
476
db1cd23c 477 if (p && code != HIER_NONE) {
bf8fe701 478 debugs(44, 3, "peerSelect: " << hier_strings[code] << "/" << p->host);
62e76326 479 peerAddFwdServer(&ps->servers, p, code);
db1cd23c 480 }
481}
482
483
484/*
485 * peerGetSomeDirect
486 *
487 * Simply adds a 'direct' entry to the FwdServers list if this
488 * request can be forwarded directly to the origin server
489 */
490static void
491peerGetSomeDirect(ps_state * ps)
492{
493 if (ps->direct == DIRECT_NO)
62e76326 494 return;
495
db80e881 496 /* WAIS is not implemented natively */
db1cd23c 497 if (ps->request->protocol == PROTO_WAIS)
db80e881 498 return;
499
500 peerAddFwdServer(&ps->servers, NULL, HIER_DIRECT);
db1cd23c 501}
502
503static void
504peerGetSomeParent(ps_state * ps)
505{
506 peer *p;
190154cf 507 HttpRequest *request = ps->request;
db1cd23c 508 hier_code code = HIER_NONE;
bf8fe701 509 debugs(44, 3, "peerGetSomeParent: " << RequestMethodStr[request->method] << " " << request->host);
62e76326 510
6b8e7481 511 if (ps->direct == DIRECT_YES)
62e76326 512 return;
513
db1cd23c 514 if ((p = getDefaultParent(request))) {
62e76326 515 code = DEFAULT_PARENT;
b3995439 516#if USE_CARP
62e76326 517
b3995439 518 } else if ((p = carpSelectParent(request))) {
62e76326 519 code = CARP;
b3995439 520#endif
62e76326 521
db1cd23c 522 } else if ((p = getRoundRobinParent(request))) {
62e76326 523 code = ROUNDROBIN_PARENT;
d1b63fc8 524 } else if ((p = getWeightedRoundRobinParent(request))) {
62e76326 525 code = ROUNDROBIN_PARENT;
db1cd23c 526 } else if ((p = getFirstUpParent(request))) {
62e76326 527 code = FIRSTUP_PARENT;
db1cd23c 528 } else if ((p = getAnyParent(request))) {
62e76326 529 code = ANY_OLD_PARENT;
db1cd23c 530 }
62e76326 531
db1cd23c 532 if (code != HIER_NONE) {
bf8fe701 533 debugs(44, 3, "peerSelect: " << hier_strings[code] << "/" << p->host);
62e76326 534 peerAddFwdServer(&ps->servers, p, code);
062e2281 535 }
536}
537
168dfda9 538/* Adds alive parents. Used as a last resort for never_direct.
539 */
540static void
541peerGetAllParents(ps_state * ps)
542{
543 peer *p;
190154cf 544 HttpRequest *request = ps->request;
168dfda9 545 /* Add all alive parents */
62e76326 546
168dfda9 547 for (p = Config.peers; p; p = p->next) {
62e76326 548 /* XXX: neighbors.c lacks a public interface for enumerating
549 * parents to a request so we have to dig some here..
550 */
551
552 if (neighborType(p, request) != PEER_PARENT)
553 continue;
554
555 if (!peerHTTPOkay(p, request))
556 continue;
557
bf8fe701 558 debugs(15, 3, "peerGetAllParents: adding alive parent " << p->host);
62e76326 559
560 peerAddFwdServer(&ps->servers, p, ANY_OLD_PARENT);
168dfda9 561 }
62e76326 562
168dfda9 563 /* XXX: should add dead parents here, but it is currently
564 * not possible to find out which parents are dead or which
565 * simply are not configured to handle the request.
566 */
567 /* Add default parent as a last resort */
568 if ((p = getDefaultParent(request))) {
62e76326 569 peerAddFwdServer(&ps->servers, p, DEFAULT_PARENT);
168dfda9 570 }
571}
572
d9586c3c 573static void
93775f90 574peerPingTimeout(void *data)
062e2281 575{
e6ccf245 576 ps_state *psstate = (ps_state *)data;
b6c0e933 577 StoreEntry *entry = psstate->entry;
62e76326 578
fefb0227 579 if (entry)
bf8fe701 580 debugs(44, 3, "peerPingTimeout: '" << entry->url() << "'" );
62e76326 581
fa80a8ef 582 if (!cbdataReferenceValid(psstate->callback_data)) {
62e76326 583 /* request aborted */
584 entry->ping_status = PING_DONE;
585 cbdataReferenceDone(psstate->callback_data);
586 peerSelectStateFree(psstate);
587 return;
73a201f8 588 }
62e76326 589
75e88d56 590 PeerStats.timeouts++;
44e237d0 591 psstate->ping.timedout = 1;
b6c0e933 592 peerSelectFoo(psstate);
85034133 593}
594
595void
596peerSelectInit(void)
597{
75e88d56 598 memset(&PeerStats, '\0', sizeof(PeerStats));
9bdbfe33 599 assert(sizeof(hier_strings) == (HIER_MAX + 1) * sizeof(char *));
062e2281 600}
93775f90 601
b3264694 602static void
603peerIcpParentMiss(peer * p, icp_common_t * header, ps_state * ps)
604{
605 int rtt;
606 int hops;
62e76326 607
b3264694 608 if (Config.onoff.query_icmp) {
62e76326 609 if (header->flags & ICP_FLAG_SRC_RTT) {
610 rtt = header->pad & 0xFFFF;
611 hops = (header->pad >> 16) & 0xFFFF;
612
613 if (rtt > 0 && rtt < 0xFFFF)
614 netdbUpdatePeer(ps->request, p, rtt, hops);
615
616 if (rtt && (ps->ping.p_rtt == 0 || rtt < ps->ping.p_rtt)) {
617 ps->closest_parent_miss = p->in_addr;
618 ps->ping.p_rtt = rtt;
619 }
620 }
b3264694 621 }
62e76326 622
18ec72b2 623 /* if closest-only is set, then don't allow FIRST_PARENT_MISS */
cd196bc8 624 if (p->options.closest_only)
62e76326 625 return;
626
85223cd7 627 /* set FIRST_MISS if there is no CLOSEST parent */
628 if (ps->closest_parent_miss.sin_addr.s_addr != any_addr.s_addr)
62e76326 629 return;
630
d1b63fc8 631 rtt = (tvSubMsec(ps->ping.start, current_time) - p->basetime) / p->weight;
62e76326 632
d1b63fc8 633 if (rtt < 1)
62e76326 634 rtt = 1;
635
0f97864c 636 if (ps->first_parent_miss.sin_addr.s_addr == any_addr.s_addr ||
62e76326 637 rtt < ps->ping.w_rtt) {
638 ps->first_parent_miss = p->in_addr;
639 ps->ping.w_rtt = rtt;
b3264694 640 }
641}
93775f90 642
b6c0e933 643static void
b3264694 644peerHandleIcpReply(peer * p, peer_t type, icp_common_t * header, void *data)
93775f90 645{
e6ccf245 646 ps_state *psstate = (ps_state *)data;
647 icp_opcode op = header->getOpCode();
bf8fe701 648 debugs(44, 3, "peerHandleIcpReply: " << icp_opcode_str[op] << " " << psstate->entry->url() );
69c95dd3 649#if USE_CACHE_DIGESTS && 0
26b164ac 650 /* do cd lookup to count false misses */
62e76326 651
3ab66981 652 if (p && request)
62e76326 653 peerNoteDigestLookup(request, p,
654 peerDigestLookup(p, request, psstate->entry));
655
26b164ac 656#endif
62e76326 657
44e237d0 658 psstate->ping.n_recv++;
62e76326 659
27cd7235 660 if (op == ICP_MISS || op == ICP_DECHO) {
62e76326 661 if (type == PEER_PARENT)
662 peerIcpParentMiss(p, header, psstate);
a7c05555 663 } else if (op == ICP_HIT) {
62e76326 664 psstate->hit = p;
665 psstate->hit_type = type;
666 peerSelectFoo(psstate);
667 return;
db1cd23c 668 }
62e76326 669
db1cd23c 670#if ALLOW_SOURCE_PING
671 else if (op == ICP_SECHO) {
62e76326 672 psstate->secho = p;
673 peerSelectFoo(psstate);
674 return;
93775f90 675 }
62e76326 676
db1cd23c 677#endif
44e237d0 678 if (psstate->ping.n_recv < psstate->ping.n_replies_expected)
62e76326 679 return;
680
b6c0e933 681 peerSelectFoo(psstate);
93775f90 682}
86aebcda 683
684#if USE_HTCP
685static void
44e237d0 686peerHandleHtcpReply(peer * p, peer_t type, htcpReplyData * htcp, void *data)
86aebcda 687{
e6ccf245 688 ps_state *psstate = (ps_state *)data;
bf8fe701 689 debugs(44, 3, "peerHandleHtcpReply: " <<
690 (htcp->hit ? "HIT" : "MISS") << " " <<
691 psstate->entry->url() );
44e237d0 692 psstate->ping.n_recv++;
62e76326 693
44e237d0 694 if (htcp->hit) {
62e76326 695 psstate->hit = p;
696 psstate->hit_type = type;
697 peerSelectFoo(psstate);
698 return;
44e237d0 699 }
62e76326 700
44e237d0 701 if (type == PEER_PARENT)
62e76326 702 peerHtcpParentMiss(p, htcp, psstate);
703
44e237d0 704 if (psstate->ping.n_recv < psstate->ping.n_replies_expected)
62e76326 705 return;
706
44e237d0 707 peerSelectFoo(psstate);
708}
709
710static void
711peerHtcpParentMiss(peer * p, htcpReplyData * htcp, ps_state * ps)
712{
713 int rtt;
714 int hops;
62e76326 715
44e237d0 716 if (Config.onoff.query_icmp) {
62e76326 717 if (htcp->cto.rtt > 0) {
718 rtt = (int) htcp->cto.rtt * 1000;
719 hops = (int) htcp->cto.hops * 1000;
720 netdbUpdatePeer(ps->request, p, rtt, hops);
721
722 if (rtt && (ps->ping.p_rtt == 0 || rtt < ps->ping.p_rtt)) {
723 ps->closest_parent_miss = p->in_addr;
724 ps->ping.p_rtt = rtt;
725 }
726 }
44e237d0 727 }
62e76326 728
44e237d0 729 /* if closest-only is set, then don't allow FIRST_PARENT_MISS */
cd196bc8 730 if (p->options.closest_only)
62e76326 731 return;
732
44e237d0 733 /* set FIRST_MISS if there is no CLOSEST parent */
734 if (ps->closest_parent_miss.sin_addr.s_addr != any_addr.s_addr)
62e76326 735 return;
736
d1b63fc8 737 rtt = (tvSubMsec(ps->ping.start, current_time) - p->basetime) / p->weight;
62e76326 738
d1b63fc8 739 if (rtt < 1)
62e76326 740 rtt = 1;
741
508b3383 742 if (ps->first_parent_miss.sin_addr.s_addr == any_addr.s_addr ||
62e76326 743 rtt < ps->ping.w_rtt) {
744 ps->first_parent_miss = p->in_addr;
745 ps->ping.w_rtt = rtt;
44e237d0 746 }
86aebcda 747}
62e76326 748
86aebcda 749#endif
750
751static void
9ef28b60 752peerHandlePingReply(peer * p, peer_t type, protocol_t proto, void *pingdata, void *data)
86aebcda 753{
754 if (proto == PROTO_ICP)
62e76326 755 peerHandleIcpReply(p, type, (icp_common_t *)pingdata, data);
756
86aebcda 757#if USE_HTCP
62e76326 758
86aebcda 759 else if (proto == PROTO_HTCP)
62e76326 760 peerHandleHtcpReply(p, type, (htcpReplyData *)pingdata, data);
761
86aebcda 762#endif
62e76326 763
86aebcda 764 else
4a7a3d56 765 debugs(44, 1, "peerHandlePingReply: unknown protocol_t " << proto);
86aebcda 766}
db1cd23c 767
768static void
b73f343e 769peerAddFwdServer(FwdServer ** FSVR, peer * p, hier_code code)
db1cd23c 770{
e6ccf245 771 FwdServer *fs = (FwdServer *)memAllocate(MEM_FWD_SERVER);
bf8fe701 772 debugs(44, 5, "peerAddFwdServer: adding " <<
773 (p ? p->host : "DIRECT") << " " <<
774 hier_strings[code] );
29b8d8d6 775 fs->_peer = cbdataReference(p);
db1cd23c 776 fs->code = code;
62e76326 777
b73f343e 778 while (*FSVR)
779 FSVR = &(*FSVR)->next;
62e76326 780
b73f343e 781 *FSVR = fs;
db1cd23c 782}
b24880fe 783
784void *
785ps_state::operator new(size_t)
786{
aa839030 787 CBDATA_INIT_TYPE(ps_state);
b24880fe 788 return cbdataAlloc(ps_state);
789}
790
791ps_state::ps_state() : request (NULL),
792 entry (NULL),
793 always_direct (0),
794 never_direct (0),
795 direct (0),
796 callback (NULL),
797 callback_data (NULL),
798 servers (NULL),
799 hit(NULL),
800 hit_type(PEER_NONE),
801#if ALLOW_SOURCE_PING
802
803 secho( NULL),
804#endif
805 acl_checklist (NULL)
806{
807 memset(&first_parent_miss, '\0', sizeof(first_parent_miss));
808 memset(&closest_parent_miss, '\0', sizeof(closest_parent_miss));
809}
810
811ping_data::ping_data() :
812 n_sent(0),
813 n_recv(0),
814 n_replies_expected(0),
815 timeout(0),
816 timedout(0),
817 w_rtt(0),
818 p_rtt(0)
819{
820 start.tv_sec = 0;
821 start.tv_usec = 0;
822 stop.tv_sec = 0;
823 stop.tv_usec = 0;
824}