]> git.ipfire.org Git - thirdparty/squid.git/blame - src/neighbors.cc
Added redirector_bypass option, written for Deere and Company
[thirdparty/squid.git] / src / neighbors.cc
CommitLineData
22f3fd98 1
30a4f2a8 2/*
03058802 3 * $Id: neighbors.cc,v 1.274 1999/05/11 18:45:46 wessels Exp $
30a4f2a8 4 *
5 * DEBUG: section 15 Neighbor Routines
6 * AUTHOR: Harvest Derived
7 *
42c04c16 8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
e25c139f 13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
019dd986 34 */
090089c4 35
44a47c6e 36#include "squid.h"
090089c4 37
429fdbec 38/* count mcast group peers every 15 minutes */
39#define MCAST_COUNT_RATE 900
40
f5b8bbc4 41static int peerAllowedToUse(const peer *, request_t *);
f5b8bbc4 42static int peerWouldBePinged(const peer *, request_t *);
43static void neighborRemove(peer *);
f5b8bbc4 44static void neighborAlive(peer *, const MemObject *, const icp_common_t *);
399cabec 45#if USE_HTCP
46static void neighborAliveHtcp(peer *, const MemObject *, const htcpReplyData *);
47#endif
56b62ecc 48static void neighborCountIgnored(peer *);
f5b8bbc4 49static void peerRefreshDNS(void *);
b69f7771 50static IPH peerDNSConfigure;
0e7b6b06 51static EVH peerCheckConnect;
b69f7771 52static IPH peerCheckConnect2;
603a02fd 53static CNCB peerCheckConnectDone;
f5b8bbc4 54static void peerCountMcastPeersDone(void *data);
55static void peerCountMcastPeersStart(void *data);
56static void peerCountMcastPeersSchedule(peer * p, time_t when);
b3264694 57static IRCB peerCountHandleIcpReply;
f5b8bbc4 58static void neighborIgnoreNonPeer(const struct sockaddr_in *, icp_opcode);
ed7f5615 59static OBJH neighborDumpPeers;
60static OBJH neighborDumpNonPeers;
61static void dump_peers(StoreEntry * sentry, peer * peers);
090089c4 62
090089c4 63static icp_common_t echo_hdr;
30a4f2a8 64static u_short echo_port;
30a4f2a8 65
c7a3724d 66static int NLateReplies = 0;
40a1495e 67static peer *first_ping = NULL;
28070024 68
c7a3724d 69char *
b69f7771 70neighborTypeStr(const peer * p)
69a71bd7 71{
e102ebda 72 if (p->type == PEER_NONE)
73 return "Non-Peer";
b69f7771 74 if (p->type == PEER_SIBLING)
69a71bd7 75 return "Sibling";
b69f7771 76 if (p->type == PEER_MULTICAST)
7b3bd12c 77 return "Multicast Group";
69a71bd7 78 return "Parent";
79}
80
090089c4 81
d9f9d78b 82peer *
0cdcddb9 83whichPeer(const struct sockaddr_in * from)
090089c4 84{
22e4fa85 85 int j;
4eda6afe 86 u_short port = ntohs(from->sin_port);
87 struct in_addr ip = from->sin_addr;
b69f7771 88 peer *p = NULL;
a3d5953d 89 debug(15, 3) ("whichPeer: from %s port %d\n", inet_ntoa(ip), port);
40a1495e 90 for (p = Config.peers; p; p = p->next) {
b69f7771 91 for (j = 0; j < p->n_addresses; j++) {
399cabec 92 if (ip.s_addr == p->addresses[j].s_addr && port == p->icp.port) {
b69f7771 93 return p;
090089c4 94 }
95 }
96 }
4eda6afe 97 return NULL;
090089c4 98}
99
701a8572 100peer_t
b69f7771 101neighborType(const peer * p, const request_t * request)
24a1003d 102{
b012353a 103 const struct _domain_type *d = NULL;
b69f7771 104 for (d = p->typelist; d; d = d->next) {
24a1003d 105 if (matchDomainName(d->domain, request->host))
deb79f06 106 if (d->type != PEER_NONE)
b012353a 107 return d->type;
24a1003d 108 }
b69f7771 109 return p->type;
24a1003d 110}
111
7b3bd12c 112/*
62fd6124 113 * peerAllowedToUse
7b3bd12c 114 *
dd4bd44e 115 * this function figures out if it is appropriate to fetch REQUEST
62fd6124 116 * from PEER.
7b3bd12c 117 */
b8d8561b 118static int
b69f7771 119peerAllowedToUse(const peer * p, request_t * request)
090089c4 120{
b012353a 121 const struct _domain_ping *d = NULL;
090089c4 122 int do_ping = 1;
f88bb09c 123 aclCheck_t checklist;
ce66013b 124 assert(request != NULL);
9689d97c 125 if (neighborType(p, request) == PEER_SIBLING) {
126 if (request->flags.nocache)
24a1003d 127 return 0;
9689d97c 128 if (request->flags.refresh)
d950cec8 129 return 0;
9689d97c 130 if (request->flags.loopdetect)
131 return 0;
132 if (request->flags.need_validation)
133 return 0;
134 }
b6a2f15e 135 if (p->peer_domain == NULL && p->access == NULL)
090089c4 136 return do_ping;
090089c4 137 do_ping = 0;
b6a2f15e 138 for (d = p->peer_domain; d; d = d->next) {
130faaed 139 if (matchDomainName(d->domain, request->host)) {
140 do_ping = d->do_ping;
141 break;
142 }
30a4f2a8 143 do_ping = !d->do_ping;
144 }
b6a2f15e 145 if (p->peer_domain && 0 == do_ping)
130faaed 146 return do_ping;
505e35db 147 if (p->access == NULL)
148 return do_ping;
8ae8bb05 149 checklist.src_addr = request->client_addr;
3c11d1f5 150 checklist.my_addr = request->my_addr;
f88bb09c 151 checklist.request = request;
505e35db 152 return aclCheckFast(p->access, &checklist);
090089c4 153}
154
62fd6124 155/* Return TRUE if it is okay to send an ICP request to this peer. */
156static int
b69f7771 157peerWouldBePinged(const peer * p, request_t * request)
62fd6124 158{
b69f7771 159 if (!peerAllowedToUse(p, request))
62fd6124 160 return 0;
cd196bc8 161 if (p->options.no_query)
62fd6124 162 return 0;
cd196bc8 163 if (p->options.mcast_responder)
62fd6124 164 return 0;
165 /* the case below seems strange, but can happen if the
166 * URL host is on the other side of a firewall */
b69f7771 167 if (p->type == PEER_SIBLING)
92695e5e 168 if (!request->flags.hierarchical)
62fd6124 169 return 0;
399cabec 170 if (p->icp.port == echo_port)
b69f7771 171 if (!neighborUp(p))
62fd6124 172 return 0;
b69f7771 173 if (p->n_addresses == 0)
dd4bd44e 174 return 0;
62fd6124 175 return 1;
176}
177
178/* Return TRUE if it is okay to send an HTTP request to this peer. */
8ff4505b 179int
b69f7771 180peerHTTPOkay(const peer * p, request_t * request)
62fd6124 181{
b69f7771 182 if (!peerAllowedToUse(p, request))
62fd6124 183 return 0;
b69f7771 184 if (!neighborUp(p))
62fd6124 185 return 0;
186 return 1;
187}
188
3c6e634f 189int
190neighborsCount(request_t * request)
090089c4 191{
b69f7771 192 peer *p = NULL;
090089c4 193 int count = 0;
40a1495e 194 for (p = Config.peers; p; p = p->next)
b69f7771 195 if (peerWouldBePinged(p, request))
3c6e634f 196 count++;
a3d5953d 197 debug(15, 3) ("neighborsCount: %d\n", count);
3c6e634f 198 return count;
199}
090089c4 200
deb79f06 201peer *
3c6e634f 202getSingleParent(request_t * request)
203{
deb79f06 204 peer *p = NULL;
b69f7771 205 peer *q = NULL;
40a1495e 206 for (q = Config.peers; q; q = q->next) {
b69f7771 207 if (!peerHTTPOkay(q, request))
caebbe00 208 continue;
b69f7771 209 if (neighborType(q, request) != PEER_PARENT)
3c6e634f 210 return NULL; /* oops, found SIBLING */
211 if (p)
212 return NULL; /* oops, found second parent */
b69f7771 213 p = q;
090089c4 214 }
cd196bc8 215 if (p != NULL && !p->options.no_query)
a369131d 216 return NULL;
a3d5953d 217 debug(15, 3) ("getSingleParent: returning %s\n", p ? p->host : "NULL");
3c6e634f 218 return p;
090089c4 219}
220
deb79f06 221peer *
b8d8561b 222getFirstUpParent(request_t * request)
090089c4 223{
b69f7771 224 peer *p = NULL;
40a1495e 225 for (p = Config.peers; p; p = p->next) {
b69f7771 226 if (!neighborUp(p))
30a4f2a8 227 continue;
b69f7771 228 if (neighborType(p, request) != PEER_PARENT)
090089c4 229 continue;
b69f7771 230 if (!peerHTTPOkay(p, request))
e924600d 231 continue;
232 break;
090089c4 233 }
a3d5953d 234 debug(15, 3) ("getFirstUpParent: returning %s\n", p ? p->host : "NULL");
b69f7771 235 return p;
090089c4 236}
237
deb79f06 238peer *
48b38d01 239getRoundRobinParent(request_t * request)
240{
b69f7771 241 peer *p;
242 peer *q = NULL;
40a1495e 243 for (p = Config.peers; p; p = p->next) {
cd196bc8 244 if (!p->options.roundrobin)
0c8177e6 245 continue;
b69f7771 246 if (neighborType(p, request) != PEER_PARENT)
0c8177e6 247 continue;
b69f7771 248 if (!peerHTTPOkay(p, request))
48b38d01 249 continue;
b69f7771 250 if (q && q->rr_count < p->rr_count)
48b38d01 251 continue;
b69f7771 252 q = p;
48b38d01 253 }
b69f7771 254 if (q)
255 q->rr_count++;
a3d5953d 256 debug(15, 3) ("getRoundRobinParent: returning %s\n", q ? q->host : "NULL");
b69f7771 257 return q;
48b38d01 258}
259
deb79f06 260peer *
5269d0bd 261getDefaultParent(request_t * request)
262{
b69f7771 263 peer *p = NULL;
40a1495e 264 for (p = Config.peers; p; p = p->next) {
b69f7771 265 if (neighborType(p, request) != PEER_PARENT)
5269d0bd 266 continue;
cd196bc8 267 if (!p->options.default_parent)
5269d0bd 268 continue;
b69f7771 269 if (!peerHTTPOkay(p, request))
5269d0bd 270 continue;
a3d5953d 271 debug(15, 3) ("getDefaultParent: returning %s\n", p->host);
b69f7771 272 return p;
5269d0bd 273 }
669fefd4 274 debug(15, 3) ("getDefaultParent: returning NULL\n");
5269d0bd 275 return NULL;
276}
277
6a655df0 278peer *
279getAnyParent(request_t * request)
280{
281 peer *p = NULL;
282 for (p = Config.peers; p; p = p->next) {
283 if (neighborType(p, request) != PEER_PARENT)
284 continue;
285 if (!peerHTTPOkay(p, request))
286 continue;
287 debug(15, 3) ("getAnyParent: returning %s\n", p->host);
288 return p;
289 }
290 debug(15, 3) ("getAnyParent: returning NULL\n");
291 return NULL;
292}
293
deb79f06 294peer *
b69f7771 295getNextPeer(peer * p)
090089c4 296{
b69f7771 297 return p->next;
090089c4 298}
299
deb79f06 300peer *
301getFirstPeer(void)
090089c4 302{
40a1495e 303 return Config.peers;
090089c4 304}
305
b8d8561b 306static void
deb79f06 307neighborRemove(peer * target)
30a4f2a8 308{
b69f7771 309 peer *p = NULL;
310 peer **P = NULL;
40a1495e 311 p = Config.peers;
312 P = &Config.peers;
b69f7771 313 while (p) {
314 if (target == p)
30a4f2a8 315 break;
b69f7771 316 P = &p->next;
317 p = p->next;
318 }
319 if (p) {
320 *P = p->next;
b6a2f15e 321 cbdataFree(p);
40a1495e 322 Config.npeers--;
4d64d74a 323 }
40a1495e 324 first_ping = Config.peers;
4d64d74a 325}
326
b8d8561b 327void
328neighbors_open(int fd)
090089c4 329{
30a4f2a8 330 struct sockaddr_in name;
6637e3a5 331 socklen_t len = sizeof(struct sockaddr_in);
30a4f2a8 332 struct servent *sep = NULL;
30a4f2a8 333 memset(&name, '\0', sizeof(struct sockaddr_in));
334 if (getsockname(fd, (struct sockaddr *) &name, &len) < 0)
a3d5953d 335 debug(15, 1) ("getsockname(%d,%p,%p) failed.\n", fd, &name, &len);
5999b776 336 peerRefreshDNS((void *) 1);
30a4f2a8 337 if (0 == echo_hdr.opcode) {
27cd7235 338 echo_hdr.opcode = ICP_SECHO;
30a4f2a8 339 echo_hdr.version = ICP_VERSION_CURRENT;
340 echo_hdr.length = 0;
341 echo_hdr.reqnum = 0;
342 echo_hdr.flags = 0;
343 echo_hdr.pad = 0;
30a4f2a8 344 echo_hdr.shostid = name.sin_addr.s_addr;
345 sep = getservbyname("echo", "udp");
346 echo_port = sep ? ntohs((u_short) sep->s_port) : 7;
090089c4 347 }
c68e4e90 348 first_ping = Config.peers;
ed7f5615 349 cachemgrRegister("server_list",
350 "Peer Cache Statistics",
1da3b90b 351 neighborDumpPeers, 0, 1);
22f3fd98 352 cachemgrRegister("non_peers",
353 "List of Unknown sites sending ICP messages",
1da3b90b 354 neighborDumpNonPeers, 0, 1);
090089c4 355}
356
b8d8561b 357int
b6c0e933 358neighborsUdpPing(request_t * request,
641941c0 359 StoreEntry * entry,
582b6456 360 IRCB * callback,
641941c0 361 void *callback_data,
52040193 362 int *exprep,
465dc415 363 int *timeout)
090089c4 364{
9fb13bb6 365 const char *url = storeUrl(entry);
b6c0e933 366 MemObject *mem = entry->mem_obj;
b69f7771 367 peer *p = NULL;
090089c4 368 int i;
1061b406 369 int reqnum = 0;
6d2296d4 370 int flags;
9dee2904 371 icp_common_t *query;
429fdbec 372 int queries_sent = 0;
0a0bf5db 373 int peers_pinged = 0;
090089c4 374
40a1495e 375 if (Config.peers == NULL)
090089c4 376 return 0;
ce66013b 377 if (theOutIcpConnection < 0)
378 fatal("neighborsUdpPing: There is no ICP socket!");
9fb13bb6 379 assert(entry->swap_status == SWAPOUT_NONE);
b6c0e933 380 mem->start_ping = current_time;
b4e7f82d 381 mem->ping_reply_callback = callback;
b6c0e933 382 mem->ircb_data = callback_data;
465dc415 383 *timeout = 0.0;
007b8be4 384 reqnum = icpSetCacheKey(entry->key);
40a1495e 385 for (i = 0, p = first_ping; i++ < Config.npeers; p = p->next) {
b69f7771 386 if (p == NULL)
40a1495e 387 p = Config.peers;
a3d5953d 388 debug(15, 5) ("neighborsUdpPing: Peer %s\n", p->host);
b69f7771 389 if (!peerWouldBePinged(p, request))
deb79f06 390 continue; /* next peer */
0a0bf5db 391 peers_pinged++;
a3d5953d 392 debug(15, 4) ("neighborsUdpPing: pinging peer %s for '%s'\n",
b69f7771 393 p->host, url);
394 if (p->type == PEER_MULTICAST)
03a1ee42 395 mcastSetTtl(theOutIcpConnection, p->mcast.ttl);
3a4a63e7 396 debug(15, 3) ("neighborsUdpPing: key = '%s'\n", storeKeyText(entry->key));
a3d5953d 397 debug(15, 3) ("neighborsUdpPing: reqnum = %d\n", reqnum);
090089c4 398
dc9d133b 399#if USE_HTCP
cd196bc8 400 if (p->options.htcp) {
1994bb24 401 debug(15, 3) ("neighborsUdpPing: sending HTCP query\n");
176ae152 402 htcpQuery(entry, request, p);
dc9d133b 403 } else
404#endif
399cabec 405 if (p->icp.port == echo_port) {
a3d5953d 406 debug(15, 4) ("neighborsUdpPing: Looks like a dumb cache, send DECHO ping\n");
1061b406 407 echo_hdr.reqnum = reqnum;
27cd7235 408 query = icpCreateMessage(ICP_DECHO, 0, url, reqnum, 0);
af00901c 409 icpUdpSend(theOutIcpConnection,
b69f7771 410 &p->in_addr,
9dee2904 411 query,
721b3dd8 412 LOG_ICP_QUERY,
aee4e794 413 0);
090089c4 414 } else {
6d2296d4 415 flags = 0;
17a0a4ee 416 if (Config.onoff.query_icmp)
399cabec 417 if (p->icp.version == ICP_VERSION_2)
429fdbec 418 flags |= ICP_FLAG_SRC_RTT;
27cd7235 419 query = icpCreateMessage(ICP_QUERY, flags, url, reqnum, 0);
af00901c 420 icpUdpSend(theOutIcpConnection,
b69f7771 421 &p->in_addr,
9dee2904 422 query,
721b3dd8 423 LOG_ICP_QUERY,
aee4e794 424 0);
090089c4 425 }
429fdbec 426 queries_sent++;
090089c4 427
b69f7771 428 p->stats.pings_sent++;
b69f7771 429 if (p->type == PEER_MULTICAST) {
dc835977 430 /*
431 * set a bogus last_reply time so neighborUp() never
432 * says a multicast peer is dead.
433 */
434 p->stats.last_reply = squid_curtime;
b69f7771 435 (*exprep) += p->mcast.n_replies_expected;
ae95b16f 436 } else if (squid_curtime - p->stats.last_query > Config.Timeout.deadPeer) {
437 /*
438 * fake a recent reply if its been a long time since our
439 * last query
440 */
441 p->stats.last_reply = squid_curtime;
e16d4250 442 /*
443 * We used to not expect a reply in this case; we assumed
444 * the peer was DEAD if we hadn't queried it in a long
445 * time. However, the number of people whining to
446 * squid-users that ICP is broken became unbearable. They
447 * tried a single request which, to their amazement, was
448 * forwarded directly to the origin server, even thought
449 * they KNEW it was in a neighbor cache. Ok, I give up, you
450 * win!
451 */
452 (*exprep)++;
453 (*timeout) += 1000;
47b780e1 454 } else if (neighborUp(p)) {
455 /* its alive, expect a reply from it */
456 (*exprep)++;
465dc415 457 (*timeout) += p->stats.rtt;
090089c4 458 } else {
1061b406 459 /* Neighbor is dead; ping it anyway, but don't expect a reply */
090089c4 460 /* log it once at the threshold */
dc835977 461 if (p->stats.logged_state == PEER_ALIVE) {
ab4b78e9 462 debug(15, 1) ("Detected DEAD %s: %s/%d/%d\n",
b69f7771 463 neighborTypeStr(p),
399cabec 464 p->host, p->http_port, p->icp.port);
dc835977 465 p->stats.logged_state = PEER_DEAD;
090089c4 466 }
467 }
dc835977 468 p->stats.last_query = squid_curtime;
090089c4 469 }
40a1495e 470 if ((first_ping = first_ping->next) == NULL)
471 first_ping = Config.peers;
090089c4 472
0ab965da 473#if ALLOW_SOURCE_PING
090089c4 474 /* only do source_ping if we have neighbors */
40a1495e 475 if (Config.npeers) {
a369131d 476 const ipcache_addrs *ia = NULL;
477 struct sockaddr_in to_addr;
478 char *host = request->host;
17a0a4ee 479 if (!Config.onoff.source_ping) {
a3d5953d 480 debug(15, 6) ("neighborsUdpPing: Source Ping is disabled.\n");
0a0bf5db 481 } else if ((ia = ipcache_gethostbyname(host, 0))) {
a3d5953d 482 debug(15, 6) ("neighborsUdpPing: Source Ping: to %s for '%s'\n",
1061b406 483 host, url);
1061b406 484 echo_hdr.reqnum = reqnum;
16b204c4 485 if (icmp_sock != -1) {
e5f6c5c2 486 icmpSourcePing(ia->in_addrs[ia->cur], &echo_hdr, url);
16b204c4 487 } else {
488 to_addr.sin_family = AF_INET;
e5f6c5c2 489 to_addr.sin_addr = ia->in_addrs[ia->cur];
16b204c4 490 to_addr.sin_port = htons(echo_port);
27cd7235 491 query = icpCreateMessage(ICP_SECHO, 0, url, reqnum, 0);
16b204c4 492 icpUdpSend(theOutIcpConnection,
16b204c4 493 &to_addr,
9dee2904 494 query,
721b3dd8 495 LOG_ICP_QUERY,
aee4e794 496 0);
16b204c4 497 }
090089c4 498 } else {
a3d5953d 499 debug(15, 6) ("neighborsUdpPing: Source Ping: unknown host: %s\n",
1061b406 500 host);
090089c4 501 }
502 }
429fdbec 503#endif
52040193 504 /*
465dc415 505 * If there is a configured timeout, use it
52040193 506 */
465dc415 507 if (Config.Timeout.icp_query)
bb337ad7 508 *timeout = Config.Timeout.icp_query;
465dc415 509 else if (*exprep > 0)
510 (*timeout) = 2 * (*timeout) / (*exprep);
52040193 511 else
98829f69 512 *timeout = 2000; /* 2 seconds */
0a0bf5db 513 return peers_pinged;
090089c4 514}
515
26b164ac 516/* lookup the digest of a given peer */
517lookup_t
4b4cd312 518peerDigestLookup(peer * p, request_t * request, StoreEntry * entry)
26b164ac 519{
6cfa8966 520#if USE_CACHE_DIGESTS
0c511722 521 const cache_key *key = request ? storeKeyPublic(storeUrl(entry), request->method) : NULL;
26b164ac 522 assert(p);
0c511722 523 assert(request);
69c95dd3 524 debug(15, 5) ("peerDigestLookup: peer %s\n", p->host);
4b4cd312 525 /* does the peeer have a valid digest? */
e13ee7ad 526 if (!p->digest) {
527 debug(15, 5) ("peerDigestLookup: gone!\n");
26b164ac 528 return LOOKUP_NONE;
9689d97c 529 } else if (!peerHTTPOkay(p, request)) {
e13ee7ad 530 debug(15, 5) ("peerDigestLookup: !peerHTTPOkay\n");
26b164ac 531 return LOOKUP_NONE;
e13ee7ad 532 } else if (p->digest->flags.usable) {
533 debug(15, 5) ("peerDigestLookup: usable\n");
4b4cd312 534 /* fall through; put here to have common case on top */ ;
e13ee7ad 535 } else if (!p->digest->flags.needed) {
536 debug(15, 5) ("peerDigestLookup: note need\n");
537 peerDigestNeeded(p->digest);
26b164ac 538 return LOOKUP_NONE;
539 } else {
e13ee7ad 540 debug(15, 5) ("peerDigestLookup: !ready && %srequested\n",
541 p->digest->flags.requested ? "" : "!");
26b164ac 542 return LOOKUP_NONE;
543 }
69c95dd3 544 debug(15, 5) ("peerDigestLookup: OK to lookup peer %s\n", p->host);
e13ee7ad 545 assert(p->digest->cd);
26b164ac 546 /* does digest predict a hit? */
e13ee7ad 547 if (!cacheDigestTest(p->digest->cd, key))
26b164ac 548 return LOOKUP_MISS;
69c95dd3 549 debug(15, 5) ("peerDigestLookup: peer %s says HIT!\n", p->host);
26b164ac 550 return LOOKUP_HIT;
551#endif
552 return LOOKUP_NONE;
553}
554
555/* select best peer based on cache digests */
a54d3f8e 556peer *
557neighborsDigestSelect(request_t * request, StoreEntry * entry)
558{
559 peer *best_p = NULL;
6cfa8966 560#if USE_CACHE_DIGESTS
a54d3f8e 561 const cache_key *key;
562 int best_rtt = 0;
563 int choice_count = 0;
564 int ichoice_count = 0;
565 peer *p;
566 int p_rtt;
567 int i;
03058802 568 if (!request->flags.hierarchical)
569 return NULL;
a54d3f8e 570 key = storeKeyPublic(storeUrl(entry), request->method);
571 for (i = 0, p = first_ping; i++ < Config.npeers; p = p->next) {
26b164ac 572 lookup_t lookup;
a54d3f8e 573 if (!p)
574 p = Config.peers;
575 if (i == 1)
576 first_ping = p;
26b164ac 577 lookup = peerDigestLookup(p, request, entry);
578 if (lookup == LOOKUP_NONE)
a54d3f8e 579 continue;
a54d3f8e 580 choice_count++;
26b164ac 581 if (lookup == LOOKUP_MISS)
a54d3f8e 582 continue;
26b164ac 583 p_rtt = netdbHostRtt(p->host);
584 debug(15, 5) ("neighborsDigestSelect: peer %s rtt: %d\n",
a54d3f8e 585 p->host, p_rtt);
586 /* is this peer better than others in terms of rtt ? */
587 if (!best_p || (p_rtt && p_rtt < best_rtt)) {
588 best_p = p;
589 best_rtt = p_rtt;
4b4cd312 590 if (p_rtt) /* informative choice (aka educated guess) */
a54d3f8e 591 ichoice_count++;
592 debug(15, 4) ("neighborsDigestSelect: peer %s leads with rtt %d\n",
593 p->host, best_rtt);
594 }
595 }
26b164ac 596 debug(15, 4) ("neighborsDigestSelect: choices: %d (%d)\n",
597 choice_count, ichoice_count);
598 peerNoteDigestLookup(request, best_p,
599 best_p ? LOOKUP_HIT : (choice_count ? LOOKUP_MISS : LOOKUP_NONE));
a54d3f8e 600 request->hier.n_choices = choice_count;
601 request->hier.n_ichoices = ichoice_count;
602#endif
603 return best_p;
604}
605
26b164ac 606void
4b4cd312 607peerNoteDigestLookup(request_t * request, peer * p, lookup_t lookup)
26b164ac 608{
6cfa8966 609#if USE_CACHE_DIGESTS
26b164ac 610 if (p)
611 strncpy(request->hier.cd_host, p->host, sizeof(request->hier.cd_host));
612 else
613 *request->hier.cd_host = '\0';
614 request->hier.cd_lookup = lookup;
615 debug(15, 4) ("peerNoteDigestLookup: peer %s, lookup: %s\n",
616 p ? p->host : "<none>", lookup_t_str[lookup]);
617#endif
618}
619
d73844ca 620static void
b69f7771 621neighborAlive(peer * p, const MemObject * mem, const icp_common_t * header)
4eda6afe 622{
39ac34a9 623 if (p->stats.logged_state == PEER_DEAD && p->tcp_up) {
ab4b78e9 624 debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n",
b69f7771 625 neighborTypeStr(p),
399cabec 626 p->host, p->http_port, p->icp.port);
dc835977 627 p->stats.logged_state = PEER_ALIVE;
4eda6afe 628 }
dc835977 629 p->stats.last_reply = squid_curtime;
44f2f2e4 630 p->stats.pings_acked++;
27cd7235 631 if ((icp_opcode) header->opcode <= ICP_END)
399cabec 632 p->icp.counts[header->opcode]++;
44f2f2e4 633 p->icp.version = (int) header->version;
634}
635
636static void
637neighborUpdateRtt(peer * p, MemObject * mem)
638{
639 int rtt;
d2cd6935 640 if (!mem)
641 return;
44f2f2e4 642 if (!mem->start_ping.tv_sec)
643 return;
644 rtt = tvSubMsec(mem->start_ping, current_time);
1b6ef2d2 645 if (rtt < 1 || rtt > 10000)
646 return;
647 p->stats.rtt = intAverage(p->stats.rtt, rtt,
d46a87a8 648 p->stats.pings_acked, RTT_AV_FACTOR);
4eda6afe 649}
090089c4 650
399cabec 651#if USE_HTCP
652static void
653neighborAliveHtcp(peer * p, const MemObject * mem, const htcpReplyData * htcp)
654{
399cabec 655 if (p->stats.logged_state == PEER_DEAD && p->tcp_up) {
656 debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n",
657 neighborTypeStr(p),
658 p->host, p->http_port, p->icp.port);
659 p->stats.logged_state = PEER_ALIVE;
660 }
661 p->stats.last_reply = squid_curtime;
44f2f2e4 662 p->stats.pings_acked++;
399cabec 663 p->htcp.counts[htcp->hit ? 1 : 0]++;
44f2f2e4 664 p->htcp.version = htcp->version;
399cabec 665}
666#endif
667
38792624 668static void
56b62ecc 669neighborCountIgnored(peer * p)
a7e59001 670{
b69f7771 671 if (p == NULL)
a7e59001 672 return;
b69f7771 673 p->stats.ignored_replies++;
c7a3724d 674 NLateReplies++;
a7e59001 675}
676
e102ebda 677static peer *non_peers = NULL;
678
679static void
680neighborIgnoreNonPeer(const struct sockaddr_in *from, icp_opcode opcode)
681{
682 peer *np;
683 double x;
684 for (np = non_peers; np; np = np->next) {
685 if (np->in_addr.sin_addr.s_addr != from->sin_addr.s_addr)
686 continue;
687 if (np->in_addr.sin_port != from->sin_port)
688 continue;
689 break;
690 }
691 if (np == NULL) {
692 np = xcalloc(1, sizeof(peer));
693 np->in_addr.sin_addr = from->sin_addr;
694 np->in_addr.sin_port = from->sin_port;
399cabec 695 np->icp.port = ntohl(from->sin_port);
e102ebda 696 np->type = PEER_NONE;
697 np->host = xstrdup(inet_ntoa(from->sin_addr));
698 np->next = non_peers;
699 non_peers = np;
700 }
701 np->stats.ignored_replies++;
399cabec 702 np->icp.counts[opcode]++;
e102ebda 703 x = log(np->stats.ignored_replies) / log(10.0);
704 if (0.0 != x - (double) (int) x)
705 return;
706 debug(15, 1) ("WARNING: Ignored %d replies from non-peer %s\n",
707 np->stats.ignored_replies, np->host);
708}
709
429fdbec 710/* ignoreMulticastReply
711 *
712 * We want to ignore replies from multicast peers if the
713 * cache_host_domain rules would normally prevent the peer
714 * from being used
715 */
716static int
b69f7771 717ignoreMulticastReply(peer * p, MemObject * mem)
429fdbec 718{
b69f7771 719 if (p == NULL)
429fdbec 720 return 0;
cd196bc8 721 if (!p->options.mcast_responder)
429fdbec 722 return 0;
b69f7771 723 if (peerHTTPOkay(p, mem->request))
429fdbec 724 return 0;
725 return 1;
726}
727
728/* I should attach these records to the entry. We take the first
729 * hit we get our wait until everyone misses. The timeout handler
730 * call needs to nip this shopping list or call one of the misses.
731 *
732 * If a hit process is already started, then sobeit
733 */
b8d8561b 734void
5ad33356 735neighborsUdpAck(const cache_key * key, icp_common_t * header, const struct sockaddr_in *from)
090089c4 736{
b69f7771 737 peer *p = NULL;
5ad33356 738 StoreEntry *entry;
739 MemObject *mem = NULL;
b6c0e933 740 peer_t ntype = PEER_NONE;
5e5126cc 741 char *opcode_d;
a7e59001 742 icp_opcode opcode = (icp_opcode) header->opcode;
090089c4 743
5ad33356 744 debug(15, 6) ("neighborsUdpAck: opcode %d '%s'\n",
745 (int) opcode, storeKeyText(key));
746 if (NULL != (entry = storeGet(key)))
747 mem = entry->mem_obj;
b69f7771 748 if ((p = whichPeer(from)))
749 neighborAlive(p, mem, header);
27cd7235 750 if (opcode > ICP_END)
d2af9477 751 return;
27cd7235 752 opcode_d = icp_opcode_str[opcode];
41587298 753 if (p)
754 neighborUpdateRtt(p, mem);
5ad33356 755 /* Does the entry exist? */
756 if (NULL == entry) {
757 debug(12, 3) ("neighborsUdpAck: Cache key '%s' not found\n",
758 storeKeyText(key));
56b62ecc 759 neighborCountIgnored(p);
5ad33356 760 return;
761 }
2d1c6a4f 762 /* check if someone is already fetching it */
d46a87a8 763 if (EBIT_TEST(entry->flags, ENTRY_DISPATCHED)) {
5ad33356 764 debug(15, 3) ("neighborsUdpAck: '%s' already being fetched.\n",
765 storeKeyText(key));
56b62ecc 766 neighborCountIgnored(p);
d2af9477 767 return;
768 }
2d1c6a4f 769 if (mem == NULL) {
5ad33356 770 debug(15, 2) ("Ignoring %s for missing mem_obj: %s\n",
771 opcode_d, storeKeyText(key));
56b62ecc 772 neighborCountIgnored(p);
8de2f7ad 773 return;
774 }
775 if (entry->ping_status != PING_WAITING) {
674ac814 776 debug(15, 2) ("neighborsUdpAck: Late %s for %s\n",
5ad33356 777 opcode_d, storeKeyText(key));
56b62ecc 778 neighborCountIgnored(p);
8de2f7ad 779 return;
780 }
4eda6afe 781 if (entry->lock_count == 0) {
5ad33356 782 debug(12, 1) ("neighborsUdpAck: '%s' has no locks\n",
783 storeKeyText(key));
56b62ecc 784 neighborCountIgnored(p);
4eda6afe 785 return;
090089c4 786 }
a3d5953d 787 debug(15, 3) ("neighborsUdpAck: %s for '%s' from %s \n",
5ad33356 788 opcode_d, storeKeyText(key), p ? p->host : "source");
44f2f2e4 789 if (p) {
b69f7771 790 ntype = neighborType(p, mem->request);
44f2f2e4 791 }
b69f7771 792 if (ignoreMulticastReply(p, mem)) {
56b62ecc 793 neighborCountIgnored(p);
27cd7235 794 } else if (opcode == ICP_MISS) {
b69f7771 795 if (p == NULL) {
e102ebda 796 neighborIgnoreNonPeer(from, opcode);
d2af9477 797 } else {
b4e7f82d 798 mem->ping_reply_callback(p, ntype, PROTO_ICP, header, mem->ircb_data);
30a4f2a8 799 }
a7c05555 800 } else if (opcode == ICP_HIT) {
b69f7771 801 if (p == NULL) {
e102ebda 802 neighborIgnoreNonPeer(from, opcode);
d2af9477 803 } else {
27cd7235 804 header->opcode = ICP_HIT;
b4e7f82d 805 mem->ping_reply_callback(p, ntype, PROTO_ICP, header, mem->ircb_data);
090089c4 806 }
27cd7235 807 } else if (opcode == ICP_DECHO) {
b69f7771 808 if (p == NULL) {
e102ebda 809 neighborIgnoreNonPeer(from, opcode);
deb79f06 810 } else if (ntype == PEER_SIBLING) {
5e604a0e 811 debug_trap("neighborsUdpAck: Found non-ICP cache as SIBLING\n");
812 debug_trap("neighborsUdpAck: non-ICP neighbors must be a PARENT\n");
090089c4 813 } else {
b4e7f82d 814 mem->ping_reply_callback(p, ntype, PROTO_ICP, header, mem->ircb_data);
090089c4 815 }
27cd7235 816 } else if (opcode == ICP_SECHO) {
b69f7771 817 if (p) {
a3d5953d 818 debug(15, 1) ("Ignoring SECHO from neighbor %s\n", p->host);
56b62ecc 819 neighborCountIgnored(p);
0ab965da 820#if ALLOW_SOURCE_PING
821 } else if (Config.onoff.source_ping) {
b4e7f82d 822 mem->ping_reply_callback(NULL, ntype, PROTO_ICP, header, mem->ircb_data);
0ab965da 823#endif
824 } else {
825 debug(15, 1) ("Unsolicited SECHO from %s\n", inet_ntoa(from->sin_addr));
090089c4 826 }
27cd7235 827 } else if (opcode == ICP_DENIED) {
b69f7771 828 if (p == NULL) {
e102ebda 829 neighborIgnoreNonPeer(from, opcode);
b69f7771 830 } else if (p->stats.pings_acked > 100) {
399cabec 831 if (100 * p->icp.counts[ICP_DENIED] / p->stats.pings_acked > 95) {
a3d5953d 832 debug(15, 0) ("95%% of replies from '%s' are UDP_DENIED\n", p->host);
833 debug(15, 0) ("Disabling '%s', please check your configuration.\n", p->host);
b69f7771 834 neighborRemove(p);
835 p = NULL;
e006d372 836 } else {
56b62ecc 837 neighborCountIgnored(p);
30a4f2a8 838 }
839 }
27cd7235 840 } else if (opcode == ICP_MISS_NOFETCH) {
b4e7f82d 841 mem->ping_reply_callback(p, ntype, PROTO_ICP, header, mem->ircb_data);
090089c4 842 } else {
a3d5953d 843 debug(15, 0) ("neighborsUdpAck: Unexpected ICP reply: %s\n", opcode_d);
d2af9477 844 }
090089c4 845}
846
deb79f06 847peer *
40a1495e 848peerFindByName(const char *name)
98ffb7e4 849{
b69f7771 850 peer *p = NULL;
40a1495e 851 for (p = Config.peers; p; p = p->next) {
b69f7771 852 if (!strcasecmp(name, p->host))
98ffb7e4 853 break;
854 }
b69f7771 855 return p;
98ffb7e4 856}
b012353a 857
db1cd23c 858peer *
859peerFindByNameAndPort(const char *name, unsigned short port)
860{
861 peer *p = NULL;
862 for (p = Config.peers; p; p = p->next) {
863 if (strcasecmp(name, p->host))
864 continue;
865 if (port != p->http_port)
866 continue;
867 break;
868 }
869 return p;
870}
871
5269d0bd 872int
b69f7771 873neighborUp(const peer * p)
5269d0bd 874{
b69f7771 875 if (!p->tcp_up)
03b82057 876 return 0;
877 if (squid_curtime - p->stats.last_query > Config.Timeout.deadPeer)
878 return 1;
fc161a66 879 if (p->stats.last_query - p->stats.last_reply > Config.Timeout.deadPeer)
03b82057 880 return 0;
881 return 1;
5269d0bd 882}
883
e6e3b09b 884void
db1cd23c 885peerDestroy(void *data, int unused)
e6e3b09b 886{
db1cd23c 887 peer *p = data;
ee4a1f5d 888 struct _domain_ping *l = NULL;
889 struct _domain_ping *nl = NULL;
b69f7771 890 if (p == NULL)
3c6e634f 891 return;
b6a2f15e 892 for (l = p->peer_domain; l; l = nl) {
ee4a1f5d 893 nl = l->next;
894 safe_free(l->domain);
895 safe_free(l);
896 }
b69f7771 897 safe_free(p->host);
e13ee7ad 898#if USE_CACHE_DIGESTS
b6a2f15e 899 if (p->digest) {
900 PeerDigest *pd = p->digest;
901 p->digest = NULL;
902 cbdataUnlock(pd);
903 }
e13ee7ad 904#endif
db1cd23c 905 xfree(p);
e6e3b09b 906}
c7a3724d 907
e13ee7ad 908void
e16d4250 909peerNoteDigestGone(peer * p)
e13ee7ad 910{
911#if USE_CACHE_DIGESTS
912 if (p->digest) {
fcbbccfe 913 PeerDigest *pd = p->digest;
e13ee7ad 914 p->digest = NULL;
fcbbccfe 915 cbdataUnlock(pd);
e13ee7ad 916 }
917#endif
918}
919
dd4bd44e 920static void
03a1ee42 921peerDNSConfigure(const ipcache_addrs * ia, void *data)
dd4bd44e 922{
b69f7771 923 peer *p = data;
dd4bd44e 924 struct sockaddr_in *ap;
925 int j;
b69f7771 926 if (p->n_addresses == 0) {
a3d5953d 927 debug(15, 1) ("Configuring %s %s/%d/%d\n", neighborTypeStr(p),
399cabec 928 p->host, p->http_port, p->icp.port);
b69f7771 929 if (p->type == PEER_MULTICAST)
a3d5953d 930 debug(15, 1) (" Multicast TTL = %d\n", p->mcast.ttl);
b69f7771 931 }
932 p->n_addresses = 0;
dd4bd44e 933 if (ia == NULL) {
a3d5953d 934 debug(0, 0) ("WARNING: DNS lookup for '%s' failed!\n", p->host);
dd4bd44e 935 return;
936 }
c04fe656 937 if ((int) ia->count < 1) {
a3d5953d 938 debug(0, 0) ("WARNING: No IP address found for '%s'!\n", p->host);
dd4bd44e 939 return;
940 }
c04fe656 941 for (j = 0; j < (int) ia->count && j < PEER_MAX_ADDRESSES; j++) {
b69f7771 942 p->addresses[j] = ia->in_addrs[j];
a3d5953d 943 debug(15, 2) ("--> IP address #%d: %s\n", j, inet_ntoa(p->addresses[j]));
b69f7771 944 p->n_addresses++;
dd4bd44e 945 }
b69f7771 946 ap = &p->in_addr;
dd4bd44e 947 memset(ap, '\0', sizeof(struct sockaddr_in));
948 ap->sin_family = AF_INET;
b69f7771 949 ap->sin_addr = p->addresses[0];
399cabec 950 ap->sin_port = htons(p->icp.port);
b69f7771 951 if (p->type == PEER_MULTICAST)
952 peerCountMcastPeersSchedule(p, 10);
1a827bc0 953 if (p->type != PEER_MULTICAST)
cd196bc8 954 if (!p->options.no_netdb_exchange)
223213df 955 eventAddIsh("netdbExchangeStart", netdbExchangeStart, p, 30.0, 1);
dd4bd44e 956}
957
958static void
51242273 959peerRefreshDNS(void *data)
dd4bd44e 960{
b69f7771 961 peer *p = NULL;
46ca5fc6 962 if (eventFind(peerRefreshDNS, NULL))
73cb7e3a 963 eventDelete(peerRefreshDNS, NULL);
51242273 964 if (!data && 0 == stat5minClientRequests()) {
1f3c4622 965 /* no recent client traffic, wait a bit */
5999b776 966 eventAddIsh("peerRefreshDNS", peerRefreshDNS, NULL, 180.0, 1);
1f3c4622 967 return;
dd4bd44e 968 }
1f3c4622 969 for (p = Config.peers; p; p = p->next)
970 ipcache_nbgethostbyname(p->host, peerDNSConfigure, p);
dd4bd44e 971 /* Reconfigure the peers every hour */
52040193 972 eventAddIsh("peerRefreshDNS", peerRefreshDNS, NULL, 3600.0, 1);
dd4bd44e 973}
e924600d 974
0e7b6b06 975/*
976 * peerCheckConnect will NOT be called by eventRun if the peer/data
977 * pointer becomes invalid.
978 */
e924600d 979static void
980peerCheckConnect(void *data)
981{
982 peer *p = data;
983 int fd;
984 fd = comm_open(SOCK_STREAM, 0, Config.Addrs.tcp_outgoing,
985 0, COMM_NONBLOCKING, p->host);
986 if (fd < 0)
987 return;
03a1ee42 988 p->test_fd = fd;
8407afee 989 ipcache_nbgethostbyname(p->host, peerCheckConnect2, p);
e924600d 990}
991
992static void
79d39a72 993peerCheckConnect2(const ipcache_addrs * ianotused, void *data)
e924600d 994{
995 peer *p = data;
03a1ee42 996 commConnectStart(p->test_fd,
e924600d 997 p->host,
998 p->http_port,
999 peerCheckConnectDone,
1000 p);
1001}
1002
1003static void
1004peerCheckConnectDone(int fd, int status, void *data)
1005{
1006 peer *p = data;
98829f69 1007 if (status == COMM_OK) {
1008 p->tcp_up = PEER_TCP_MAGIC_COUNT;
feb88ffa 1009 debug(15, 1) ("TCP connection to %s/%d succeeded\n",
e924600d 1010 p->host, p->http_port);
1011 } else {
98829f69 1012 eventAdd("peerCheckConnect", peerCheckConnect, p, 60.0, 1);
e924600d 1013 }
1014 comm_close(fd);
1015 return;
1016}
1017
1018void
1019peerCheckConnectStart(peer * p)
1020{
1021 if (!p->tcp_up)
1022 return;
feb88ffa 1023 debug(15, 1) ("TCP connection to %s/%d failed\n", p->host, p->http_port);
98829f69 1024 p->tcp_up--;
1025 if (p->tcp_up != (PEER_TCP_MAGIC_COUNT - 1))
1026 return;
e924600d 1027 p->last_fail_time = squid_curtime;
98829f69 1028 eventAdd("peerCheckConnect", peerCheckConnect, p, 30.0, 1);
e924600d 1029}
429fdbec 1030
1031static void
1032peerCountMcastPeersSchedule(peer * p, time_t when)
1033{
b515fc11 1034 if (p->mcast.flags.count_event_pending)
429fdbec 1035 return;
1036 eventAdd("peerCountMcastPeersStart",
1037 peerCountMcastPeersStart,
1038 p,
52040193 1039 (double) when, 1);
b515fc11 1040 p->mcast.flags.count_event_pending = 1;
429fdbec 1041}
1042
1043static void
1044peerCountMcastPeersStart(void *data)
1045{
1046 peer *p = data;
1047 ps_state *psstate = xcalloc(1, sizeof(ps_state));
1048 StoreEntry *fake;
1049 MemObject *mem;
1050 icp_common_t *query;
007b8be4 1051 int reqnum;
429fdbec 1052 LOCAL_ARRAY(char, url, MAX_URL);
ce66013b 1053 assert(p->type == PEER_MULTICAST);
b515fc11 1054 p->mcast.flags.count_event_pending = 0;
042461c3 1055 snprintf(url, MAX_URL, "http://%s/", inet_ntoa(p->in_addr.sin_addr));
92695e5e 1056 fake = storeCreateEntry(url, url, null_request_flags, METHOD_GET);
429fdbec 1057 psstate->request = requestLink(urlParse(METHOD_GET, url));
1058 psstate->entry = fake;
1059 psstate->callback = NULL;
429fdbec 1060 psstate->callback_data = p;
b4e7f82d 1061 psstate->ping.start = current_time;
db1cd23c 1062 cbdataAdd(psstate, cbdataXfree, 0);
429fdbec 1063 mem = fake->mem_obj;
2db609de 1064 mem->request = requestLink(psstate->request);
429fdbec 1065 mem->start_ping = current_time;
b4e7f82d 1066 mem->ping_reply_callback = peerCountHandleIcpReply;
429fdbec 1067 mem->ircb_data = psstate;
03a1ee42 1068 mcastSetTtl(theOutIcpConnection, p->mcast.ttl);
007b8be4 1069 p->mcast.id = mem->id;
1070 reqnum = icpSetCacheKey(fake->key);
1071 query = icpCreateMessage(ICP_QUERY, 0, url, reqnum, 0);
429fdbec 1072 icpUdpSend(theOutIcpConnection,
1073 &p->in_addr,
1074 query,
721b3dd8 1075 LOG_ICP_QUERY,
aee4e794 1076 0);
429fdbec 1077 fake->ping_status = PING_WAITING;
1078 eventAdd("peerCountMcastPeersDone",
1079 peerCountMcastPeersDone,
2db609de 1080 psstate,
465dc415 1081 (double) Config.Timeout.mcast_icp_query, 1);
b515fc11 1082 p->mcast.flags.counting = 1;
429fdbec 1083 peerCountMcastPeersSchedule(p, MCAST_COUNT_RATE);
1084}
1085
1086static void
1087peerCountMcastPeersDone(void *data)
1088{
1089 ps_state *psstate = data;
1090 peer *p = psstate->callback_data;
1091 StoreEntry *fake = psstate->entry;
b515fc11 1092 p->mcast.flags.counting = 0;
9e4ad609 1093 p->mcast.avg_n_members = doubleAverage(p->mcast.avg_n_members,
b4e7f82d 1094 (double) psstate->ping.n_recv,
9e4ad609 1095 ++p->mcast.n_times_counted,
1096 10);
1a827bc0 1097 debug(15, 1) ("Group %s: %d replies, %4.1f average, RTT %d\n",
429fdbec 1098 p->host,
b4e7f82d 1099 psstate->ping.n_recv,
1a827bc0 1100 p->mcast.avg_n_members,
1101 p->stats.rtt);
429fdbec 1102 p->mcast.n_replies_expected = (int) p->mcast.avg_n_members;
b7fe0ab0 1103 EBIT_SET(fake->flags, ENTRY_ABORTED);
e7a22b88 1104 requestUnlink(fake->mem_obj->request);
f0d5043e 1105 fake->mem_obj->request = NULL;
429fdbec 1106 storeReleaseRequest(fake);
1107 storeUnlockObject(fake);
e7a22b88 1108 requestUnlink(psstate->request);
1a827bc0 1109 cbdataFree(psstate);
429fdbec 1110}
1111
1112static void
5942e8d4 1113peerCountHandleIcpReply(peer * p, peer_t type, protocol_t proto, void *hdrnotused, void *data)
429fdbec 1114{
1115 ps_state *psstate = data;
1a827bc0 1116 StoreEntry *fake = psstate->entry;
1117 MemObject *mem = fake->mem_obj;
1118 int rtt = tvSubMsec(mem->start_ping, current_time);
86aebcda 1119 assert(proto == PROTO_ICP);
1a827bc0 1120 assert(fake);
1121 assert(mem);
b4e7f82d 1122 psstate->ping.n_recv++;
1123 p->stats.rtt = intAverage(p->stats.rtt, rtt, psstate->ping.n_recv, RTT_AV_FACTOR);
429fdbec 1124}
ed7f5615 1125
1126static void
1127neighborDumpPeers(StoreEntry * sentry)
1128{
1129 dump_peers(sentry, Config.peers);
1130}
1131
1132static void
1133neighborDumpNonPeers(StoreEntry * sentry)
1134{
1135 dump_peers(sentry, non_peers);
1136}
1137
a369131d 1138void
1139dump_peer_options(StoreEntry * sentry, peer * p)
1140{
cd196bc8 1141 if (p->options.proxy_only)
a369131d 1142 storeAppendPrintf(sentry, " proxy-only");
cd196bc8 1143 if (p->options.no_query)
a369131d 1144 storeAppendPrintf(sentry, " no-query");
cd196bc8 1145 if (p->options.no_digest)
8638fc66 1146 storeAppendPrintf(sentry, " no-digest");
cd196bc8 1147 if (p->options.default_parent)
a369131d 1148 storeAppendPrintf(sentry, " default");
cd196bc8 1149 if (p->options.roundrobin)
a369131d 1150 storeAppendPrintf(sentry, " round-robin");
cd196bc8 1151 if (p->options.mcast_responder)
a369131d 1152 storeAppendPrintf(sentry, " multicast-responder");
cd196bc8 1153 if (p->options.closest_only)
a369131d 1154 storeAppendPrintf(sentry, " closest-only");
dc9d133b 1155#if USE_HTCP
cd196bc8 1156 if (p->options.htcp)
e8d185d2 1157 storeAppendPrintf(sentry, " htcp");
dc9d133b 1158#endif
cd196bc8 1159 if (p->options.no_netdb_exchange)
1a5dae67 1160 storeAppendPrintf(sentry, " no-netdb-exchange");
95e36d02 1161#if DELAY_POOLS
cd196bc8 1162 if (p->options.no_delay)
95e36d02 1163 storeAppendPrintf(sentry, " no-delay");
1164#endif
c68e9c6b 1165 if (p->login)
1166 storeAppendPrintf(sentry, " login=%s", p->login);
a369131d 1167 if (p->mcast.ttl > 0)
1168 storeAppendPrintf(sentry, " ttl=%d", p->mcast.ttl);
1169 storeAppendPrintf(sentry, "\n");
1170}
1171
ed7f5615 1172static void
1173dump_peers(StoreEntry * sentry, peer * peers)
1174{
1175 peer *e = NULL;
1176 struct _domain_ping *d = NULL;
1177 icp_opcode op;
06e6d12a 1178 int i;
ed7f5615 1179 if (peers == NULL)
1180 storeAppendPrintf(sentry, "There are no neighbors installed.\n");
1181 for (e = peers; e; e = e->next) {
1182 assert(e->host != NULL);
1183 storeAppendPrintf(sentry, "\n%-11.11s: %s/%d/%d\n",
1184 neighborTypeStr(e),
1185 e->host,
1186 e->http_port,
399cabec 1187 e->icp.port);
a369131d 1188 storeAppendPrintf(sentry, "Flags :");
1189 dump_peer_options(sentry, e);
06e6d12a 1190 for (i = 0; i < e->n_addresses; i++) {
1191 storeAppendPrintf(sentry, "Address[%d] : %s\n", i,
1192 inet_ntoa(e->addresses[i]));
1193 }
ed7f5615 1194 storeAppendPrintf(sentry, "Status : %s\n",
1195 neighborUp(e) ? "Up" : "Down");
1196 storeAppendPrintf(sentry, "AVG RTT : %d msec\n", e->stats.rtt);
1197 storeAppendPrintf(sentry, "LAST QUERY : %8d seconds ago\n",
1198 (int) (squid_curtime - e->stats.last_query));
1199 storeAppendPrintf(sentry, "LAST REPLY : %8d seconds ago\n",
1200 (int) (squid_curtime - e->stats.last_reply));
1201 storeAppendPrintf(sentry, "PINGS SENT : %8d\n", e->stats.pings_sent);
1202 storeAppendPrintf(sentry, "PINGS ACKED: %8d %3d%%\n",
1203 e->stats.pings_acked,
1204 percent(e->stats.pings_acked, e->stats.pings_sent));
1205 storeAppendPrintf(sentry, "FETCHES : %8d %3d%%\n",
1206 e->stats.fetches,
1207 percent(e->stats.fetches, e->stats.pings_acked));
1208 storeAppendPrintf(sentry, "IGNORED : %8d %3d%%\n",
1209 e->stats.ignored_replies,
1210 percent(e->stats.ignored_replies, e->stats.pings_acked));
1211 storeAppendPrintf(sentry, "Histogram of PINGS ACKED:\n");
1994bb24 1212#if USE_HTCP
cd196bc8 1213 if (e->options.htcp) {
1994bb24 1214 storeAppendPrintf(sentry, "\tMisses\t%8d %3d%%\n",
1215 e->htcp.counts[0],
1216 percent(e->htcp.counts[0], e->stats.pings_acked));
1217 storeAppendPrintf(sentry, "\tHits\t%8d %3d%%\n",
1218 e->htcp.counts[1],
1219 percent(e->htcp.counts[1], e->stats.pings_acked));
1220 } else {
1221#endif
5942e8d4 1222 for (op = ICP_INVALID; op < ICP_END; op++) {
1223 if (e->icp.counts[op] == 0)
1224 continue;
1225 storeAppendPrintf(sentry, " %12.12s : %8d %3d%%\n",
1226 icp_opcode_str[op],
1227 e->icp.counts[op],
1228 percent(e->icp.counts[op], e->stats.pings_acked));
1229 }
1994bb24 1230#if USE_HTCP
5942e8d4 1231 }
1994bb24 1232#endif
ed7f5615 1233 if (e->last_fail_time) {
1234 storeAppendPrintf(sentry, "Last failed connect() at: %s\n",
1235 mkhttpdlogtime(&(e->last_fail_time)));
1236 }
b6a2f15e 1237 if (e->peer_domain != NULL) {
ed7f5615 1238 storeAppendPrintf(sentry, "DOMAIN LIST: ");
b6a2f15e 1239 for (d = e->peer_domain; d; d = d->next) {
5942e8d4 1240 storeAppendPrintf(sentry, "%s%s ",
1241 d->do_ping ? null_string : "!", d->domain);
1994bb24 1242 }
1243 storeAppendPrintf(sentry, "\n");
ed7f5615 1244 }
99edd1c3 1245 storeAppendPrintf(sentry, "keep-alive ratio: %d%%\n",
ed7f5615 1246 percent(e->stats.n_keepalives_recv, e->stats.n_keepalives_sent));
1247 }
1248}
86aebcda 1249
1250#if USE_HTCP
1251void
1252neighborsHtcpReply(const cache_key * key, htcpReplyData * htcp, const struct sockaddr_in *from)
1253{
b4e7f82d 1254 StoreEntry *e = storeGet(key);
399cabec 1255 MemObject *mem = NULL;
1256 peer *p;
1257 peer_t ntype = PEER_NONE;
399cabec 1258 debug(15, 6) ("neighborsHtcpReply: %s %s\n",
1259 htcp->hit ? "HIT" : "MISS", storeKeyText(key));
1260 if (NULL != (e = storeGet(key)))
1261 mem = e->mem_obj;
1262 if ((p = whichPeer(from)))
1263 neighborAliveHtcp(p, mem, htcp);
1264 /* Does the entry exist? */
1265 if (NULL == e) {
1266 debug(12, 3) ("neighyborsHtcpReply: Cache key '%s' not found\n",
1267 storeKeyText(key));
1268 neighborCountIgnored(p);
1269 return;
1270 }
1271 /* check if someone is already fetching it */
d46a87a8 1272 if (EBIT_TEST(e->flags, ENTRY_DISPATCHED)) {
399cabec 1273 debug(15, 3) ("neighborsUdpAck: '%s' already being fetched.\n",
1274 storeKeyText(key));
1275 neighborCountIgnored(p);
1276 return;
1277 }
1278 if (mem == NULL) {
1279 debug(15, 2) ("Ignoring reply for missing mem_obj: %s\n",
1280 storeKeyText(key));
1281 neighborCountIgnored(p);
1282 return;
1283 }
1284 if (e->ping_status != PING_WAITING) {
1285 debug(15, 2) ("neighborsUdpAck: Entry %s is not PING_WAITING\n",
1286 storeKeyText(key));
1287 neighborCountIgnored(p);
1288 return;
1289 }
1290 if (e->lock_count == 0) {
1291 debug(12, 1) ("neighborsUdpAck: '%s' has no locks\n",
1292 storeKeyText(key));
1293 neighborCountIgnored(p);
1294 return;
1295 }
44f2f2e4 1296 if (p) {
399cabec 1297 ntype = neighborType(p, mem->request);
44f2f2e4 1298 neighborUpdateRtt(p, mem);
1299 }
399cabec 1300 if (ignoreMulticastReply(p, mem)) {
1301 neighborCountIgnored(p);
1302 return;
1303 }
1304 debug(15, 1) ("neighborsHtcpReply: e = %p\n", e);
b4e7f82d 1305 mem->ping_reply_callback(p, ntype, PROTO_HTCP, htcp, mem->ircb_data);
86aebcda 1306}
1307#endif