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