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