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