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