]> git.ipfire.org Git - thirdparty/squid.git/blob - src/peer_select.cc
Summary: Final MSVC fixups.
[thirdparty/squid.git] / src / peer_select.cc
1
2 /*
3 * $Id: peer_select.cc,v 1.131 2003/08/10 11:00:44 robertc Exp $
4 *
5 * DEBUG: section 44 Peer Selection Algorithm
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
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
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37 #include "Store.h"
38 #include "ICP.h"
39 #include "HttpRequest.h"
40 #include "ACLChecklist.h"
41 #include "htcp.h"
42
43 const char *hier_strings[] =
44 {
45 "NONE",
46 "DIRECT",
47 "SIBLING_HIT",
48 "PARENT_HIT",
49 "DEFAULT_PARENT",
50 "SINGLE_PARENT",
51 "FIRST_UP_PARENT",
52 "FIRST_PARENT_MISS",
53 "CLOSEST_PARENT_MISS",
54 "CLOSEST_PARENT",
55 "CLOSEST_DIRECT",
56 "NO_DIRECT_FAIL",
57 "SOURCE_FASTEST",
58 "ROUNDROBIN_PARENT",
59 #if USE_CACHE_DIGESTS
60 "CD_PARENT_HIT",
61 "CD_SIBLING_HIT",
62 #endif
63 #if USE_CARP
64 "CARP",
65 #endif
66 "ANY_PARENT",
67 "INVALID CODE"
68 };
69
70 static struct
71 {
72 int timeouts;
73 }
74
75 PeerStats;
76
77 static const char *DirectStr[] =
78 {
79 "DIRECT_UNKNOWN",
80 "DIRECT_NO",
81 "DIRECT_MAYBE",
82 "DIRECT_YES"
83 };
84
85 static void peerSelectFoo(ps_state *);
86 static void peerPingTimeout(void *data);
87 static void peerSelectCallback(ps_state * psstate);
88 static IRCB peerHandlePingReply;
89 static void peerSelectStateFree(ps_state * psstate);
90 static void peerIcpParentMiss(peer *, icp_common_t *, ps_state *);
91 #if USE_HTCP
92 static void peerHtcpParentMiss(peer *, htcpReplyData *, ps_state *);
93 static void peerHandleHtcpReply(peer *, peer_t, htcpReplyData *, void *);
94 #endif
95 static int peerCheckNetdbDirect(ps_state * psstate);
96 static void peerGetSomeNeighbor(ps_state *);
97 static void peerGetSomeNeighborReplies(ps_state *);
98 static void peerGetSomeDirect(ps_state *);
99 static void peerGetSomeParent(ps_state *);
100 static void peerGetAllParents(ps_state *);
101 static void peerAddFwdServer(FwdServer **, peer *, hier_code);
102
103 static void
104 peerSelectStateFree(ps_state * psstate)
105 {
106 if (psstate->acl_checklist) {
107 debug(44, 1) ("calling aclChecklistFree() from peerSelectStateFree\n");
108 delete (psstate->acl_checklist);
109 }
110
111 requestUnlink(psstate->request);
112 psstate->request = NULL;
113
114 if (psstate->entry) {
115 assert(psstate->entry->ping_status != PING_WAITING);
116 storeUnlockObject(psstate->entry);
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 debug(44, 3) ("peerSelectIcpPing: %s\n", storeUrl(entry));
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 debug(44, 3) ("peerSelectIcpPing: counted %d neighbors\n", n);
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 debug(44, 3) ("peerSelect: %s\n", storeUrl(entry));
157 else
158 debug(44, 3) ("peerSelect: %s\n", RequestMethodStr[request->method]);
159
160 psstate = cbdataAlloc(ps_state);
161
162 psstate->request = requestLink(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 storeLockObject(psstate->entry);
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 debug(44, 3) ("peerCheckNeverDirectDone: %d\n", 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 debug(44, 3) ("peerCheckAlwaysDirectDone: %d\n", 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 debug(44, 3) ("peerSelectCallback: %s\n", storeUrl(entry));
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 debug(44, 1) ("Failed to select source for '%s'\n", storeUrl(entry));
223 debug(44, 1) (" always_direct = %d\n", psstate->always_direct);
224 debug(44, 1) (" never_direct = %d\n", psstate->never_direct);
225 debug(44, 1) (" timedout = %d\n", 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->host);
252
253 debug(44, 3) ("peerCheckNetdbDirect: MY RTT = %d msec\n", myrtt);
254
255 debug(44, 3) ("peerCheckNetdbDirect: minimum_direct_rtt = %d msec\n",
256 Config.minDirectRtt);
257
258 if (myrtt && myrtt <= Config.minDirectRtt)
259 return 1;
260
261 myhops = netdbHostHops(psstate->request->host);
262
263 debug(44, 3) ("peerCheckNetdbDirect: MY hops = %d\n", myhops);
264
265 debug(44, 3) ("peerCheckNetdbDirect: minimum_direct_hops = %d\n",
266 Config.minDirectHops);
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 debug(44, 3) ("peerCheckNetdbDirect: closest_parent_miss RTT = %d msec\n",
277 psstate->ping.p_rtt);
278
279 if (myrtt && myrtt <= psstate->ping.p_rtt)
280 return 1;
281
282 return 0;
283 }
284
285 static void
286 peerSelectFoo(ps_state * ps)
287 {
288 StoreEntry *entry = ps->entry;
289 HttpRequest *request = ps->request;
290 debug(44, 3) ("peerSelectFoo: '%s %s'\n",
291 RequestMethodStr[request->method],
292 request->host);
293
294 if (ps->direct == DIRECT_UNKNOWN) {
295 if (ps->always_direct == 0 && Config.accessList.AlwaysDirect) {
296 ps->acl_checklist = aclChecklistCreate(
297 Config.accessList.AlwaysDirect,
298 request,
299 NULL); /* ident */
300 ps->acl_checklist->nonBlockingCheck(peerCheckAlwaysDirectDone,
301 ps);
302 return;
303 } else if (ps->always_direct > 0) {
304 ps->direct = DIRECT_YES;
305 } else if (ps->never_direct == 0 && Config.accessList.NeverDirect) {
306 ps->acl_checklist = aclChecklistCreate(
307 Config.accessList.NeverDirect,
308 request,
309 NULL); /* ident */
310 ps->acl_checklist->nonBlockingCheck(peerCheckNeverDirectDone,
311 ps);
312 return;
313 } else if (ps->never_direct > 0) {
314 ps->direct = DIRECT_NO;
315 } else if (request->flags.accelerated) {
316 ps->direct = DIRECT_NO;
317 } else if (request->flags.loopdetect) {
318 ps->direct = DIRECT_YES;
319 } else if (peerCheckNetdbDirect(ps)) {
320 ps->direct = DIRECT_YES;
321 } else {
322 ps->direct = DIRECT_MAYBE;
323 }
324
325 debug(44, 3) ("peerSelectFoo: direct = %s\n",
326 DirectStr[ps->direct]);
327 }
328
329 if (entry == NULL) {
330 (void) 0;
331 } else if (entry->ping_status == PING_NONE) {
332 peerGetSomeNeighbor(ps);
333
334 if (entry->ping_status == PING_WAITING)
335 return;
336 } else if (entry->ping_status == PING_WAITING) {
337 peerGetSomeNeighborReplies(ps);
338 entry->ping_status = PING_DONE;
339 }
340
341 switch (ps->direct) {
342
343 case DIRECT_YES:
344 peerGetSomeDirect(ps);
345 break;
346
347 case DIRECT_NO:
348 peerGetSomeParent(ps);
349 peerGetAllParents(ps);
350 break;
351
352 default:
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;
364 }
365
366 peerSelectCallback(ps);
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 */
379 static void
380 peerGetSomeNeighbor(ps_state * ps)
381 {
382 StoreEntry *entry = ps->entry;
383 HttpRequest *request = ps->request;
384 peer *p;
385 hier_code code = HIER_NONE;
386 assert(entry->ping_status == PING_NONE);
387
388 if (ps->direct == DIRECT_YES) {
389 entry->ping_status = PING_DONE;
390 return;
391 }
392
393 #if USE_CACHE_DIGESTS
394 if ((p = neighborsDigestSelect(request))) {
395 if (neighborType(p, request) == PEER_PARENT)
396 code = CD_PARENT_HIT;
397 else
398 code = CD_SIBLING_HIT;
399 } else
400 #endif
401 if ((p = netdbClosestParent(request))) {
402 code = CLOSEST_PARENT;
403 } else if (peerSelectIcpPing(request, ps->direct, entry)) {
404 debug(44, 3) ("peerSelect: Doing ICP pings\n");
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)
414 debug(44, 0) ("WARNING: neighborsUdpPing returned 0\n");
415
416 debug(44, 3) ("peerSelect: %d ICP replies expected, RTT %d msec\n",
417 ps->ping.n_replies_expected, ps->ping.timeout);
418
419 if (ps->ping.n_replies_expected > 0) {
420 entry->ping_status = PING_WAITING;
421 eventAdd("peerPingTimeout",
422 peerPingTimeout,
423 ps,
424 0.001 * ps->ping.timeout,
425 0);
426 return;
427 }
428 }
429
430 if (code != HIER_NONE) {
431 assert(p);
432 debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], p->host);
433 peerAddFwdServer(&ps->servers, p, code);
434 }
435
436 entry->ping_status = PING_DONE;
437 }
438
439 /*
440 * peerGetSomeNeighborReplies
441 *
442 * Selects a neighbor (parent or sibling) based on ICP/HTCP replies.
443 */
444 static void
445 peerGetSomeNeighborReplies(ps_state * ps)
446 {
447 HttpRequest *request = ps->request;
448 peer *p = NULL;
449 hier_code code = HIER_NONE;
450 assert(ps->entry->ping_status == PING_WAITING);
451 assert(ps->direct != DIRECT_YES);
452
453 if (peerCheckNetdbDirect(ps)) {
454 code = CLOSEST_DIRECT;
455 debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], request->host);
456 peerAddFwdServer(&ps->servers, NULL, code);
457 return;
458 }
459
460 if ((p = ps->hit)) {
461 code = ps->hit_type == PEER_PARENT ? PARENT_HIT : SIBLING_HIT;
462 } else
463 #if ALLOW_SOURCE_PING
464 if ((p = ps->secho)) {
465 code = SOURCE_FASTEST;
466 } else
467 #endif
468 if (ps->closest_parent_miss.sin_addr.s_addr != any_addr.s_addr) {
469 p = whichPeer(&ps->closest_parent_miss);
470 code = CLOSEST_PARENT_MISS;
471 } else if (ps->first_parent_miss.sin_addr.s_addr != any_addr.s_addr) {
472 p = whichPeer(&ps->first_parent_miss);
473 code = FIRST_PARENT_MISS;
474 }
475
476 if (p && code != HIER_NONE) {
477 debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], p->host);
478 peerAddFwdServer(&ps->servers, p, code);
479 }
480 }
481
482
483 /*
484 * peerGetSomeDirect
485 *
486 * Simply adds a 'direct' entry to the FwdServers list if this
487 * request can be forwarded directly to the origin server
488 */
489 static void
490 peerGetSomeDirect(ps_state * ps)
491 {
492 if (ps->direct == DIRECT_NO)
493 return;
494
495 if (ps->request->protocol == PROTO_WAIS)
496 /* Its not really DIRECT, now is it? */
497 peerAddFwdServer(&ps->servers, Config.Wais._peer, DIRECT);
498 else
499 peerAddFwdServer(&ps->servers, NULL, DIRECT);
500 }
501
502 static void
503 peerGetSomeParent(ps_state * ps)
504 {
505 peer *p;
506 HttpRequest *request = ps->request;
507 hier_code code = HIER_NONE;
508 debug(44, 3) ("peerGetSomeParent: %s %s\n",
509 RequestMethodStr[request->method],
510 request->host);
511
512 if (ps->direct == DIRECT_YES)
513 return;
514
515 if ((p = getDefaultParent(request))) {
516 code = DEFAULT_PARENT;
517 #if USE_CARP
518
519 } else if ((p = carpSelectParent(request))) {
520 code = CARP;
521 #endif
522
523 } else if ((p = getRoundRobinParent(request))) {
524 code = ROUNDROBIN_PARENT;
525 } else if ((p = getWeightedRoundRobinParent(request))) {
526 code = ROUNDROBIN_PARENT;
527 } else if ((p = getFirstUpParent(request))) {
528 code = FIRSTUP_PARENT;
529 } else if ((p = getAnyParent(request))) {
530 code = ANY_OLD_PARENT;
531 }
532
533 if (code != HIER_NONE) {
534 debug(44, 3) ("peerSelect: %s/%s\n", hier_strings[code], p->host);
535 peerAddFwdServer(&ps->servers, p, code);
536 }
537 }
538
539 /* Adds alive parents. Used as a last resort for never_direct.
540 */
541 static void
542 peerGetAllParents(ps_state * ps)
543 {
544 peer *p;
545 HttpRequest *request = ps->request;
546 /* Add all alive parents */
547
548 for (p = Config.peers; p; p = p->next) {
549 /* XXX: neighbors.c lacks a public interface for enumerating
550 * parents to a request so we have to dig some here..
551 */
552
553 if (neighborType(p, request) != PEER_PARENT)
554 continue;
555
556 if (!peerHTTPOkay(p, request))
557 continue;
558
559 debug(15, 3) ("peerGetAllParents: adding alive parent %s\n", p->host);
560
561 peerAddFwdServer(&ps->servers, p, ANY_OLD_PARENT);
562 }
563
564 /* XXX: should add dead parents here, but it is currently
565 * not possible to find out which parents are dead or which
566 * simply are not configured to handle the request.
567 */
568 /* Add default parent as a last resort */
569 if ((p = getDefaultParent(request))) {
570 peerAddFwdServer(&ps->servers, p, DEFAULT_PARENT);
571 }
572 }
573
574 static void
575 peerPingTimeout(void *data)
576 {
577 ps_state *psstate = (ps_state *)data;
578 StoreEntry *entry = psstate->entry;
579
580 if (entry)
581 debug(44, 3) ("peerPingTimeout: '%s'\n", storeUrl(entry));
582
583 if (!cbdataReferenceValid(psstate->callback_data)) {
584 /* request aborted */
585 entry->ping_status = PING_DONE;
586 cbdataReferenceDone(psstate->callback_data);
587 peerSelectStateFree(psstate);
588 return;
589 }
590
591 PeerStats.timeouts++;
592 psstate->ping.timedout = 1;
593 peerSelectFoo(psstate);
594 }
595
596 void
597 peerSelectInit(void)
598 {
599 memset(&PeerStats, '\0', sizeof(PeerStats));
600 assert(sizeof(hier_strings) == (HIER_MAX + 1) * sizeof(char *));
601 }
602
603 static void
604 peerIcpParentMiss(peer * p, icp_common_t * header, ps_state * ps)
605 {
606 int rtt;
607 int hops;
608
609 if (Config.onoff.query_icmp) {
610 if (header->flags & ICP_FLAG_SRC_RTT) {
611 rtt = header->pad & 0xFFFF;
612 hops = (header->pad >> 16) & 0xFFFF;
613
614 if (rtt > 0 && rtt < 0xFFFF)
615 netdbUpdatePeer(ps->request, p, rtt, hops);
616
617 if (rtt && (ps->ping.p_rtt == 0 || rtt < ps->ping.p_rtt)) {
618 ps->closest_parent_miss = p->in_addr;
619 ps->ping.p_rtt = rtt;
620 }
621 }
622 }
623
624 /* if closest-only is set, then don't allow FIRST_PARENT_MISS */
625 if (p->options.closest_only)
626 return;
627
628 /* set FIRST_MISS if there is no CLOSEST parent */
629 if (ps->closest_parent_miss.sin_addr.s_addr != any_addr.s_addr)
630 return;
631
632 rtt = (tvSubMsec(ps->ping.start, current_time) - p->basetime) / p->weight;
633
634 if (rtt < 1)
635 rtt = 1;
636
637 if (ps->first_parent_miss.sin_addr.s_addr == any_addr.s_addr ||
638 rtt < ps->ping.w_rtt) {
639 ps->first_parent_miss = p->in_addr;
640 ps->ping.w_rtt = rtt;
641 }
642 }
643
644 static void
645 peerHandleIcpReply(peer * p, peer_t type, icp_common_t * header, void *data)
646 {
647 ps_state *psstate = (ps_state *)data;
648 icp_opcode op = header->getOpCode();
649 debug(44, 3) ("peerHandleIcpReply: %s %s\n",
650 icp_opcode_str[op],
651 storeUrl(psstate->entry));
652 #if USE_CACHE_DIGESTS && 0
653 /* do cd lookup to count false misses */
654
655 if (p && request)
656 peerNoteDigestLookup(request, p,
657 peerDigestLookup(p, request, psstate->entry));
658
659 #endif
660
661 psstate->ping.n_recv++;
662
663 if (op == ICP_MISS || op == ICP_DECHO) {
664 if (type == PEER_PARENT)
665 peerIcpParentMiss(p, header, psstate);
666 } else if (op == ICP_HIT) {
667 psstate->hit = p;
668 psstate->hit_type = type;
669 peerSelectFoo(psstate);
670 return;
671 }
672
673 #if ALLOW_SOURCE_PING
674 else if (op == ICP_SECHO) {
675 psstate->secho = p;
676 peerSelectFoo(psstate);
677 return;
678 }
679
680 #endif
681 if (psstate->ping.n_recv < psstate->ping.n_replies_expected)
682 return;
683
684 peerSelectFoo(psstate);
685 }
686
687 #if USE_HTCP
688 static void
689 peerHandleHtcpReply(peer * p, peer_t type, htcpReplyData * htcp, void *data)
690 {
691 ps_state *psstate = (ps_state *)data;
692 debug(44, 3) ("peerHandleIcpReply: %s %s\n",
693 htcp->hit ? "HIT" : "MISS",
694 storeUrl(psstate->entry));
695 psstate->ping.n_recv++;
696
697 if (htcp->hit) {
698 psstate->hit = p;
699 psstate->hit_type = type;
700 peerSelectFoo(psstate);
701 return;
702 }
703
704 if (type == PEER_PARENT)
705 peerHtcpParentMiss(p, htcp, psstate);
706
707 if (psstate->ping.n_recv < psstate->ping.n_replies_expected)
708 return;
709
710 peerSelectFoo(psstate);
711 }
712
713 static void
714 peerHtcpParentMiss(peer * p, htcpReplyData * htcp, ps_state * ps)
715 {
716 int rtt;
717 int hops;
718
719 if (Config.onoff.query_icmp) {
720 if (htcp->cto.rtt > 0) {
721 rtt = (int) htcp->cto.rtt * 1000;
722 hops = (int) htcp->cto.hops * 1000;
723 netdbUpdatePeer(ps->request, p, rtt, hops);
724
725 if (rtt && (ps->ping.p_rtt == 0 || rtt < ps->ping.p_rtt)) {
726 ps->closest_parent_miss = p->in_addr;
727 ps->ping.p_rtt = rtt;
728 }
729 }
730 }
731
732 /* if closest-only is set, then don't allow FIRST_PARENT_MISS */
733 if (p->options.closest_only)
734 return;
735
736 /* set FIRST_MISS if there is no CLOSEST parent */
737 if (ps->closest_parent_miss.sin_addr.s_addr != any_addr.s_addr)
738 return;
739
740 rtt = (tvSubMsec(ps->ping.start, current_time) - p->basetime) / p->weight;
741
742 if (rtt < 1)
743 rtt = 1;
744
745 if (ps->first_parent_miss.sin_addr.s_addr == any_addr.s_addr ||
746 rtt < ps->ping.w_rtt) {
747 ps->first_parent_miss = p->in_addr;
748 ps->ping.w_rtt = rtt;
749 }
750 }
751
752 #endif
753
754 static void
755 peerHandlePingReply(peer * p, peer_t type, protocol_t proto, void *pingdata, void *data)
756 {
757 if (proto == PROTO_ICP)
758 peerHandleIcpReply(p, type, (icp_common_t *)pingdata, data);
759
760 #if USE_HTCP
761
762 else if (proto == PROTO_HTCP)
763 peerHandleHtcpReply(p, type, (htcpReplyData *)pingdata, data);
764
765 #endif
766
767 else
768 debug(44, 1) ("peerHandlePingReply: unknown protocol_t %d\n", (int) proto);
769 }
770
771 static void
772 peerAddFwdServer(FwdServer ** FS, peer * p, hier_code code)
773 {
774 FwdServer *fs = (FwdServer *)memAllocate(MEM_FWD_SERVER);
775 debug(44, 5) ("peerAddFwdServer: adding %s %s\n",
776 p ? p->host : "DIRECT",
777 hier_strings[code]);
778 fs->_peer = cbdataReference(p);
779 fs->code = code;
780
781 while (*FS)
782 FS = &(*FS)->next;
783
784 *FS = fs;
785 }