]> git.ipfire.org Git - thirdparty/squid.git/blame - src/neighbors.cc
Synced #includes after moving files around.
[thirdparty/squid.git] / src / neighbors.cc
CommitLineData
30a4f2a8 1/*
30a4f2a8 2 * DEBUG: section 15 Neighbor Routines
3 * AUTHOR: Harvest Derived
4 *
2b6662ba 5 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 6 * ----------------------------------------------------------
30a4f2a8 7 *
2b6662ba 8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
30a4f2a8 16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
26ac0430 21 *
30a4f2a8 22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26ac0430 26 *
30a4f2a8 27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
cbdec147 29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 30 *
019dd986 31 */
090089c4 32
44a47c6e 33#include "squid.h"
07f765a3 34#include "ProtoPort.h"
aa839030 35#include "ACLChecklist.h"
a553a5a3 36#include "event.h"
62ee09ca 37#include "CacheManager.h"
aa839030 38#include "htcp.h"
528b2c61 39#include "HttpRequest.h"
aa839030 40#include "ICP.h"
528b2c61 41#include "MemObject.h"
aa839030 42#include "PeerDigest.h"
b24880fe 43#include "PeerSelectState.h"
985c86bc 44#include "SquidTime.h"
aa839030 45#include "Store.h"
9b5c4a9a 46#include "icmp/net_db.h"
9837e5f0 47#include "ip/IpAddress.h"
090089c4 48
429fdbec 49/* count mcast group peers every 15 minutes */
50#define MCAST_COUNT_RATE 900
51
d67acb4e 52int peerAllowedToUse(const peer *, HttpRequest *);
190154cf 53static int peerWouldBePinged(const peer *, HttpRequest *);
f5b8bbc4 54static void neighborRemove(peer *);
f5b8bbc4 55static void neighborAlive(peer *, const MemObject *, const icp_common_t *);
399cabec 56#if USE_HTCP
57static void neighborAliveHtcp(peer *, const MemObject *, const htcpReplyData *);
58#endif
56b62ecc 59static void neighborCountIgnored(peer *);
f5b8bbc4 60static void peerRefreshDNS(void *);
b69f7771 61static IPH peerDNSConfigure;
4ed0e075 62static int peerProbeConnect(peer *);
eb406bb7 63static CNCB peerProbeConnectDone;
f5b8bbc4 64static void peerCountMcastPeersDone(void *data);
65static void peerCountMcastPeersStart(void *data);
66static void peerCountMcastPeersSchedule(peer * p, time_t when);
b3264694 67static IRCB peerCountHandleIcpReply;
62e76326 68
ad61a2b4 69static void neighborIgnoreNonPeer(const IpAddress &, icp_opcode);
ed7f5615 70static OBJH neighborDumpPeers;
71static OBJH neighborDumpNonPeers;
72static void dump_peers(StoreEntry * sentry, peer * peers);
090089c4 73
090089c4 74static icp_common_t echo_hdr;
30a4f2a8 75static u_short echo_port;
30a4f2a8 76
c7a3724d 77static int NLateReplies = 0;
40a1495e 78static peer *first_ping = NULL;
28070024 79
a2c963ae 80const char *
b69f7771 81neighborTypeStr(const peer * p)
69a71bd7 82{
e102ebda 83 if (p->type == PEER_NONE)
62e76326 84 return "Non-Peer";
85
b69f7771 86 if (p->type == PEER_SIBLING)
62e76326 87 return "Sibling";
88
b69f7771 89 if (p->type == PEER_MULTICAST)
62e76326 90 return "Multicast Group";
91
69a71bd7 92 return "Parent";
93}
94
090089c4 95
d9f9d78b 96peer *
ad61a2b4 97whichPeer(const IpAddress &from)
090089c4 98{
22e4fa85 99 int j;
62e76326 100
b69f7771 101 peer *p = NULL;
cc192b50 102 debugs(15, 3, "whichPeer: from " << from);
62e76326 103
26ac0430 104 for (p = Config.peers; p; p = p->next) {
62e76326 105 for (j = 0; j < p->n_addresses; j++) {
cc192b50 106 if (from == p->addresses[j] && from.GetPort() == p->icp.port) {
62e76326 107 return p;
108 }
109 }
090089c4 110 }
62e76326 111
4eda6afe 112 return NULL;
090089c4 113}
114
701a8572 115peer_t
190154cf 116neighborType(const peer * p, const HttpRequest * request)
24a1003d 117{
62e76326 118
b012353a 119 const struct _domain_type *d = NULL;
62e76326 120
b69f7771 121 for (d = p->typelist; d; d = d->next) {
cc192b50 122 if (0 == matchDomainName(request->GetHost(), d->domain))
62e76326 123 if (d->type != PEER_NONE)
124 return d->type;
24a1003d 125 }
62e76326 126
b69f7771 127 return p->type;
24a1003d 128}
129
7b3bd12c 130/*
62fd6124 131 * peerAllowedToUse
7b3bd12c 132 *
dd4bd44e 133 * this function figures out if it is appropriate to fetch REQUEST
62fd6124 134 * from PEER.
7b3bd12c 135 */
d67acb4e 136int
190154cf 137peerAllowedToUse(const peer * p, HttpRequest * request)
090089c4 138{
62e76326 139
b012353a 140 const struct _domain_ping *d = NULL;
090089c4 141 int do_ping = 1;
ce66013b 142 assert(request != NULL);
62e76326 143
9689d97c 144 if (neighborType(p, request) == PEER_SIBLING) {
62e76326 145 if (request->flags.nocache)
146 return 0;
147
148 if (request->flags.refresh)
149 return 0;
150
151 if (request->flags.loopdetect)
152 return 0;
153
154 if (request->flags.need_validation)
155 return 0;
9689d97c 156 }
62e76326 157
b6a2f15e 158 if (p->peer_domain == NULL && p->access == NULL)
62e76326 159 return do_ping;
160
090089c4 161 do_ping = 0;
62e76326 162
b6a2f15e 163 for (d = p->peer_domain; d; d = d->next) {
cc192b50 164 if (0 == matchDomainName(request->GetHost(), d->domain)) {
62e76326 165 do_ping = d->do_ping;
166 break;
167 }
168
169 do_ping = !d->do_ping;
30a4f2a8 170 }
62e76326 171
b6a2f15e 172 if (p->peer_domain && 0 == do_ping)
62e76326 173 return do_ping;
174
505e35db 175 if (p->access == NULL)
62e76326 176 return do_ping;
177
4fb35c3c 178 ACLChecklist checklist;
62e76326 179
8ae8bb05 180 checklist.src_addr = request->client_addr;
62e76326 181
3c11d1f5 182 checklist.my_addr = request->my_addr;
62e76326 183
6dd9f4bd 184 checklist.request = HTTPMSGLOCK(request);
62e76326 185
506768d9 186 checklist.accessList = cbdataReference(p->access);
b448c119 187
108d65b2 188 /* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */
189
4749aee5 190#if 0 && USE_IDENT
191 /*
192 * this is currently broken because 'request->user_ident' has been
193 * moved to conn->rfc931 and we don't have access to the parent
194 * ConnStateData here.
195 */
94e7025e 196 if (request->user_ident[0])
62e76326 197 xstrncpy(checklist.rfc931, request->user_ident, USER_IDENT_SZ);
198
94e7025e 199#endif
62e76326 200
108d65b2 201 return checklist.fastCheck();
090089c4 202}
203
62fd6124 204/* Return TRUE if it is okay to send an ICP request to this peer. */
205static int
190154cf 206peerWouldBePinged(const peer * p, HttpRequest * request)
62fd6124 207{
b69f7771 208 if (!peerAllowedToUse(p, request))
62e76326 209 return 0;
210
cd196bc8 211 if (p->options.no_query)
62e76326 212 return 0;
213
d1b63fc8 214 if (p->options.background_ping && (squid_curtime - p->stats.last_query < Config.backgroundPingRate))
62e76326 215 return 0;
216
cd196bc8 217 if (p->options.mcast_responder)
62e76326 218 return 0;
219
83b381d5 220 if (p->n_addresses == 0)
62e76326 221 return 0;
222
0e614a06 223 if (p->icp.port == 0)
62e76326 224 return 0;
225
62fd6124 226 /* the case below seems strange, but can happen if the
227 * URL host is on the other side of a firewall */
b69f7771 228 if (p->type == PEER_SIBLING)
62e76326 229 if (!request->flags.hierarchical)
230 return 0;
231
83b381d5 232 /* Ping dead peers every timeout interval */
233 if (squid_curtime - p->stats.last_query > Config.Timeout.deadPeer)
62e76326 234 return 1;
235
5537c535 236 if (!neighborUp(p))
237 return 0;
62e76326 238
62fd6124 239 return 1;
240}
241
242/* Return TRUE if it is okay to send an HTTP request to this peer. */
8ff4505b 243int
190154cf 244peerHTTPOkay(const peer * p, HttpRequest * request)
62fd6124 245{
b69f7771 246 if (!peerAllowedToUse(p, request))
62e76326 247 return 0;
248
b69f7771 249 if (!neighborUp(p))
62e76326 250 return 0;
251
c7f9eb6d 252 if (p->max_conn)
62e76326 253 if (p->stats.conn_open >= p->max_conn)
254 return 0;
255
62fd6124 256 return 1;
257}
258
3c6e634f 259int
190154cf 260neighborsCount(HttpRequest * request)
090089c4 261{
b69f7771 262 peer *p = NULL;
090089c4 263 int count = 0;
62e76326 264
40a1495e 265 for (p = Config.peers; p; p = p->next)
62e76326 266 if (peerWouldBePinged(p, request))
267 count++;
268
bf8fe701 269 debugs(15, 3, "neighborsCount: " << count);
62e76326 270
3c6e634f 271 return count;
272}
090089c4 273
deb79f06 274peer *
190154cf 275getFirstUpParent(HttpRequest * request)
090089c4 276{
b69f7771 277 peer *p = NULL;
62e76326 278
40a1495e 279 for (p = Config.peers; p; p = p->next) {
62e76326 280 if (!neighborUp(p))
281 continue;
282
283 if (neighborType(p, request) != PEER_PARENT)
284 continue;
285
286 if (!peerHTTPOkay(p, request))
287 continue;
288
289 break;
090089c4 290 }
62e76326 291
bf8fe701 292 debugs(15, 3, "getFirstUpParent: returning " << (p ? p->host : "NULL"));
b69f7771 293 return p;
090089c4 294}
295
deb79f06 296peer *
190154cf 297getRoundRobinParent(HttpRequest * request)
48b38d01 298{
b69f7771 299 peer *p;
300 peer *q = NULL;
62e76326 301
40a1495e 302 for (p = Config.peers; p; p = p->next) {
62e76326 303 if (!p->options.roundrobin)
304 continue;
305
306 if (neighborType(p, request) != PEER_PARENT)
307 continue;
308
309 if (!peerHTTPOkay(p, request))
310 continue;
311
1d0bef67 312 if (p->weight == 0)
0d5a2006 313 continue;
1d0bef67
AJ
314
315 if (q) {
316 if (p->weight == q->weight) {
317 if (q->rr_count < p->rr_count)
318 continue;
319 } else if ( (double) q->rr_count / q->weight < (double) p->rr_count / p->weight) {
320 continue;
321 }
0d5a2006 322 }
62e76326 323
324 q = p;
48b38d01 325 }
62e76326 326
b69f7771 327 if (q)
62e76326 328 q->rr_count++;
329
1d0bef67 330 debugs(15, 3, HERE << "returning " << (q ? q->host : "NULL"));
62e76326 331
b69f7771 332 return q;
48b38d01 333}
334
d1b63fc8 335peer *
190154cf 336getWeightedRoundRobinParent(HttpRequest * request)
d1b63fc8 337{
338 peer *p;
339 peer *q = NULL;
340 int weighted_rtt;
62e76326 341
d1b63fc8 342 for (p = Config.peers; p; p = p->next) {
62e76326 343 if (!p->options.weighted_roundrobin)
344 continue;
345
346 if (neighborType(p, request) != PEER_PARENT)
347 continue;
348
349 if (!peerHTTPOkay(p, request))
350 continue;
351
352 if (q && q->rr_count < p->rr_count)
353 continue;
354
355 q = p;
d1b63fc8 356 }
62e76326 357
d1b63fc8 358 if (q && q->rr_count > 1000000)
62e76326 359 for (p = Config.peers; p; p = p->next) {
360 if (!p->options.weighted_roundrobin)
361 continue;
362
363 if (neighborType(p, request) != PEER_PARENT)
364 continue;
365
366 p->rr_count = 0;
367 }
368
d1b63fc8 369 if (q) {
62e76326 370 weighted_rtt = (q->stats.rtt - q->basetime) / q->weight;
d1b63fc8 371
62e76326 372 if (weighted_rtt < 1)
373 weighted_rtt = 1;
374
375 q->rr_count += weighted_rtt;
376
4a7a3d56 377 debugs(15, 3, "getWeightedRoundRobinParent: weighted_rtt " << weighted_rtt);
d1b63fc8 378 }
62e76326 379
bf8fe701 380 debugs(15, 3, "getWeightedRoundRobinParent: returning " << (q ? q->host : "NULL"));
d1b63fc8 381 return q;
382}
383
32a47e3e
AJ
384/**
385 * This gets called every 5 minutes to clear the round-robin counter.
386 * The exact timing is an arbitrary default, set on estimate timing of a
387 * large number of requests in a high-performance environment during the
388 * period. The larger the number of requests between cycled resets the
389 * more balanced the operations.
390 *
391 \param data unused.
392 \todo Make the reset timing a selectable parameter in squid.conf
393 */
26ac0430 394static void
32a47e3e
AJ
395peerClearRRLoop(void *data)
396{
397 peerClearRR();
398 eventAdd("peerClearRR", peerClearRRLoop, data, 5 * 60.0, 0);
399}
400
401/**
402 * This gets called on startup and restart to kick off the peer round-robin
403 * maintenance event. It ensures that no matter how many times its called
404 * no more than one event is scheduled.
405 */
82056f1e 406void
32a47e3e 407peerClearRRStart(void)
82056f1e 408{
32a47e3e
AJ
409 static int event_added = 0;
410 if (!event_added) {
411 peerClearRRLoop(NULL);
412 }
413}
62e76326 414
32a47e3e
AJ
415/**
416 * Called whenever the round-robin counters need to be reset to a sane state.
417 * So far those times are:
418 \item On startup and reconfigure - to set the counters to sane initial settings.
419 \item When a peer has revived from dead, to prevent the revived peer being
420 * flooded with requests which it has 'missed' during the down period.
421 */
422void
423peerClearRR()
424{
425 peer *p = NULL;
426 for (p = Config.peers; p; p = p->next) {
62e76326 427 p->rr_count = 0;
32a47e3e
AJ
428 }
429}
62e76326 430
32a47e3e
AJ
431/**
432 * Perform all actions when a peer is detected revived.
433 */
434void
435peerAlive(peer *p)
436{
437 if (p->stats.logged_state == PEER_DEAD && p->tcp_up) {
438 debugs(15, 1, "Detected REVIVED " << neighborTypeStr(p) << ": " << p->name);
439 p->stats.logged_state = PEER_ALIVE;
440 peerClearRR();
441 }
62e76326 442
32a47e3e
AJ
443 p->stats.last_reply = squid_curtime;
444 p->stats.probe_start = 0;
82056f1e 445}
446
deb79f06 447peer *
190154cf 448getDefaultParent(HttpRequest * request)
5269d0bd 449{
b69f7771 450 peer *p = NULL;
62e76326 451
40a1495e 452 for (p = Config.peers; p; p = p->next) {
62e76326 453 if (neighborType(p, request) != PEER_PARENT)
454 continue;
455
456 if (!p->options.default_parent)
457 continue;
458
459 if (!peerHTTPOkay(p, request))
460 continue;
461
bf8fe701 462 debugs(15, 3, "getDefaultParent: returning " << p->host);
62e76326 463
464 return p;
5269d0bd 465 }
62e76326 466
bf8fe701 467 debugs(15, 3, "getDefaultParent: returning NULL");
5269d0bd 468 return NULL;
469}
470
3c50f9bd 471/*
472 * XXX DW thinks this function is equivalent to/redundant with
473 * getFirstUpParent(). peerHTTPOkay() only returns true if the
26ac0430 474 * peer is UP anyway, so this function would not return a
3c50f9bd 475 * DOWN parent.
476 */
6a655df0 477peer *
190154cf 478getAnyParent(HttpRequest * request)
6a655df0 479{
480 peer *p = NULL;
62e76326 481
6a655df0 482 for (p = Config.peers; p; p = p->next) {
62e76326 483 if (neighborType(p, request) != PEER_PARENT)
484 continue;
485
486 if (!peerHTTPOkay(p, request))
487 continue;
488
bf8fe701 489 debugs(15, 3, "getAnyParent: returning " << p->host);
62e76326 490
491 return p;
6a655df0 492 }
62e76326 493
bf8fe701 494 debugs(15, 3, "getAnyParent: returning NULL");
6a655df0 495 return NULL;
496}
497
deb79f06 498peer *
b69f7771 499getNextPeer(peer * p)
090089c4 500{
b69f7771 501 return p->next;
090089c4 502}
503
deb79f06 504peer *
505getFirstPeer(void)
090089c4 506{
40a1495e 507 return Config.peers;
090089c4 508}
509
b8d8561b 510static void
deb79f06 511neighborRemove(peer * target)
30a4f2a8 512{
b69f7771 513 peer *p = NULL;
514 peer **P = NULL;
40a1495e 515 p = Config.peers;
516 P = &Config.peers;
62e76326 517
b69f7771 518 while (p) {
62e76326 519 if (target == p)
520 break;
521
522 P = &p->next;
523
524 p = p->next;
b69f7771 525 }
62e76326 526
b69f7771 527 if (p) {
62e76326 528 *P = p->next;
529 cbdataFree(p);
530 Config.npeers--;
4d64d74a 531 }
62e76326 532
40a1495e 533 first_ping = Config.peers;
4d64d74a 534}
535
5f5e883f
FC
536static void
537neighborsRegisterWithCacheManager()
538{
539 CacheManager *manager = CacheManager::GetInstance();
540 manager->registerAction("server_list",
26ac0430
AJ
541 "Peer Cache Statistics",
542 neighborDumpPeers, 0, 1);
5f5e883f
FC
543
544 if (theInIcpConnection >= 0) {
545 manager->registerAction("non_peers",
26ac0430
AJ
546 "List of Unknown sites sending ICP messages",
547 neighborDumpNonPeers, 0, 1);
5f5e883f
FC
548 }
549}
550
b8d8561b 551void
a86029b9 552neighbors_init(void)
090089c4 553{
ad61a2b4 554 IpAddress nul;
cc192b50 555 struct addrinfo *AI = NULL;
30a4f2a8 556 struct servent *sep = NULL;
b263bd3f 557 const char *me = getMyHostname();
cc192b50 558 peer *thisPeer = NULL;
559 peer *next = NULL;
a86029b9 560 int fd = theInIcpConnection;
62e76326 561
6fdc2d18
FC
562 neighborsRegisterWithCacheManager();
563
cc192b50 564 /* setup addrinfo for use */
565 nul.InitAddrInfo(AI);
62e76326 566
cc192b50 567 if (fd >= 0) {
62e76326 568
cc192b50 569 if (getsockname(fd, AI->ai_addr, &AI->ai_addrlen) < 0)
570 debugs(15, 1, "getsockname(" << fd << "," << AI->ai_addr << "," << &AI->ai_addrlen << ") failed.");
62e76326 571
572 for (thisPeer = Config.peers; thisPeer; thisPeer = next) {
cc192b50 573 http_port_list *s = NULL;
62e76326 574 next = thisPeer->next;
575
576 if (0 != strcmp(thisPeer->host, me))
577 continue;
578
579 for (s = Config.Sockaddr.http; s; s = s->next) {
cc192b50 580 if (thisPeer->http_port != s->s.GetPort())
62e76326 581 continue;
582
bf8fe701 583 debugs(15, 1, "WARNING: Peer looks like this host");
584
585 debugs(15, 1, " Ignoring " <<
586 neighborTypeStr(thisPeer) << " " << thisPeer->host <<
587 "/" << thisPeer->http_port << "/" <<
588 thisPeer->icp.port);
62e76326 589
62e76326 590 neighborRemove(thisPeer);
591 }
592 }
b263bd3f 593 }
62e76326 594
5999b776 595 peerRefreshDNS((void *) 1);
62e76326 596
e6ccf245 597 if (ICP_INVALID == echo_hdr.opcode) {
62e76326 598 echo_hdr.opcode = ICP_SECHO;
599 echo_hdr.version = ICP_VERSION_CURRENT;
600 echo_hdr.length = 0;
601 echo_hdr.reqnum = 0;
602 echo_hdr.flags = 0;
603 echo_hdr.pad = 0;
cc192b50 604 nul = *AI;
605 nul.GetInAddr( *((struct in_addr*)&echo_hdr.shostid) );
62e76326 606 sep = getservbyname("echo", "udp");
607 echo_port = sep ? ntohs((u_short) sep->s_port) : 7;
090089c4 608 }
62e76326 609
c68e4e90 610 first_ping = Config.peers;
cc192b50 611 nul.FreeAddrInfo(AI);
62ee09ca 612}
613
b8d8561b 614int
190154cf 615neighborsUdpPing(HttpRequest * request,
62e76326 616 StoreEntry * entry,
617 IRCB * callback,
618 void *callback_data,
619 int *exprep,
620 int *timeout)
090089c4 621{
3900307b 622 const char *url = entry->url();
b6c0e933 623 MemObject *mem = entry->mem_obj;
b69f7771 624 peer *p = NULL;
090089c4 625 int i;
1061b406 626 int reqnum = 0;
6d2296d4 627 int flags;
9dee2904 628 icp_common_t *query;
429fdbec 629 int queries_sent = 0;
0a0bf5db 630 int peers_pinged = 0;
a8c926ff 631 int parent_timeout = 0, parent_exprep = 0;
632 int sibling_timeout = 0, sibling_exprep = 0;
1bf2cd49 633 int mcast_timeout = 0, mcast_exprep = 0;
090089c4 634
40a1495e 635 if (Config.peers == NULL)
62e76326 636 return 0;
637
9fb13bb6 638 assert(entry->swap_status == SWAPOUT_NONE);
62e76326 639
b6c0e933 640 mem->start_ping = current_time;
62e76326 641
b4e7f82d 642 mem->ping_reply_callback = callback;
62e76326 643
b6c0e933 644 mem->ircb_data = callback_data;
62e76326 645
332dafa2 646 reqnum = icpSetCacheKey((const cache_key *)entry->key);
62e76326 647
40a1495e 648 for (i = 0, p = first_ping; i++ < Config.npeers; p = p->next) {
62e76326 649 if (p == NULL)
650 p = Config.peers;
651
bf8fe701 652 debugs(15, 5, "neighborsUdpPing: Peer " << p->host);
62e76326 653
654 if (!peerWouldBePinged(p, request))
655 continue; /* next peer */
656
657 peers_pinged++;
658
bf8fe701 659 debugs(15, 4, "neighborsUdpPing: pinging peer " << p->host << " for '" << url << "'");
62e76326 660
bf8fe701 661 debugs(15, 3, "neighborsUdpPing: key = '" << entry->getMD5Text() << "'");
62e76326 662
bf8fe701 663 debugs(15, 3, "neighborsUdpPing: reqnum = " << reqnum);
090089c4 664
dc9d133b 665#if USE_HTCP
4f4fa815 666 if (p->options.htcp && !p->options.htcp_only_clr) {
bebf08ff
AJ
667 if (Config.Port.htcp <= 0) {
668 debugs(15, DBG_CRITICAL, "HTCP is disabled! Cannot send HTCP request to peer.");
669 continue;
670 }
671
bf8fe701 672 debugs(15, 3, "neighborsUdpPing: sending HTCP query");
bebf08ff 673 if (htcpQuery(entry, request, p) <= 0) continue; // unable to send.
62e76326 674 } else
dc9d133b 675#endif
bebf08ff
AJ
676 {
677 if (Config.Port.icp <= 0 || theOutIcpConnection <= 0) {
678 debugs(15, DBG_CRITICAL, "ICP is disabled! Cannot send ICP request to peer.");
679 continue;
62e76326 680 } else {
62e76326 681
bebf08ff
AJ
682 if (p->type == PEER_MULTICAST)
683 mcastSetTtl(theOutIcpConnection, p->mcast.ttl);
684
685 if (p->icp.port == echo_port) {
686 debugs(15, 4, "neighborsUdpPing: Looks like a dumb cache, send DECHO ping");
687 echo_hdr.reqnum = reqnum;
688 query = _icp_common_t::createMessage(ICP_DECHO, 0, url, reqnum, 0);
689 icpUdpSend(theOutIcpConnection,p->in_addr,query,LOG_ICP_QUERY,0);
690 } else {
691 flags = 0;
62e76326 692
bebf08ff
AJ
693 if (Config.onoff.query_icmp)
694 if (p->icp.version == ICP_VERSION_2)
695 flags |= ICP_FLAG_SRC_RTT;
62e76326 696
bebf08ff
AJ
697 query = _icp_common_t::createMessage(ICP_QUERY, flags, url, reqnum, 0);
698
699 icpUdpSend(theOutIcpConnection, p->in_addr, query, LOG_ICP_QUERY, 0);
700 }
62e76326 701 }
bebf08ff 702 }
62e76326 703
704 queries_sent++;
705
706 p->stats.pings_sent++;
707
708 if (p->type == PEER_MULTICAST) {
1bf2cd49 709 mcast_exprep += p->mcast.n_replies_expected;
710 mcast_timeout += (p->stats.rtt * p->mcast.n_replies_expected);
62e76326 711 } else if (neighborUp(p)) {
712 /* its alive, expect a reply from it */
713
714 if (neighborType(p, request) == PEER_PARENT) {
715 parent_exprep++;
716 parent_timeout += p->stats.rtt;
717 } else {
718 sibling_exprep++;
719 sibling_timeout += p->stats.rtt;
720 }
721 } else {
722 /* Neighbor is dead; ping it anyway, but don't expect a reply */
723 /* log it once at the threshold */
724
725 if (p->stats.logged_state == PEER_ALIVE) {
bf8fe701 726 debugs(15, 1, "Detected DEAD " << neighborTypeStr(p) << ": " << p->name);
62e76326 727 p->stats.logged_state = PEER_DEAD;
728 }
729 }
730
731 p->stats.last_query = squid_curtime;
732
67c8308c 733 /*
734 * keep probe_start == 0 for a multicast peer,
735 * so neighborUp() never says this peer is dead.
736 */
737
738 if ((p->type != PEER_MULTICAST) && (p->stats.probe_start == 0))
62e76326 739 p->stats.probe_start = squid_curtime;
090089c4 740 }
62e76326 741
40a1495e 742 if ((first_ping = first_ping->next) == NULL)
62e76326 743 first_ping = Config.peers;
090089c4 744
a8c926ff 745 /*
746 * How many replies to expect?
747 */
1bf2cd49 748 *exprep = parent_exprep + sibling_exprep + mcast_exprep;
a8c926ff 749
52040193 750 /*
465dc415 751 * If there is a configured timeout, use it
52040193 752 */
465dc415 753 if (Config.Timeout.icp_query)
62e76326 754 *timeout = Config.Timeout.icp_query;
28993292 755 else {
62e76326 756 if (*exprep > 0) {
757 if (parent_exprep)
758 *timeout = 2 * parent_timeout / parent_exprep;
1bf2cd49 759 else if (mcast_exprep)
760 *timeout = 2 * mcast_timeout / mcast_exprep;
62e76326 761 else
762 *timeout = 2 * sibling_timeout / sibling_exprep;
763 } else
764 *timeout = 2000; /* 2 seconds */
765
766 if (Config.Timeout.icp_query_max)
767 if (*timeout > Config.Timeout.icp_query_max)
768 *timeout = Config.Timeout.icp_query_max;
769
770 if (*timeout < Config.Timeout.icp_query_min)
771 *timeout = Config.Timeout.icp_query_min;
28993292 772 }
62e76326 773
0a0bf5db 774 return peers_pinged;
090089c4 775}
776
26b164ac 777/* lookup the digest of a given peer */
778lookup_t
190154cf 779peerDigestLookup(peer * p, HttpRequest * request)
26b164ac 780{
6cfa8966 781#if USE_CACHE_DIGESTS
f66a9ef4 782 const cache_key *key = request ? storeKeyPublicByRequest(request) : NULL;
26b164ac 783 assert(p);
0c511722 784 assert(request);
bf8fe701 785 debugs(15, 5, "peerDigestLookup: peer " << p->host);
4b4cd312 786 /* does the peeer have a valid digest? */
62e76326 787
e13ee7ad 788 if (!p->digest) {
bf8fe701 789 debugs(15, 5, "peerDigestLookup: gone!");
62e76326 790 return LOOKUP_NONE;
6755df2e 791 } else if (!peerHTTPOkay(p, request)) {
bf8fe701 792 debugs(15, 5, "peerDigestLookup: !peerHTTPOkay");
6755df2e 793 return LOOKUP_NONE;
e13ee7ad 794 } else if (!p->digest->flags.needed) {
bf8fe701 795 debugs(15, 5, "peerDigestLookup: note need");
62e76326 796 peerDigestNeeded(p->digest);
797 return LOOKUP_NONE;
4ed0e075 798 } else if (!p->digest->flags.usable) {
bf8fe701 799 debugs(15, 5, "peerDigestLookup: !ready && " << (p->digest->flags.requested ? "" : "!") << "requested");
62e76326 800 return LOOKUP_NONE;
26b164ac 801 }
62e76326 802
bf8fe701 803 debugs(15, 5, "peerDigestLookup: OK to lookup peer " << p->host);
e13ee7ad 804 assert(p->digest->cd);
26b164ac 805 /* does digest predict a hit? */
62e76326 806
e13ee7ad 807 if (!cacheDigestTest(p->digest->cd, key))
62e76326 808 return LOOKUP_MISS;
809
bf8fe701 810 debugs(15, 5, "peerDigestLookup: peer " << p->host << " says HIT!");
62e76326 811
26b164ac 812 return LOOKUP_HIT;
62e76326 813
26b164ac 814#endif
62e76326 815
26b164ac 816 return LOOKUP_NONE;
817}
818
819/* select best peer based on cache digests */
a54d3f8e 820peer *
190154cf 821neighborsDigestSelect(HttpRequest * request)
a54d3f8e 822{
823 peer *best_p = NULL;
6cfa8966 824#if USE_CACHE_DIGESTS
62e76326 825
a54d3f8e 826 const cache_key *key;
827 int best_rtt = 0;
828 int choice_count = 0;
829 int ichoice_count = 0;
830 peer *p;
831 int p_rtt;
832 int i;
62e76326 833
03058802 834 if (!request->flags.hierarchical)
62e76326 835 return NULL;
836
f66a9ef4 837 key = storeKeyPublicByRequest(request);
62e76326 838
a54d3f8e 839 for (i = 0, p = first_ping; i++ < Config.npeers; p = p->next) {
62e76326 840 lookup_t lookup;
841
842 if (!p)
843 p = Config.peers;
844
845 if (i == 1)
846 first_ping = p;
847
848 lookup = peerDigestLookup(p, request);
849
850 if (lookup == LOOKUP_NONE)
851 continue;
852
853 choice_count++;
854
855 if (lookup == LOOKUP_MISS)
856 continue;
857
858 p_rtt = netdbHostRtt(p->host);
859
bf8fe701 860 debugs(15, 5, "neighborsDigestSelect: peer " << p->host << " rtt: " << p_rtt);
62e76326 861
862 /* is this peer better than others in terms of rtt ? */
863 if (!best_p || (p_rtt && p_rtt < best_rtt)) {
864 best_p = p;
865 best_rtt = p_rtt;
866
867 if (p_rtt) /* informative choice (aka educated guess) */
868 ichoice_count++;
869
bf8fe701 870 debugs(15, 4, "neighborsDigestSelect: peer " << p->host << " leads with rtt " << best_rtt);
62e76326 871 }
a54d3f8e 872 }
62e76326 873
bf8fe701 874 debugs(15, 4, "neighborsDigestSelect: choices: " << choice_count << " (" << ichoice_count << ")");
26b164ac 875 peerNoteDigestLookup(request, best_p,
62e76326 876 best_p ? LOOKUP_HIT : (choice_count ? LOOKUP_MISS : LOOKUP_NONE));
a54d3f8e 877 request->hier.n_choices = choice_count;
878 request->hier.n_ichoices = ichoice_count;
879#endif
62e76326 880
a54d3f8e 881 return best_p;
882}
883
26b164ac 884void
190154cf 885peerNoteDigestLookup(HttpRequest * request, peer * p, lookup_t lookup)
26b164ac 886{
6cfa8966 887#if USE_CACHE_DIGESTS
62e76326 888
26b164ac 889 if (p)
62e76326 890 strncpy(request->hier.cd_host, p->host, sizeof(request->hier.cd_host));
26b164ac 891 else
62e76326 892 *request->hier.cd_host = '\0';
893
26b164ac 894 request->hier.cd_lookup = lookup;
62e76326 895
26ac0430
AJ
896 debugs(15, 4, "peerNoteDigestLookup: peer " <<
897 (p ? p->host : "<none>") << ", lookup: " <<
898 lookup_t_str[lookup] );
62e76326 899
26b164ac 900#endif
901}
902
d73844ca 903static void
b69f7771 904neighborAlive(peer * p, const MemObject * mem, const icp_common_t * header)
4eda6afe 905{
32a47e3e 906 peerAlive(p);
44f2f2e4 907 p->stats.pings_acked++;
62e76326 908
27cd7235 909 if ((icp_opcode) header->opcode <= ICP_END)
62e76326 910 p->icp.counts[header->opcode]++;
911
44f2f2e4 912 p->icp.version = (int) header->version;
913}
914
915static void
916neighborUpdateRtt(peer * p, MemObject * mem)
917{
d1b63fc8 918 int rtt, rtt_av_factor;
62e76326 919
d2cd6935 920 if (!mem)
62e76326 921 return;
922
44f2f2e4 923 if (!mem->start_ping.tv_sec)
62e76326 924 return;
925
44f2f2e4 926 rtt = tvSubMsec(mem->start_ping, current_time);
62e76326 927
1b6ef2d2 928 if (rtt < 1 || rtt > 10000)
62e76326 929 return;
930
d1b63fc8 931 rtt_av_factor = RTT_AV_FACTOR;
62e76326 932
d1b63fc8 933 if (p->options.weighted_roundrobin)
62e76326 934 rtt_av_factor = RTT_BACKGROUND_AV_FACTOR;
935
1b6ef2d2 936 p->stats.rtt = intAverage(p->stats.rtt, rtt,
62e76326 937 p->stats.pings_acked, rtt_av_factor);
4eda6afe 938}
090089c4 939
399cabec 940#if USE_HTCP
941static void
942neighborAliveHtcp(peer * p, const MemObject * mem, const htcpReplyData * htcp)
943{
32a47e3e 944 peerAlive(p);
f80286f6 945 p->stats.pings_acked++;
399cabec 946 p->htcp.counts[htcp->hit ? 1 : 0]++;
44f2f2e4 947 p->htcp.version = htcp->version;
399cabec 948}
62e76326 949
399cabec 950#endif
951
38792624 952static void
56b62ecc 953neighborCountIgnored(peer * p)
a7e59001 954{
b69f7771 955 if (p == NULL)
62e76326 956 return;
957
b69f7771 958 p->stats.ignored_replies++;
62e76326 959
c7a3724d 960 NLateReplies++;
a7e59001 961}
962
e102ebda 963static peer *non_peers = NULL;
964
965static void
ad61a2b4 966neighborIgnoreNonPeer(const IpAddress &from, icp_opcode opcode)
e102ebda 967{
968 peer *np;
62e76326 969
26ac0430 970 for (np = non_peers; np; np = np->next) {
cc192b50 971 if (np->in_addr != from)
62e76326 972 continue;
973
cc192b50 974 if (np->in_addr.GetPort() != from.GetPort())
62e76326 975 continue;
976
977 break;
e102ebda 978 }
62e76326 979
26ac0430 980 if (np == NULL) {
62e76326 981 np = (peer *)xcalloc(1, sizeof(peer));
cc192b50 982 np->in_addr = from;
983 np->icp.port = from.GetPort();
62e76326 984 np->type = PEER_NONE;
cc192b50 985 np->host = new char[MAX_IPSTRLEN];
986 from.NtoA(np->host,MAX_IPSTRLEN);
62e76326 987 np->next = non_peers;
988 non_peers = np;
e102ebda 989 }
62e76326 990
399cabec 991 np->icp.counts[opcode]++;
62e76326 992
e4cc2fdf 993 if (isPowTen(++np->stats.ignored_replies))
bf8fe701 994 debugs(15, 1, "WARNING: Ignored " << np->stats.ignored_replies << " replies from non-peer " << np->host);
e102ebda 995}
996
429fdbec 997/* ignoreMulticastReply
26ac0430 998 *
d6827718 999 * * We want to ignore replies from multicast peers if the
1000 * * cache_host_domain rules would normally prevent the peer
1001 * * from being used
429fdbec 1002 */
1003static int
b69f7771 1004ignoreMulticastReply(peer * p, MemObject * mem)
429fdbec 1005{
b69f7771 1006 if (p == NULL)
62e76326 1007 return 0;
1008
cd196bc8 1009 if (!p->options.mcast_responder)
62e76326 1010 return 0;
1011
b69f7771 1012 if (peerHTTPOkay(p, mem->request))
62e76326 1013 return 0;
1014
429fdbec 1015 return 1;
1016}
1017
1018/* I should attach these records to the entry. We take the first
1019 * hit we get our wait until everyone misses. The timeout handler
1020 * call needs to nip this shopping list or call one of the misses.
26ac0430 1021 *
429fdbec 1022 * If a hit process is already started, then sobeit
1023 */
b8d8561b 1024void
62e76326 1025
ad61a2b4 1026neighborsUdpAck(const cache_key * key, icp_common_t * header, const IpAddress &from)
090089c4 1027{
b69f7771 1028 peer *p = NULL;
5ad33356 1029 StoreEntry *entry;
1030 MemObject *mem = NULL;
b6c0e933 1031 peer_t ntype = PEER_NONE;
5e5126cc 1032 char *opcode_d;
a7e59001 1033 icp_opcode opcode = (icp_opcode) header->opcode;
090089c4 1034
4a7a3d56 1035 debugs(15, 6, "neighborsUdpAck: opcode " << opcode << " '" << storeKeyText(key) << "'");
62e76326 1036
c8f4eac4 1037 if (NULL != (entry = Store::Root().get(key)))
62e76326 1038 mem = entry->mem_obj;
1039
b69f7771 1040 if ((p = whichPeer(from)))
62e76326 1041 neighborAlive(p, mem, header);
1042
27cd7235 1043 if (opcode > ICP_END)
62e76326 1044 return;
1045
27cd7235 1046 opcode_d = icp_opcode_str[opcode];
62e76326 1047
41587298 1048 if (p)
62e76326 1049 neighborUpdateRtt(p, mem);
1050
5ad33356 1051 /* Does the entry exist? */
26ac0430 1052 if (NULL == entry) {
bf8fe701 1053 debugs(12, 3, "neighborsUdpAck: Cache key '" << storeKeyText(key) << "' not found");
62e76326 1054 neighborCountIgnored(p);
1055 return;
5ad33356 1056 }
62e76326 1057
2d1c6a4f 1058 /* check if someone is already fetching it */
26ac0430 1059 if (EBIT_TEST(entry->flags, ENTRY_DISPATCHED)) {
bf8fe701 1060 debugs(15, 3, "neighborsUdpAck: '" << storeKeyText(key) << "' already being fetched.");
62e76326 1061 neighborCountIgnored(p);
1062 return;
d2af9477 1063 }
62e76326 1064
26ac0430 1065 if (mem == NULL) {
bf8fe701 1066 debugs(15, 2, "Ignoring " << opcode_d << " for missing mem_obj: " << storeKeyText(key));
62e76326 1067 neighborCountIgnored(p);
1068 return;
8de2f7ad 1069 }
62e76326 1070
26ac0430 1071 if (entry->ping_status != PING_WAITING) {
bf8fe701 1072 debugs(15, 2, "neighborsUdpAck: Late " << opcode_d << " for " << storeKeyText(key));
62e76326 1073 neighborCountIgnored(p);
1074 return;
8de2f7ad 1075 }
62e76326 1076
26ac0430 1077 if (entry->lock_count == 0) {
bf8fe701 1078 debugs(12, 1, "neighborsUdpAck: '" << storeKeyText(key) << "' has no locks");
62e76326 1079 neighborCountIgnored(p);
1080 return;
090089c4 1081 }
62e76326 1082
bf8fe701 1083 debugs(15, 3, "neighborsUdpAck: " << opcode_d << " for '" << storeKeyText(key) << "' from " << (p ? p->host : "source") << " ");
62e76326 1084
26ac0430 1085 if (p) {
62e76326 1086 ntype = neighborType(p, mem->request);
44f2f2e4 1087 }
62e76326 1088
26ac0430 1089 if (ignoreMulticastReply(p, mem)) {
62e76326 1090 neighborCountIgnored(p);
26ac0430 1091 } else if (opcode == ICP_MISS) {
62e76326 1092 if (p == NULL) {
1093 neighborIgnoreNonPeer(from, opcode);
1094 } else {
1095 mem->ping_reply_callback(p, ntype, PROTO_ICP, header, mem->ircb_data);
1096 }
26ac0430 1097 } else if (opcode == ICP_HIT) {
62e76326 1098 if (p == NULL) {
1099 neighborIgnoreNonPeer(from, opcode);
1100 } else {
1101 header->opcode = ICP_HIT;
1102 mem->ping_reply_callback(p, ntype, PROTO_ICP, header, mem->ircb_data);
1103 }
26ac0430 1104 } else if (opcode == ICP_DECHO) {
62e76326 1105 if (p == NULL) {
1106 neighborIgnoreNonPeer(from, opcode);
1107 } else if (ntype == PEER_SIBLING) {
1108 debug_trap("neighborsUdpAck: Found non-ICP cache as SIBLING\n");
1109 debug_trap("neighborsUdpAck: non-ICP neighbors must be a PARENT\n");
1110 } else {
1111 mem->ping_reply_callback(p, ntype, PROTO_ICP, header, mem->ircb_data);
1112 }
26ac0430 1113 } else if (opcode == ICP_SECHO) {
62e76326 1114 if (p) {
bf8fe701 1115 debugs(15, 1, "Ignoring SECHO from neighbor " << p->host);
62e76326 1116 neighborCountIgnored(p);
62e76326 1117 } else {
cc192b50 1118 debugs(15, 1, "Unsolicited SECHO from " << from);
62e76326 1119 }
26ac0430 1120 } else if (opcode == ICP_DENIED) {
62e76326 1121 if (p == NULL) {
1122 neighborIgnoreNonPeer(from, opcode);
1123 } else if (p->stats.pings_acked > 100) {
1124 if (100 * p->icp.counts[ICP_DENIED] / p->stats.pings_acked > 95) {
bf8fe701 1125 debugs(15, 0, "95%% of replies from '" << p->host << "' are UDP_DENIED");
1126 debugs(15, 0, "Disabling '" << p->host << "', please check your configuration.");
62e76326 1127 neighborRemove(p);
1128 p = NULL;
1129 } else {
1130 neighborCountIgnored(p);
1131 }
1132 }
26ac0430 1133 } else if (opcode == ICP_MISS_NOFETCH) {
62e76326 1134 mem->ping_reply_callback(p, ntype, PROTO_ICP, header, mem->ircb_data);
26ac0430 1135 } else {
bf8fe701 1136 debugs(15, 0, "neighborsUdpAck: Unexpected ICP reply: " << opcode_d);
d2af9477 1137 }
090089c4 1138}
1139
deb79f06 1140peer *
40a1495e 1141peerFindByName(const char *name)
98ffb7e4 1142{
b69f7771 1143 peer *p = NULL;
62e76326 1144
40a1495e 1145 for (p = Config.peers; p; p = p->next) {
62e76326 1146 if (!strcasecmp(name, p->name))
1147 break;
98ffb7e4 1148 }
62e76326 1149
b69f7771 1150 return p;
98ffb7e4 1151}
b012353a 1152
db1cd23c 1153peer *
1154peerFindByNameAndPort(const char *name, unsigned short port)
1155{
1156 peer *p = NULL;
62e76326 1157
db1cd23c 1158 for (p = Config.peers; p; p = p->next) {
62e76326 1159 if (strcasecmp(name, p->name))
1160 continue;
1161
1162 if (port != p->http_port)
1163 continue;
1164
1165 break;
db1cd23c 1166 }
62e76326 1167
db1cd23c 1168 return p;
1169}
1170
5269d0bd 1171int
b69f7771 1172neighborUp(const peer * p)
5269d0bd 1173{
eb406bb7 1174 if (!p->tcp_up) {
cc192b50 1175 if (!peerProbeConnect((peer *) p)) {
1176 debugs(15, 8, "neighborUp: DOWN (probed): " << p->host << " (" << p->in_addr << ")");
4ed0e075 1177 return 0;
cc192b50 1178 }
eb406bb7 1179 }
62e76326 1180
64b8103b 1181 /*
1182 * The peer can not be UP if we don't have any IP addresses
26ac0430 1183 * for it.
64b8103b 1184 */
cc192b50 1185 if (0 == p->n_addresses) {
1186 debugs(15, 8, "neighborUp: DOWN (no-ip): " << p->host << " (" << p->in_addr << ")");
62e76326 1187 return 0;
cc192b50 1188 }
62e76326 1189
cc192b50 1190 if (p->options.no_query) {
1191 debugs(15, 8, "neighborUp: UP (no-query): " << p->host << " (" << p->in_addr << ")");
67c8308c 1192 return 1;
cc192b50 1193 }
67c8308c 1194
1195 if (p->stats.probe_start != 0 &&
cc192b50 1196 squid_curtime - p->stats.probe_start > Config.Timeout.deadPeer) {
1197 debugs(15, 8, "neighborUp: DOWN (dead): " << p->host << " (" << p->in_addr << ")");
67c8308c 1198 return 0;
cc192b50 1199 }
67c8308c 1200
cc192b50 1201 debugs(15, 8, "neighborUp: UP: " << p->host << " (" << p->in_addr << ")");
03b82057 1202 return 1;
5269d0bd 1203}
1204
e6e3b09b 1205void
28c60158 1206peerDestroy(void *data)
e6e3b09b 1207{
e6ccf245 1208 peer *p = (peer *)data;
62e76326 1209
ee4a1f5d 1210 struct _domain_ping *l = NULL;
62e76326 1211
ee4a1f5d 1212 struct _domain_ping *nl = NULL;
62e76326 1213
b69f7771 1214 if (p == NULL)
62e76326 1215 return;
1216
b6a2f15e 1217 for (l = p->peer_domain; l; l = nl) {
62e76326 1218 nl = l->next;
1219 safe_free(l->domain);
1220 safe_free(l);
ee4a1f5d 1221 }
62e76326 1222
b69f7771 1223 safe_free(p->host);
be753325 1224 safe_free(p->name);
1225 safe_free(p->domain);
e13ee7ad 1226#if USE_CACHE_DIGESTS
62e76326 1227
fa80a8ef 1228 cbdataReferenceDone(p->digest);
e13ee7ad 1229#endif
e6e3b09b 1230}
c7a3724d 1231
e13ee7ad 1232void
e16d4250 1233peerNoteDigestGone(peer * p)
e13ee7ad 1234{
1235#if USE_CACHE_DIGESTS
fa80a8ef 1236 cbdataReferenceDone(p->digest);
e13ee7ad 1237#endif
1238}
1239
dd4bd44e 1240static void
03a1ee42 1241peerDNSConfigure(const ipcache_addrs * ia, void *data)
dd4bd44e 1242{
e6ccf245 1243 peer *p = (peer *)data;
62e76326 1244
dd4bd44e 1245 int j;
62e76326 1246
b69f7771 1247 if (p->n_addresses == 0) {
bf8fe701 1248 debugs(15, 1, "Configuring " << neighborTypeStr(p) << " " << p->host << "/" << p->http_port << "/" << p->icp.port);
62e76326 1249
1250 if (p->type == PEER_MULTICAST)
bf8fe701 1251 debugs(15, 1, " Multicast TTL = " << p->mcast.ttl);
b69f7771 1252 }
62e76326 1253
b69f7771 1254 p->n_addresses = 0;
62e76326 1255
dd4bd44e 1256 if (ia == NULL) {
bf8fe701 1257 debugs(0, 0, "WARNING: DNS lookup for '" << p->host << "' failed!");
62e76326 1258 return;
dd4bd44e 1259 }
62e76326 1260
c04fe656 1261 if ((int) ia->count < 1) {
bf8fe701 1262 debugs(0, 0, "WARNING: No IP address found for '" << p->host << "'!");
62e76326 1263 return;
dd4bd44e 1264 }
62e76326 1265
dc3a5177 1266 p->tcp_up = PEER_TCP_MAGIC_COUNT;
1267
c04fe656 1268 for (j = 0; j < (int) ia->count && j < PEER_MAX_ADDRESSES; j++) {
62e76326 1269 p->addresses[j] = ia->in_addrs[j];
cc192b50 1270 debugs(15, 2, "--> IP address #" << j << ": " << p->addresses[j]);
62e76326 1271 p->n_addresses++;
dd4bd44e 1272 }
62e76326 1273
cc192b50 1274 p->in_addr.SetEmpty();
1275 p->in_addr = p->addresses[0];
1276 p->in_addr.SetPort(p->icp.port);
62e76326 1277
b69f7771 1278 if (p->type == PEER_MULTICAST)
62e76326 1279 peerCountMcastPeersSchedule(p, 10);
1280
9b5c4a9a 1281#if USE_ICMP
1a827bc0 1282 if (p->type != PEER_MULTICAST)
62e76326 1283 if (!p->options.no_netdb_exchange)
1284 eventAddIsh("netdbExchangeStart", netdbExchangeStart, p, 30.0, 1);
9b5c4a9a
AJ
1285#endif
1286
dd4bd44e 1287}
1288
1289static void
51242273 1290peerRefreshDNS(void *data)
dd4bd44e 1291{
b69f7771 1292 peer *p = NULL;
62e76326 1293
46ca5fc6 1294 if (eventFind(peerRefreshDNS, NULL))
62e76326 1295 eventDelete(peerRefreshDNS, NULL);
1296
51242273 1297 if (!data && 0 == stat5minClientRequests()) {
62e76326 1298 /* no recent client traffic, wait a bit */
1299 eventAddIsh("peerRefreshDNS", peerRefreshDNS, NULL, 180.0, 1);
1300 return;
dd4bd44e 1301 }
62e76326 1302
1f3c4622 1303 for (p = Config.peers; p; p = p->next)
62e76326 1304 ipcache_nbgethostbyname(p->host, peerDNSConfigure, p);
1305
dd4bd44e 1306 /* Reconfigure the peers every hour */
52040193 1307 eventAddIsh("peerRefreshDNS", peerRefreshDNS, NULL, 3600.0, 1);
dd4bd44e 1308}
e924600d 1309
4ed0e075 1310static void
1311peerConnectFailedSilent(peer * p)
eb406bb7 1312{
1313 p->stats.last_connect_failure = squid_curtime;
62e76326 1314
eb406bb7 1315 if (!p->tcp_up) {
bf8fe701 1316 debugs(15, 2, "TCP connection to " << p->host << "/" << p->http_port <<
1317 " dead");
62e76326 1318 return;
eb406bb7 1319 }
62e76326 1320
eb406bb7 1321 p->tcp_up--;
62e76326 1322
eb406bb7 1323 if (!p->tcp_up) {
bf8fe701 1324 debugs(15, 1, "Detected DEAD " << neighborTypeStr(p) << ": " << p->name);
62e76326 1325 p->stats.logged_state = PEER_DEAD;
eb406bb7 1326 }
1327}
1328
4ed0e075 1329void
1330peerConnectFailed(peer *p)
1331{
bf8fe701 1332 debugs(15, 1, "TCP connection to " << p->host << "/" << p->http_port << " failed");
4ed0e075 1333 peerConnectFailedSilent(p);
1334}
1335
eb406bb7 1336void
a4b8110e 1337peerConnectSucceded(peer * p)
eb406bb7 1338{
1339 if (!p->tcp_up) {
bf8fe701 1340 debugs(15, 2, "TCP connection to " << p->host << "/" << p->http_port << " succeded");
32a47e3e
AJ
1341 p->tcp_up = PEER_TCP_MAGIC_COUNT; // NP: so peerAlive(p) works properly.
1342 peerAlive(p);
26ac0430
AJ
1343 if (!p->n_addresses)
1344 ipcache_nbgethostbyname(p->host, peerDNSConfigure, p);
1345 } else
32a47e3e 1346 p->tcp_up = PEER_TCP_MAGIC_COUNT;
eb406bb7 1347}
1348
46574433
AR
1349/// called by Comm when test_fd is closed while connect is in progress
1350static void
1351peerProbeClosed(int fd, void *data)
1352{
1353 peer *p = (peer*)data;
1354 p->test_fd = -1;
1355 // it is a failure because we failed to connect
1356 peerConnectFailedSilent(p);
1357}
1358
e924600d 1359static void
4ed0e075 1360peerProbeConnectTimeout(int fd, void *data)
1361{
1362 peer * p = (peer *)data;
46574433 1363 comm_remove_close_handler(fd, &peerProbeClosed, p);
4ed0e075 1364 comm_close(fd);
1365 p->test_fd = -1;
1366 peerConnectFailedSilent(p);
1367}
1368
1369/*
26ac0430 1370* peerProbeConnect will be called on dead peers by neighborUp
4ed0e075 1371*/
1372static int
a4b8110e 1373peerProbeConnect(peer * p)
e924600d 1374{
e924600d 1375 int fd;
4ed0e075 1376 time_t ctimeout = p->connect_timeout > 0 ? p->connect_timeout
1377 : Config.Timeout.peer_connect;
1378 int ret = squid_curtime - p->stats.last_connect_failure > ctimeout * 10;
62e76326 1379
eb406bb7 1380 if (p->test_fd != -1)
4ed0e075 1381 return ret;/* probe already running */
62e76326 1382
4ed0e075 1383 if (squid_curtime - p->stats.last_connect_probe == 0)
1384 return ret;/* don't probe to often */
62e76326 1385
ad61a2b4 1386 IpAddress temp(getOutgoingAddr(NULL,p));
cc192b50 1387
1388 fd = comm_open(SOCK_STREAM, IPPROTO_TCP, temp, COMM_NONBLOCKING, p->host);
62e76326 1389
e924600d 1390 if (fd < 0)
4ed0e075 1391 return ret;
1392
46574433 1393 comm_add_close_handler(fd, &peerProbeClosed, p);
4ed0e075 1394 commSetTimeout(fd, ctimeout, peerProbeConnectTimeout, p);
62e76326 1395
03a1ee42 1396 p->test_fd = fd;
62e76326 1397
eb406bb7 1398 p->stats.last_connect_probe = squid_curtime;
62e76326 1399
03a1ee42 1400 commConnectStart(p->test_fd,
62e76326 1401 p->host,
1402 p->http_port,
1403 peerProbeConnectDone,
1404 p);
4ed0e075 1405
1406 return ret;
e924600d 1407}
1408
1409static void
f3400a93 1410peerProbeConnectDone(int fd, comm_err_t status, int xerrno, void *data)
e924600d 1411{
e6ccf245 1412 peer *p = (peer*)data;
62e76326 1413
98829f69 1414 if (status == COMM_OK) {
62e76326 1415 peerConnectSucceded(p);
e924600d 1416 } else {
4ed0e075 1417 peerConnectFailedSilent(p);
e924600d 1418 }
62e76326 1419
46574433 1420 comm_remove_close_handler(fd, &peerProbeClosed, p);
e924600d 1421 comm_close(fd);
eb406bb7 1422 p->test_fd = -1;
e924600d 1423 return;
1424}
1425
429fdbec 1426static void
1427peerCountMcastPeersSchedule(peer * p, time_t when)
1428{
b515fc11 1429 if (p->mcast.flags.count_event_pending)
62e76326 1430 return;
1431
429fdbec 1432 eventAdd("peerCountMcastPeersStart",
62e76326 1433 peerCountMcastPeersStart,
1434 p,
1435 (double) when, 1);
1436
b515fc11 1437 p->mcast.flags.count_event_pending = 1;
429fdbec 1438}
1439
1440static void
1441peerCountMcastPeersStart(void *data)
1442{
e6ccf245 1443 peer *p = (peer *)data;
28c60158 1444 ps_state *psstate;
429fdbec 1445 StoreEntry *fake;
1446 MemObject *mem;
1447 icp_common_t *query;
007b8be4 1448 int reqnum;
429fdbec 1449 LOCAL_ARRAY(char, url, MAX_URL);
ce66013b 1450 assert(p->type == PEER_MULTICAST);
b515fc11 1451 p->mcast.flags.count_event_pending = 0;
cc192b50 1452 snprintf(url, MAX_URL, "http://");
1453 p->in_addr.ToURL(url+7, MAX_URL -8 );
1454 strcat(url, "/");
e429f975 1455 fake = storeCreateEntry(url, url, request_flags(), METHOD_GET);
c21ad0f5 1456 HttpRequest *req = HttpRequest::CreateFromUrl(url);
b24880fe 1457 psstate = new ps_state;
6dd9f4bd 1458 psstate->request = HTTPMSGLOCK(req);
429fdbec 1459 psstate->entry = fake;
1460 psstate->callback = NULL;
99117d82 1461 psstate->callback_data = cbdataReference(p);
b4e7f82d 1462 psstate->ping.start = current_time;
429fdbec 1463 mem = fake->mem_obj;
6dd9f4bd 1464 mem->request = HTTPMSGLOCK(psstate->request);
429fdbec 1465 mem->start_ping = current_time;
b4e7f82d 1466 mem->ping_reply_callback = peerCountHandleIcpReply;
429fdbec 1467 mem->ircb_data = psstate;
03a1ee42 1468 mcastSetTtl(theOutIcpConnection, p->mcast.ttl);
007b8be4 1469 p->mcast.id = mem->id;
332dafa2 1470 reqnum = icpSetCacheKey((const cache_key *)fake->key);
e6ccf245 1471 query = _icp_common_t::createMessage(ICP_QUERY, 0, url, reqnum, 0);
429fdbec 1472 icpUdpSend(theOutIcpConnection,
cc192b50 1473 p->in_addr,
62e76326 1474 query,
1475 LOG_ICP_QUERY,
1476 0);
429fdbec 1477 fake->ping_status = PING_WAITING;
1478 eventAdd("peerCountMcastPeersDone",
62e76326 1479 peerCountMcastPeersDone,
1480 psstate,
99117d82 1481 Config.Timeout.mcast_icp_query / 1000.0, 1);
b515fc11 1482 p->mcast.flags.counting = 1;
429fdbec 1483 peerCountMcastPeersSchedule(p, MCAST_COUNT_RATE);
1484}
1485
1486static void
1487peerCountMcastPeersDone(void *data)
1488{
e6ccf245 1489 ps_state *psstate = (ps_state *)data;
429fdbec 1490 StoreEntry *fake = psstate->entry;
99117d82 1491
1492 if (cbdataReferenceValid(psstate->callback_data)) {
1493 peer *p = (peer *)psstate->callback_data;
1494 p->mcast.flags.counting = 0;
1495 p->mcast.avg_n_members = doubleAverage(p->mcast.avg_n_members,
1496 (double) psstate->ping.n_recv,
1497 ++p->mcast.n_times_counted,
1498 10);
bf8fe701 1499 debugs(15, 1, "Group " << p->host << ": " << psstate->ping.n_recv <<
1500 " replies, "<< std::setw(4)<< std::setprecision(2) <<
1501 p->mcast.avg_n_members <<" average, RTT " << p->stats.rtt);
99117d82 1502 p->mcast.n_replies_expected = (int) p->mcast.avg_n_members;
1503 }
1504
1505 cbdataReferenceDone(psstate->callback_data);
1506
b7fe0ab0 1507 EBIT_SET(fake->flags, ENTRY_ABORTED);
6dd9f4bd 1508 HTTPMSGUNLOCK(fake->mem_obj->request);
d88e3c49 1509 fake->releaseRequest();
97b5e68f 1510 fake->unlock();
6dd9f4bd 1511 HTTPMSGUNLOCK(psstate->request);
1a827bc0 1512 cbdataFree(psstate);
429fdbec 1513}
1514
1515static void
5942e8d4 1516peerCountHandleIcpReply(peer * p, peer_t type, protocol_t proto, void *hdrnotused, void *data)
429fdbec 1517{
d1b63fc8 1518 int rtt_av_factor;
1519
e6ccf245 1520 ps_state *psstate = (ps_state *)data;
1a827bc0 1521 StoreEntry *fake = psstate->entry;
1522 MemObject *mem = fake->mem_obj;
1523 int rtt = tvSubMsec(mem->start_ping, current_time);
86aebcda 1524 assert(proto == PROTO_ICP);
1a827bc0 1525 assert(fake);
1526 assert(mem);
b4e7f82d 1527 psstate->ping.n_recv++;
d1b63fc8 1528 rtt_av_factor = RTT_AV_FACTOR;
62e76326 1529
d1b63fc8 1530 if (p->options.weighted_roundrobin)
62e76326 1531 rtt_av_factor = RTT_BACKGROUND_AV_FACTOR;
1532
d1b63fc8 1533 p->stats.rtt = intAverage(p->stats.rtt, rtt, psstate->ping.n_recv, rtt_av_factor);
429fdbec 1534}
ed7f5615 1535
1536static void
1537neighborDumpPeers(StoreEntry * sentry)
1538{
1539 dump_peers(sentry, Config.peers);
1540}
1541
1542static void
1543neighborDumpNonPeers(StoreEntry * sentry)
1544{
1545 dump_peers(sentry, non_peers);
1546}
1547
a369131d 1548void
1549dump_peer_options(StoreEntry * sentry, peer * p)
1550{
cd196bc8 1551 if (p->options.proxy_only)
62e76326 1552 storeAppendPrintf(sentry, " proxy-only");
1553
cd196bc8 1554 if (p->options.no_query)
62e76326 1555 storeAppendPrintf(sentry, " no-query");
1556
d1b63fc8 1557 if (p->options.background_ping)
62e76326 1558 storeAppendPrintf(sentry, " background-ping");
1559
cd196bc8 1560 if (p->options.no_digest)
62e76326 1561 storeAppendPrintf(sentry, " no-digest");
1562
cd196bc8 1563 if (p->options.default_parent)
62e76326 1564 storeAppendPrintf(sentry, " default");
1565
cd196bc8 1566 if (p->options.roundrobin)
62e76326 1567 storeAppendPrintf(sentry, " round-robin");
1568
f7e1d9ce
HN
1569 if (p->options.carp)
1570 storeAppendPrintf(sentry, " carp");
1571
1572 if (p->options.userhash)
1573 storeAppendPrintf(sentry, " userhash");
1574
1575 if (p->options.userhash)
1576 storeAppendPrintf(sentry, " sourcehash");
1577
d1b63fc8 1578 if (p->options.weighted_roundrobin)
62e76326 1579 storeAppendPrintf(sentry, " weighted-round-robin");
1580
cd196bc8 1581 if (p->options.mcast_responder)
62e76326 1582 storeAppendPrintf(sentry, " multicast-responder");
1583
678a066c 1584 if (p->weight != 1)
62e76326 1585 storeAppendPrintf(sentry, " weight=%d", p->weight);
1586
cd196bc8 1587 if (p->options.closest_only)
62e76326 1588 storeAppendPrintf(sentry, " closest-only");
1589
dc9d133b 1590#if USE_HTCP
cd196bc8 1591 if (p->options.htcp)
62e76326 1592 storeAppendPrintf(sentry, " htcp");
26ac0430
AJ
1593 if (p->options.htcp_oldsquid)
1594 storeAppendPrintf(sentry, " htcp-oldsquid");
1595 if (p->options.htcp_no_clr)
1596 storeAppendPrintf(sentry, " htcp-no-clr");
1597 if (p->options.htcp_no_purge_clr)
1598 storeAppendPrintf(sentry, " htcp-no-purge-clr");
1599 if (p->options.htcp_only_clr)
1600 storeAppendPrintf(sentry, " htcp-only-clr");
dc9d133b 1601#endif
62e76326 1602
cd196bc8 1603 if (p->options.no_netdb_exchange)
62e76326 1604 storeAppendPrintf(sentry, " no-netdb-exchange");
1605
95e36d02 1606#if DELAY_POOLS
62e76326 1607
cd196bc8 1608 if (p->options.no_delay)
62e76326 1609 storeAppendPrintf(sentry, " no-delay");
1610
95e36d02 1611#endif
62e76326 1612
c68e9c6b 1613 if (p->login)
62e76326 1614 storeAppendPrintf(sentry, " login=%s", p->login);
1615
a369131d 1616 if (p->mcast.ttl > 0)
62e76326 1617 storeAppendPrintf(sentry, " ttl=%d", p->mcast.ttl);
1618
be753325 1619 if (p->connect_timeout > 0)
62e76326 1620 storeAppendPrintf(sentry, " connect-timeout=%d", (int) p->connect_timeout);
1621
be753325 1622#if USE_CACHE_DIGESTS
62e76326 1623
be753325 1624 if (p->digest_url)
62e76326 1625 storeAppendPrintf(sentry, " digest-url=%s", p->digest_url);
1626
be753325 1627#endif
62e76326 1628
be753325 1629 if (p->options.allow_miss)
62e76326 1630 storeAppendPrintf(sentry, " allow-miss");
1631
be753325 1632 if (p->max_conn > 0)
62e76326 1633 storeAppendPrintf(sentry, " max-conn=%d", p->max_conn);
1634
be753325 1635 if (p->options.originserver)
62e76326 1636 storeAppendPrintf(sentry, " originserver");
1637
be753325 1638 if (p->domain)
62e76326 1639 storeAppendPrintf(sentry, " forceddomain=%s", p->domain);
1640
26ac0430
AJ
1641 if (p->connection_auth == 0)
1642 storeAppendPrintf(sentry, " connection-auth=off");
1643 else if (p->connection_auth == 1)
1644 storeAppendPrintf(sentry, " connection-auth=on");
1645 else if (p->connection_auth == 2)
1646 storeAppendPrintf(sentry, " connection-auth=auto");
d67acb4e 1647
a369131d 1648 storeAppendPrintf(sentry, "\n");
1649}
1650
ed7f5615 1651static void
1652dump_peers(StoreEntry * sentry, peer * peers)
1653{
1654 peer *e = NULL;
cc192b50 1655 char ntoabuf[MAX_IPSTRLEN];
ed7f5615 1656 struct _domain_ping *d = NULL;
1657 icp_opcode op;
06e6d12a 1658 int i;
62e76326 1659
ed7f5615 1660 if (peers == NULL)
62e76326 1661 storeAppendPrintf(sentry, "There are no neighbors installed.\n");
1662
ed7f5615 1663 for (e = peers; e; e = e->next) {
62e76326 1664 assert(e->host != NULL);
1665 storeAppendPrintf(sentry, "\n%-11.11s: %s\n",
1666 neighborTypeStr(e),
1667 e->name);
1668 storeAppendPrintf(sentry, "Host : %s/%d/%d\n",
1669 e->host,
1670 e->http_port,
1671 e->icp.port);
1672 storeAppendPrintf(sentry, "Flags :");
1673 dump_peer_options(sentry, e);
1674
1675 for (i = 0; i < e->n_addresses; i++) {
1676 storeAppendPrintf(sentry, "Address[%d] : %s\n", i,
cc192b50 1677 e->addresses[i].NtoA(ntoabuf,MAX_IPSTRLEN) );
62e76326 1678 }
1679
1680 storeAppendPrintf(sentry, "Status : %s\n",
1681 neighborUp(e) ? "Up" : "Down");
1682 storeAppendPrintf(sentry, "FETCHES : %d\n", e->stats.fetches);
1683 storeAppendPrintf(sentry, "OPEN CONNS : %d\n", e->stats.conn_open);
1684 storeAppendPrintf(sentry, "AVG RTT : %d msec\n", e->stats.rtt);
1685
1686 if (!e->options.no_query) {
1687 storeAppendPrintf(sentry, "LAST QUERY : %8d seconds ago\n",
1688 (int) (squid_curtime - e->stats.last_query));
1689
1690 if (e->stats.last_reply > 0)
1691 storeAppendPrintf(sentry, "LAST REPLY : %8d seconds ago\n",
1692 (int) (squid_curtime - e->stats.last_reply));
1693 else
1694 storeAppendPrintf(sentry, "LAST REPLY : none received\n");
1695
1696 storeAppendPrintf(sentry, "PINGS SENT : %8d\n", e->stats.pings_sent);
1697
1698 storeAppendPrintf(sentry, "PINGS ACKED: %8d %3d%%\n",
1699 e->stats.pings_acked,
1700 percent(e->stats.pings_acked, e->stats.pings_sent));
1701 }
1702
1703 storeAppendPrintf(sentry, "IGNORED : %8d %3d%%\n",
1704 e->stats.ignored_replies,
1705 percent(e->stats.ignored_replies, e->stats.pings_acked));
1706
1707 if (!e->options.no_query) {
1708 storeAppendPrintf(sentry, "Histogram of PINGS ACKED:\n");
1994bb24 1709#if USE_HTCP
62e76326 1710
1711 if (e->options.htcp) {
1712 storeAppendPrintf(sentry, "\tMisses\t%8d %3d%%\n",
1713 e->htcp.counts[0],
1714 percent(e->htcp.counts[0], e->stats.pings_acked));
1715 storeAppendPrintf(sentry, "\tHits\t%8d %3d%%\n",
1716 e->htcp.counts[1],
1717 percent(e->htcp.counts[1], e->stats.pings_acked));
1718 } else {
1994bb24 1719#endif
62e76326 1720
1721 for (op = ICP_INVALID; op < ICP_END; ++op) {
1722 if (e->icp.counts[op] == 0)
1723 continue;
1724
1725 storeAppendPrintf(sentry, " %12.12s : %8d %3d%%\n",
1726 icp_opcode_str[op],
1727 e->icp.counts[op],
1728 percent(e->icp.counts[op], e->stats.pings_acked));
1729 }
1730
1994bb24 1731#if USE_HTCP
62e76326 1732
1733 }
1734
1994bb24 1735#endif
62e76326 1736
1737 }
1738
1739 if (e->stats.last_connect_failure) {
1740 storeAppendPrintf(sentry, "Last failed connect() at: %s\n",
1741 mkhttpdlogtime(&(e->stats.last_connect_failure)));
1742 }
1743
1744 if (e->peer_domain != NULL) {
1745 storeAppendPrintf(sentry, "DOMAIN LIST: ");
1746
1747 for (d = e->peer_domain; d; d = d->next) {
1748 storeAppendPrintf(sentry, "%s%s ",
1749 d->do_ping ? null_string : "!", d->domain);
1750 }
1751
1752 storeAppendPrintf(sentry, "\n");
1753 }
1754
1755 storeAppendPrintf(sentry, "keep-alive ratio: %d%%\n",
1756 percent(e->stats.n_keepalives_recv, e->stats.n_keepalives_sent));
ed7f5615 1757 }
1758}
86aebcda 1759
1760#if USE_HTCP
1761void
ad61a2b4 1762neighborsHtcpReply(const cache_key * key, htcpReplyData * htcp, const IpAddress &from)
86aebcda 1763{
53525d53 1764 StoreEntry *e = Store::Root().get(key);
399cabec 1765 MemObject *mem = NULL;
1766 peer *p;
1767 peer_t ntype = PEER_NONE;
26ac0430
AJ
1768 debugs(15, 6, "neighborsHtcpReply: " <<
1769 (htcp->hit ? "HIT" : "MISS") << " " <<
1770 storeKeyText(key) );
62e76326 1771
88e13392 1772 if (NULL != e)
62e76326 1773 mem = e->mem_obj;
1774
399cabec 1775 if ((p = whichPeer(from)))
62e76326 1776 neighborAliveHtcp(p, mem, htcp);
1777
399cabec 1778 /* Does the entry exist? */
26ac0430 1779 if (NULL == e) {
bf8fe701 1780 debugs(12, 3, "neighyborsHtcpReply: Cache key '" << storeKeyText(key) << "' not found");
62e76326 1781 neighborCountIgnored(p);
1782 return;
399cabec 1783 }
62e76326 1784
399cabec 1785 /* check if someone is already fetching it */
26ac0430 1786 if (EBIT_TEST(e->flags, ENTRY_DISPATCHED)) {
bf8fe701 1787 debugs(15, 3, "neighborsUdpAck: '" << storeKeyText(key) << "' already being fetched.");
62e76326 1788 neighborCountIgnored(p);
1789 return;
399cabec 1790 }
62e76326 1791
26ac0430 1792 if (mem == NULL) {
bf8fe701 1793 debugs(15, 2, "Ignoring reply for missing mem_obj: " << storeKeyText(key));
62e76326 1794 neighborCountIgnored(p);
1795 return;
399cabec 1796 }
62e76326 1797
26ac0430 1798 if (e->ping_status != PING_WAITING) {
bf8fe701 1799 debugs(15, 2, "neighborsUdpAck: Entry " << storeKeyText(key) << " is not PING_WAITING");
62e76326 1800 neighborCountIgnored(p);
1801 return;
399cabec 1802 }
62e76326 1803
26ac0430 1804 if (e->lock_count == 0) {
bf8fe701 1805 debugs(12, 1, "neighborsUdpAck: '" << storeKeyText(key) << "' has no locks");
62e76326 1806 neighborCountIgnored(p);
1807 return;
399cabec 1808 }
62e76326 1809
26ac0430 1810 if (p) {
62e76326 1811 ntype = neighborType(p, mem->request);
1812 neighborUpdateRtt(p, mem);
44f2f2e4 1813 }
62e76326 1814
26ac0430 1815 if (ignoreMulticastReply(p, mem)) {
62e76326 1816 neighborCountIgnored(p);
1817 return;
399cabec 1818 }
62e76326 1819
bf8fe701 1820 debugs(15, 3, "neighborsHtcpReply: e = " << e);
b4e7f82d 1821 mem->ping_reply_callback(p, ntype, PROTO_HTCP, htcp, mem->ircb_data);
86aebcda 1822}
62e76326 1823
1bd06eff
BR
1824/*
1825 * Send HTCP CLR messages to all peers configured to receive them.
1826 */
4f4fa815 1827void
8dceeee3 1828neighborsHtcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &method, htcp_clr_reason reason)
4f4fa815
BR
1829{
1830 peer *p;
1831 char buf[128];
1832
4f4fa815
BR
1833 for (p = Config.peers; p; p = p->next) {
1834 if (!p->options.htcp) {
1835 continue;
1836 }
1837 if (p->options.htcp_no_clr) {
1838 continue;
1839 }
1840 if (p->options.htcp_no_purge_clr && reason == HTCP_CLR_PURGE) {
1841 continue;
1842 }
1bd06eff 1843 debugs(15, 3, "neighborsHtcpClear: sending CLR to " << p->in_addr.ToURL(buf, 128));
4f4fa815
BR
1844 htcpClear(e, uri, req, method, p, reason);
1845 }
1846}
1847
86aebcda 1848#endif