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