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