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