]> git.ipfire.org Git - thirdparty/squid.git/blame - src/neighbors.cc
update
[thirdparty/squid.git] / src / neighbors.cc
CommitLineData
22f3fd98 1
30a4f2a8 2/*
6cfa8966 3 * $Id: neighbors.cc,v 1.200 1998/04/24 06:08:18 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
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 *);
113static int peerHTTPOkay(const peer *, request_t *);
114static int peerWouldBePinged(const peer *, request_t *);
115static void neighborRemove(peer *);
ea3a2a69 116static peer *whichPeer(const struct sockaddr_in *from);
f5b8bbc4 117static void neighborAlive(peer *, const MemObject *, const icp_common_t *);
118static void neighborCountIgnored(peer *, icp_opcode op_unused);
119static void peerRefreshDNS(void *);
b69f7771 120static IPH peerDNSConfigure;
f5b8bbc4 121static void peerCheckConnect(void *);
b69f7771 122static IPH peerCheckConnect2;
603a02fd 123static CNCB peerCheckConnectDone;
f5b8bbc4 124static void peerCountMcastPeersDone(void *data);
125static void peerCountMcastPeersStart(void *data);
126static void peerCountMcastPeersSchedule(peer * p, time_t when);
b3264694 127static IRCB peerCountHandleIcpReply;
f5b8bbc4 128static void neighborIgnoreNonPeer(const struct sockaddr_in *, icp_opcode);
ed7f5615 129static OBJH neighborDumpPeers;
130static OBJH neighborDumpNonPeers;
131static void dump_peers(StoreEntry * sentry, peer * peers);
090089c4 132
090089c4 133static icp_common_t echo_hdr;
30a4f2a8 134static u_short echo_port;
30a4f2a8 135
c7a3724d 136static int NLateReplies = 0;
40a1495e 137static peer *first_ping = NULL;
28070024 138
c7a3724d 139char *
b69f7771 140neighborTypeStr(const peer * p)
69a71bd7 141{
e102ebda 142 if (p->type == PEER_NONE)
143 return "Non-Peer";
b69f7771 144 if (p->type == PEER_SIBLING)
69a71bd7 145 return "Sibling";
b69f7771 146 if (p->type == PEER_MULTICAST)
7b3bd12c 147 return "Multicast Group";
69a71bd7 148 return "Parent";
149}
150
090089c4 151
deb79f06 152static peer *
153whichPeer(const struct sockaddr_in *from)
090089c4 154{
22e4fa85 155 int j;
4eda6afe 156 u_short port = ntohs(from->sin_port);
157 struct in_addr ip = from->sin_addr;
b69f7771 158 peer *p = NULL;
a3d5953d 159 debug(15, 3) ("whichPeer: from %s port %d\n", inet_ntoa(ip), port);
40a1495e 160 for (p = Config.peers; p; p = p->next) {
b69f7771 161 for (j = 0; j < p->n_addresses; j++) {
162 if (ip.s_addr == p->addresses[j].s_addr && port == p->icp_port) {
163 return p;
090089c4 164 }
165 }
166 }
4eda6afe 167 return NULL;
090089c4 168}
169
b6c0e933 170static peer_t
b69f7771 171neighborType(const peer * p, const request_t * request)
24a1003d 172{
b012353a 173 const struct _domain_type *d = NULL;
b69f7771 174 for (d = p->typelist; d; d = d->next) {
24a1003d 175 if (matchDomainName(d->domain, request->host))
deb79f06 176 if (d->type != PEER_NONE)
b012353a 177 return d->type;
24a1003d 178 }
b69f7771 179 return p->type;
24a1003d 180}
181
7b3bd12c 182/*
62fd6124 183 * peerAllowedToUse
7b3bd12c 184 *
dd4bd44e 185 * this function figures out if it is appropriate to fetch REQUEST
62fd6124 186 * from PEER.
7b3bd12c 187 */
b8d8561b 188static int
b69f7771 189peerAllowedToUse(const peer * p, request_t * request)
090089c4 190{
b012353a 191 const struct _domain_ping *d = NULL;
090089c4 192 int do_ping = 1;
0ee4272b 193 const struct _acl_list *a = NULL;
f88bb09c 194 aclCheck_t checklist;
ce66013b 195 assert(request != NULL);
79a15e0a 196 if (EBIT_TEST(request->flags, REQ_NOCACHE))
b69f7771 197 if (neighborType(p, request) == PEER_SIBLING)
24a1003d 198 return 0;
79a15e0a 199 if (EBIT_TEST(request->flags, REQ_REFRESH))
b69f7771 200 if (neighborType(p, request) == PEER_SIBLING)
d950cec8 201 return 0;
b69f7771 202 if (p->pinglist == NULL && p->acls == NULL)
090089c4 203 return do_ping;
090089c4 204 do_ping = 0;
b69f7771 205 for (d = p->pinglist; d; d = d->next) {
130faaed 206 if (matchDomainName(d->domain, request->host)) {
207 do_ping = d->do_ping;
208 break;
209 }
30a4f2a8 210 do_ping = !d->do_ping;
211 }
130faaed 212 if (0 == do_ping)
213 return do_ping;
8ae8bb05 214 checklist.src_addr = request->client_addr;
f88bb09c 215 checklist.request = request;
b69f7771 216 for (a = p->acls; a; a = a->next) {
130faaed 217 if (aclMatchAcl(a->acl, &checklist)) {
218 do_ping = a->op;
219 break;
220 }
30a4f2a8 221 do_ping = !a->op;
090089c4 222 }
223 return do_ping;
224}
225
62fd6124 226/* Return TRUE if it is okay to send an ICP request to this peer. */
227static int
b69f7771 228peerWouldBePinged(const peer * p, request_t * request)
62fd6124 229{
b69f7771 230 if (!peerAllowedToUse(p, request))
62fd6124 231 return 0;
a369131d 232 if (EBIT_TEST(p->options, NEIGHBOR_NO_QUERY))
62fd6124 233 return 0;
a369131d 234 if (EBIT_TEST(p->options, NEIGHBOR_MCAST_RESPONDER))
62fd6124 235 return 0;
236 /* the case below seems strange, but can happen if the
237 * URL host is on the other side of a firewall */
b69f7771 238 if (p->type == PEER_SIBLING)
79a15e0a 239 if (!EBIT_TEST(request->flags, REQ_HIERARCHICAL))
62fd6124 240 return 0;
b69f7771 241 if (p->icp_port == echo_port)
242 if (!neighborUp(p))
62fd6124 243 return 0;
b69f7771 244 if (p->n_addresses == 0)
dd4bd44e 245 return 0;
62fd6124 246 return 1;
247}
248
249/* Return TRUE if it is okay to send an HTTP request to this peer. */
250static int
b69f7771 251peerHTTPOkay(const peer * p, request_t * request)
62fd6124 252{
b69f7771 253 if (!peerAllowedToUse(p, request))
62fd6124 254 return 0;
b69f7771 255 if (!neighborUp(p))
62fd6124 256 return 0;
257 return 1;
258}
259
3c6e634f 260int
261neighborsCount(request_t * request)
090089c4 262{
b69f7771 263 peer *p = NULL;
090089c4 264 int count = 0;
40a1495e 265 for (p = Config.peers; p; p = p->next)
b69f7771 266 if (peerWouldBePinged(p, request))
3c6e634f 267 count++;
a3d5953d 268 debug(15, 3) ("neighborsCount: %d\n", count);
3c6e634f 269 return count;
270}
090089c4 271
deb79f06 272peer *
3c6e634f 273getSingleParent(request_t * request)
274{
deb79f06 275 peer *p = NULL;
b69f7771 276 peer *q = NULL;
40a1495e 277 for (q = Config.peers; q; q = q->next) {
b69f7771 278 if (!peerHTTPOkay(q, request))
caebbe00 279 continue;
b69f7771 280 if (neighborType(q, request) != PEER_PARENT)
3c6e634f 281 return NULL; /* oops, found SIBLING */
282 if (p)
283 return NULL; /* oops, found second parent */
b69f7771 284 p = q;
090089c4 285 }
a369131d 286 if (p != NULL && !EBIT_TEST(p->options, NEIGHBOR_NO_QUERY))
287 return NULL;
a3d5953d 288 debug(15, 3) ("getSingleParent: returning %s\n", p ? p->host : "NULL");
3c6e634f 289 return p;
090089c4 290}
291
deb79f06 292peer *
b8d8561b 293getFirstUpParent(request_t * request)
090089c4 294{
b69f7771 295 peer *p = NULL;
40a1495e 296 for (p = Config.peers; p; p = p->next) {
b69f7771 297 if (!neighborUp(p))
30a4f2a8 298 continue;
b69f7771 299 if (neighborType(p, request) != PEER_PARENT)
090089c4 300 continue;
b69f7771 301 if (!peerHTTPOkay(p, request))
e924600d 302 continue;
303 break;
090089c4 304 }
a3d5953d 305 debug(15, 3) ("getFirstUpParent: returning %s\n", p ? p->host : "NULL");
b69f7771 306 return p;
090089c4 307}
308
deb79f06 309peer *
48b38d01 310getRoundRobinParent(request_t * request)
311{
b69f7771 312 peer *p;
313 peer *q = NULL;
40a1495e 314 for (p = Config.peers; p; p = p->next) {
79a15e0a 315 if (!EBIT_TEST(p->options, NEIGHBOR_ROUNDROBIN))
0c8177e6 316 continue;
b69f7771 317 if (neighborType(p, request) != PEER_PARENT)
0c8177e6 318 continue;
b69f7771 319 if (!peerHTTPOkay(p, request))
48b38d01 320 continue;
b69f7771 321 if (q && q->rr_count < p->rr_count)
48b38d01 322 continue;
b69f7771 323 q = p;
48b38d01 324 }
b69f7771 325 if (q)
326 q->rr_count++;
a3d5953d 327 debug(15, 3) ("getRoundRobinParent: returning %s\n", q ? q->host : "NULL");
b69f7771 328 return q;
48b38d01 329}
330
deb79f06 331peer *
5269d0bd 332getDefaultParent(request_t * request)
333{
b69f7771 334 peer *p = NULL;
40a1495e 335 for (p = Config.peers; p; p = p->next) {
b69f7771 336 if (neighborType(p, request) != PEER_PARENT)
5269d0bd 337 continue;
79a15e0a 338 if (!EBIT_TEST(p->options, NEIGHBOR_DEFAULT_PARENT))
5269d0bd 339 continue;
b69f7771 340 if (!peerHTTPOkay(p, request))
5269d0bd 341 continue;
a3d5953d 342 debug(15, 3) ("getDefaultParent: returning %s\n", p->host);
b69f7771 343 return p;
5269d0bd 344 }
345 return NULL;
346}
347
deb79f06 348peer *
b69f7771 349getNextPeer(peer * p)
090089c4 350{
b69f7771 351 return p->next;
090089c4 352}
353
deb79f06 354peer *
355getFirstPeer(void)
090089c4 356{
40a1495e 357 return Config.peers;
090089c4 358}
359
b8d8561b 360static void
deb79f06 361neighborRemove(peer * target)
30a4f2a8 362{
b69f7771 363 peer *p = NULL;
364 peer **P = NULL;
40a1495e 365 p = Config.peers;
366 P = &Config.peers;
b69f7771 367 while (p) {
368 if (target == p)
30a4f2a8 369 break;
b69f7771 370 P = &p->next;
371 p = p->next;
372 }
373 if (p) {
374 *P = p->next;
b69f7771 375 peerDestroy(p);
40a1495e 376 Config.npeers--;
4d64d74a 377 }
40a1495e 378 first_ping = Config.peers;
4d64d74a 379}
380
b8d8561b 381void
382neighbors_open(int fd)
090089c4 383{
30a4f2a8 384 struct sockaddr_in name;
30a4f2a8 385 int len = sizeof(struct sockaddr_in);
30a4f2a8 386 struct servent *sep = NULL;
30a4f2a8 387 memset(&name, '\0', sizeof(struct sockaddr_in));
388 if (getsockname(fd, (struct sockaddr *) &name, &len) < 0)
a3d5953d 389 debug(15, 1) ("getsockname(%d,%p,%p) failed.\n", fd, &name, &len);
dd4bd44e 390 peerRefreshDNS(NULL);
30a4f2a8 391 if (0 == echo_hdr.opcode) {
27cd7235 392 echo_hdr.opcode = ICP_SECHO;
30a4f2a8 393 echo_hdr.version = ICP_VERSION_CURRENT;
394 echo_hdr.length = 0;
395 echo_hdr.reqnum = 0;
396 echo_hdr.flags = 0;
397 echo_hdr.pad = 0;
30a4f2a8 398 echo_hdr.shostid = name.sin_addr.s_addr;
399 sep = getservbyname("echo", "udp");
400 echo_port = sep ? ntohs((u_short) sep->s_port) : 7;
090089c4 401 }
c68e4e90 402 first_ping = Config.peers;
ed7f5615 403 cachemgrRegister("server_list",
404 "Peer Cache Statistics",
405 neighborDumpPeers, 0);
22f3fd98 406 cachemgrRegister("non_peers",
407 "List of Unknown sites sending ICP messages",
408 neighborDumpNonPeers, 0);
090089c4 409}
410
b8d8561b 411int
b6c0e933 412neighborsUdpPing(request_t * request,
641941c0 413 StoreEntry * entry,
582b6456 414 IRCB * callback,
641941c0 415 void *callback_data,
416 int *exprep)
090089c4 417{
9fb13bb6 418 const char *url = storeUrl(entry);
b6c0e933 419 MemObject *mem = entry->mem_obj;
b69f7771 420 peer *p = NULL;
090089c4 421 int i;
1061b406 422 int reqnum = 0;
6d2296d4 423 int flags;
9dee2904 424 icp_common_t *query;
429fdbec 425 int queries_sent = 0;
0a0bf5db 426 int peers_pinged = 0;
090089c4 427
40a1495e 428 if (Config.peers == NULL)
090089c4 429 return 0;
ce66013b 430 if (theOutIcpConnection < 0)
431 fatal("neighborsUdpPing: There is no ICP socket!");
9fb13bb6 432 assert(entry->swap_status == SWAPOUT_NONE);
b6c0e933 433 mem->start_ping = current_time;
434 mem->icp_reply_callback = callback;
435 mem->ircb_data = callback_data;
40a1495e 436 for (i = 0, p = first_ping; i++ < Config.npeers; p = p->next) {
b69f7771 437 if (p == NULL)
40a1495e 438 p = Config.peers;
a3d5953d 439 debug(15, 5) ("neighborsUdpPing: Peer %s\n", p->host);
b69f7771 440 if (!peerWouldBePinged(p, request))
deb79f06 441 continue; /* next peer */
0a0bf5db 442 peers_pinged++;
a3d5953d 443 debug(15, 4) ("neighborsUdpPing: pinging peer %s for '%s'\n",
b69f7771 444 p->host, url);
445 if (p->type == PEER_MULTICAST)
03a1ee42 446 mcastSetTtl(theOutIcpConnection, p->mcast.ttl);
9fb13bb6 447 reqnum = mem->reqnum;
3a4a63e7 448 debug(15, 3) ("neighborsUdpPing: key = '%s'\n", storeKeyText(entry->key));
a3d5953d 449 debug(15, 3) ("neighborsUdpPing: reqnum = %d\n", reqnum);
090089c4 450
dc9d133b 451#if USE_HTCP
e8d185d2 452 if (EBIT_TEST(p->options, NEIGHBOR_HTCP)) {
1afe05c5 453 debug(15, 0) ("neighborsUdpPing: sending HTCP query\n");
176ae152 454 htcpQuery(entry, request, p);
dc9d133b 455 } else
456#endif
1afe05c5 457 if (p->icp_port == echo_port) {
a3d5953d 458 debug(15, 4) ("neighborsUdpPing: Looks like a dumb cache, send DECHO ping\n");
1061b406 459 echo_hdr.reqnum = reqnum;
27cd7235 460 query = icpCreateMessage(ICP_DECHO, 0, url, reqnum, 0);
af00901c 461 icpUdpSend(theOutIcpConnection,
b69f7771 462 &p->in_addr,
9dee2904 463 query,
721b3dd8 464 LOG_ICP_QUERY,
aee4e794 465 0);
090089c4 466 } else {
6d2296d4 467 flags = 0;
17a0a4ee 468 if (Config.onoff.query_icmp)
b69f7771 469 if (p->icp_version == ICP_VERSION_2)
429fdbec 470 flags |= ICP_FLAG_SRC_RTT;
27cd7235 471 query = icpCreateMessage(ICP_QUERY, flags, url, reqnum, 0);
af00901c 472 icpUdpSend(theOutIcpConnection,
b69f7771 473 &p->in_addr,
9dee2904 474 query,
721b3dd8 475 LOG_ICP_QUERY,
aee4e794 476 0);
090089c4 477 }
429fdbec 478 queries_sent++;
090089c4 479
b69f7771 480 p->stats.pings_sent++;
b69f7771 481 if (p->type == PEER_MULTICAST) {
dc835977 482 /*
483 * set a bogus last_reply time so neighborUp() never
484 * says a multicast peer is dead.
485 */
486 p->stats.last_reply = squid_curtime;
b69f7771 487 (*exprep) += p->mcast.n_replies_expected;
ae95b16f 488 } else if (squid_curtime - p->stats.last_query > Config.Timeout.deadPeer) {
489 /*
490 * fake a recent reply if its been a long time since our
491 * last query
492 */
493 p->stats.last_reply = squid_curtime;
47b780e1 494 } else if (neighborUp(p)) {
495 /* its alive, expect a reply from it */
496 (*exprep)++;
090089c4 497 } else {
1061b406 498 /* Neighbor is dead; ping it anyway, but don't expect a reply */
090089c4 499 /* log it once at the threshold */
dc835977 500 if (p->stats.logged_state == PEER_ALIVE) {
ab4b78e9 501 debug(15, 1) ("Detected DEAD %s: %s/%d/%d\n",
b69f7771 502 neighborTypeStr(p),
503 p->host, p->http_port, p->icp_port);
dc835977 504 p->stats.logged_state = PEER_DEAD;
090089c4 505 }
506 }
dc835977 507 p->stats.last_query = squid_curtime;
090089c4 508 }
40a1495e 509 if ((first_ping = first_ping->next) == NULL)
510 first_ping = Config.peers;
090089c4 511
0ab965da 512#if ALLOW_SOURCE_PING
090089c4 513 /* only do source_ping if we have neighbors */
40a1495e 514 if (Config.npeers) {
a369131d 515 const ipcache_addrs *ia = NULL;
516 struct sockaddr_in to_addr;
517 char *host = request->host;
17a0a4ee 518 if (!Config.onoff.source_ping) {
a3d5953d 519 debug(15, 6) ("neighborsUdpPing: Source Ping is disabled.\n");
0a0bf5db 520 } else if ((ia = ipcache_gethostbyname(host, 0))) {
a3d5953d 521 debug(15, 6) ("neighborsUdpPing: Source Ping: to %s for '%s'\n",
1061b406 522 host, url);
1061b406 523 echo_hdr.reqnum = reqnum;
16b204c4 524 if (icmp_sock != -1) {
e5f6c5c2 525 icmpSourcePing(ia->in_addrs[ia->cur], &echo_hdr, url);
16b204c4 526 } else {
527 to_addr.sin_family = AF_INET;
e5f6c5c2 528 to_addr.sin_addr = ia->in_addrs[ia->cur];
16b204c4 529 to_addr.sin_port = htons(echo_port);
27cd7235 530 query = icpCreateMessage(ICP_SECHO, 0, url, reqnum, 0);
16b204c4 531 icpUdpSend(theOutIcpConnection,
16b204c4 532 &to_addr,
9dee2904 533 query,
721b3dd8 534 LOG_ICP_QUERY,
aee4e794 535 0);
16b204c4 536 }
090089c4 537 } else {
a3d5953d 538 debug(15, 6) ("neighborsUdpPing: Source Ping: unknown host: %s\n",
1061b406 539 host);
090089c4 540 }
541 }
0ab965da 542#endif
429fdbec 543#if LOG_ICP_NUMBERS
544 request->hierarchy.n_sent = peers_pinged;
545 request->hierarchy.n_expect = *exprep;
546#endif
0a0bf5db 547 return peers_pinged;
090089c4 548}
549
26b164ac 550/* lookup the digest of a given peer */
551lookup_t
552peerDigestLookup(peer *p, request_t * request, StoreEntry * entry)
553{
6cfa8966 554#if USE_CACHE_DIGESTS
0c511722 555 const cache_key *key = request ? storeKeyPublic(storeUrl(entry), request->method) : NULL;
26b164ac 556 assert(p);
0c511722 557 assert(request);
26b164ac 558 debug(15, 5) ("neighborsDigestPeerLookup: peer %s\n", p->host);
559 /* does the peeer have a valid digest? */
560 if (EBIT_TEST(p->digest.flags, PD_DISABLED)) {
561 return LOOKUP_NONE;
562 } else
563 if (!peerAllowedToUse(p, request)) {
564 return LOOKUP_NONE;
565 } else
566 if (EBIT_TEST(p->digest.flags, PD_USABLE)) {
567 /* fall through; put here to have common case on top */;
568 } else
569 if (!EBIT_TEST(p->digest.flags, PD_INITED)) {
570 peerDigestInit(p);
571 return LOOKUP_NONE;
572 } else {
573 assert(EBIT_TEST(p->digest.flags, PD_REQUESTED));
574 return LOOKUP_NONE;
575 }
576 debug(15, 5) ("neighborsDigestPeerLookup: OK to lookup peer %s\n", p->host);
577 assert(p->digest.cd);
578 /* does digest predict a hit? */
579 if (!cacheDigestTest(p->digest.cd, key))
580 return LOOKUP_MISS;
581 debug(15, 5) ("neighborsDigestPeerLookup: peer %s says HIT!\n", p->host);
582 return LOOKUP_HIT;
583#endif
584 return LOOKUP_NONE;
585}
586
587/* select best peer based on cache digests */
a54d3f8e 588peer *
589neighborsDigestSelect(request_t * request, StoreEntry * entry)
590{
591 peer *best_p = NULL;
6cfa8966 592#if USE_CACHE_DIGESTS
a54d3f8e 593 const cache_key *key;
594 int best_rtt = 0;
595 int choice_count = 0;
596 int ichoice_count = 0;
597 peer *p;
598 int p_rtt;
599 int i;
600
601 key = storeKeyPublic(storeUrl(entry), request->method);
602 for (i = 0, p = first_ping; i++ < Config.npeers; p = p->next) {
26b164ac 603 lookup_t lookup;
a54d3f8e 604 if (!p)
605 p = Config.peers;
606 if (i == 1)
607 first_ping = p;
26b164ac 608 lookup = peerDigestLookup(p, request, entry);
609 if (lookup == LOOKUP_NONE)
a54d3f8e 610 continue;
a54d3f8e 611 choice_count++;
26b164ac 612 if (lookup == LOOKUP_MISS)
a54d3f8e 613 continue;
26b164ac 614 p_rtt = netdbHostRtt(p->host);
615 debug(15, 5) ("neighborsDigestSelect: peer %s rtt: %d\n",
a54d3f8e 616 p->host, p_rtt);
617 /* is this peer better than others in terms of rtt ? */
618 if (!best_p || (p_rtt && p_rtt < best_rtt)) {
619 best_p = p;
620 best_rtt = p_rtt;
621 if (p_rtt) /* informative choice (aka educated guess) */
622 ichoice_count++;
623 debug(15, 4) ("neighborsDigestSelect: peer %s leads with rtt %d\n",
624 p->host, best_rtt);
625 }
626 }
26b164ac 627 debug(15, 4) ("neighborsDigestSelect: choices: %d (%d)\n",
628 choice_count, ichoice_count);
629 peerNoteDigestLookup(request, best_p,
630 best_p ? LOOKUP_HIT : (choice_count ? LOOKUP_MISS : LOOKUP_NONE));
a54d3f8e 631 request->hier.n_choices = choice_count;
632 request->hier.n_ichoices = ichoice_count;
633#endif
634 return best_p;
635}
636
26b164ac 637void
638peerNoteDigestLookup(request_t * request, peer *p, lookup_t lookup)
639{
6cfa8966 640#if USE_CACHE_DIGESTS
26b164ac 641 if (p)
642 strncpy(request->hier.cd_host, p->host, sizeof(request->hier.cd_host));
643 else
644 *request->hier.cd_host = '\0';
645 request->hier.cd_lookup = lookup;
646 debug(15, 4) ("peerNoteDigestLookup: peer %s, lookup: %s\n",
647 p ? p->host : "<none>", lookup_t_str[lookup]);
648#endif
649}
650
d73844ca 651static void
b69f7771 652neighborAlive(peer * p, const MemObject * mem, const icp_common_t * header)
4eda6afe 653{
654 int rtt;
655 int n;
39ac34a9 656 if (p->stats.logged_state == PEER_DEAD && p->tcp_up) {
ab4b78e9 657 debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n",
b69f7771 658 neighborTypeStr(p),
659 p->host, p->http_port, p->icp_port);
dc835977 660 p->stats.logged_state = PEER_ALIVE;
4eda6afe 661 }
dc835977 662 p->stats.last_reply = squid_curtime;
b69f7771 663 n = ++p->stats.pings_acked;
27cd7235 664 if ((icp_opcode) header->opcode <= ICP_END)
b69f7771 665 p->stats.counts[header->opcode]++;
4eda6afe 666 if (mem) {
667 rtt = tvSubMsec(mem->start_ping, current_time);
9e4ad609 668 p->stats.rtt = intAverage(p->stats.rtt, rtt, n, RTT_AV_FACTOR);
b69f7771 669 p->icp_version = (int) header->version;
4eda6afe 670 }
671}
090089c4 672
38792624 673static void
79d39a72 674neighborCountIgnored(peer * p, icp_opcode opnotused)
a7e59001 675{
b69f7771 676 if (p == NULL)
a7e59001 677 return;
b69f7771 678 p->stats.ignored_replies++;
c7a3724d 679 NLateReplies++;
a7e59001 680}
681
e102ebda 682static peer *non_peers = NULL;
683
684static void
685neighborIgnoreNonPeer(const struct sockaddr_in *from, icp_opcode opcode)
686{
687 peer *np;
688 double x;
689 for (np = non_peers; np; np = np->next) {
690 if (np->in_addr.sin_addr.s_addr != from->sin_addr.s_addr)
691 continue;
692 if (np->in_addr.sin_port != from->sin_port)
693 continue;
694 break;
695 }
696 if (np == NULL) {
697 np = xcalloc(1, sizeof(peer));
698 np->in_addr.sin_addr = from->sin_addr;
699 np->in_addr.sin_port = from->sin_port;
700 np->icp_port = ntohl(from->sin_port);
701 np->type = PEER_NONE;
702 np->host = xstrdup(inet_ntoa(from->sin_addr));
703 np->next = non_peers;
704 non_peers = np;
705 }
706 np->stats.ignored_replies++;
707 np->stats.counts[opcode]++;
708 x = log(np->stats.ignored_replies) / log(10.0);
709 if (0.0 != x - (double) (int) x)
710 return;
711 debug(15, 1) ("WARNING: Ignored %d replies from non-peer %s\n",
712 np->stats.ignored_replies, np->host);
713}
714
429fdbec 715/* ignoreMulticastReply
716 *
717 * We want to ignore replies from multicast peers if the
718 * cache_host_domain rules would normally prevent the peer
719 * from being used
720 */
721static int
b69f7771 722ignoreMulticastReply(peer * p, MemObject * mem)
429fdbec 723{
b69f7771 724 if (p == NULL)
429fdbec 725 return 0;
79a15e0a 726 if (!EBIT_TEST(p->options, NEIGHBOR_MCAST_RESPONDER))
429fdbec 727 return 0;
b69f7771 728 if (peerHTTPOkay(p, mem->request))
429fdbec 729 return 0;
730 return 1;
731}
732
733/* I should attach these records to the entry. We take the first
734 * hit we get our wait until everyone misses. The timeout handler
735 * call needs to nip this shopping list or call one of the misses.
736 *
737 * If a hit process is already started, then sobeit
738 */
b8d8561b 739void
5ad33356 740neighborsUdpAck(const cache_key * key, icp_common_t * header, const struct sockaddr_in *from)
090089c4 741{
b69f7771 742 peer *p = NULL;
5ad33356 743 StoreEntry *entry;
744 MemObject *mem = NULL;
b6c0e933 745 peer_t ntype = PEER_NONE;
5e5126cc 746 char *opcode_d;
a7e59001 747 icp_opcode opcode = (icp_opcode) header->opcode;
090089c4 748
5ad33356 749 debug(15, 6) ("neighborsUdpAck: opcode %d '%s'\n",
750 (int) opcode, storeKeyText(key));
751 if (NULL != (entry = storeGet(key)))
752 mem = entry->mem_obj;
b69f7771 753 if ((p = whichPeer(from)))
754 neighborAlive(p, mem, header);
27cd7235 755 if (opcode > ICP_END)
d2af9477 756 return;
27cd7235 757 opcode_d = icp_opcode_str[opcode];
5ad33356 758 /* Does the entry exist? */
759 if (NULL == entry) {
760 debug(12, 3) ("neighborsUdpAck: Cache key '%s' not found\n",
761 storeKeyText(key));
762 neighborCountIgnored(p, opcode);
763 return;
764 }
2d1c6a4f 765 /* check if someone is already fetching it */
79a15e0a 766 if (EBIT_TEST(entry->flag, ENTRY_DISPATCHED)) {
5ad33356 767 debug(15, 3) ("neighborsUdpAck: '%s' already being fetched.\n",
768 storeKeyText(key));
b69f7771 769 neighborCountIgnored(p, opcode);
d2af9477 770 return;
771 }
2d1c6a4f 772 if (mem == NULL) {
5ad33356 773 debug(15, 2) ("Ignoring %s for missing mem_obj: %s\n",
774 opcode_d, storeKeyText(key));
b69f7771 775 neighborCountIgnored(p, opcode);
8de2f7ad 776 return;
777 }
778 if (entry->ping_status != PING_WAITING) {
5ad33356 779 debug(15, 2) ("neighborsUdpAck: Unexpected %s for %s\n",
780 opcode_d, storeKeyText(key));
b69f7771 781 neighborCountIgnored(p, opcode);
8de2f7ad 782 return;
783 }
4eda6afe 784 if (entry->lock_count == 0) {
5ad33356 785 debug(12, 1) ("neighborsUdpAck: '%s' has no locks\n",
786 storeKeyText(key));
b69f7771 787 neighborCountIgnored(p, opcode);
4eda6afe 788 return;
090089c4 789 }
a3d5953d 790 debug(15, 3) ("neighborsUdpAck: %s for '%s' from %s \n",
5ad33356 791 opcode_d, storeKeyText(key), p ? p->host : "source");
b69f7771 792 if (p)
793 ntype = neighborType(p, mem->request);
794 if (ignoreMulticastReply(p, mem)) {
795 neighborCountIgnored(p, opcode);
27cd7235 796 } else if (opcode == ICP_SECHO) {
429fdbec 797 /* Received source-ping reply */
b69f7771 798 if (p) {
a3d5953d 799 debug(15, 1) ("Ignoring SECHO from neighbor %s\n", p->host);
b69f7771 800 neighborCountIgnored(p, opcode);
429fdbec 801 } else {
802 /* if we reach here, source-ping reply is the first 'parent',
803 * so fetch directly from the source */
a3d5953d 804 debug(15, 6) ("Source is the first to respond.\n");
b3264694 805 mem->icp_reply_callback(NULL, ntype, header, mem->ircb_data);
429fdbec 806 }
27cd7235 807 } else if (opcode == ICP_MISS) {
b69f7771 808 if (p == NULL) {
e102ebda 809 neighborIgnoreNonPeer(from, opcode);
d2af9477 810 } else {
b3264694 811 mem->icp_reply_callback(p, ntype, header, mem->ircb_data);
30a4f2a8 812 }
a7c05555 813 } else if (opcode == ICP_HIT) {
b69f7771 814 if (p == NULL) {
e102ebda 815 neighborIgnoreNonPeer(from, opcode);
d2af9477 816 } else {
27cd7235 817 header->opcode = ICP_HIT;
b3264694 818 mem->icp_reply_callback(p, ntype, header, mem->ircb_data);
090089c4 819 }
27cd7235 820 } else if (opcode == ICP_DECHO) {
b69f7771 821 if (p == NULL) {
e102ebda 822 neighborIgnoreNonPeer(from, opcode);
deb79f06 823 } else if (ntype == PEER_SIBLING) {
5e604a0e 824 debug_trap("neighborsUdpAck: Found non-ICP cache as SIBLING\n");
825 debug_trap("neighborsUdpAck: non-ICP neighbors must be a PARENT\n");
090089c4 826 } else {
b3264694 827 mem->icp_reply_callback(p, ntype, header, mem->ircb_data);
090089c4 828 }
27cd7235 829 } else if (opcode == ICP_SECHO) {
b69f7771 830 if (p) {
a3d5953d 831 debug(15, 1) ("Ignoring SECHO from neighbor %s\n", p->host);
b69f7771 832 neighborCountIgnored(p, opcode);
0ab965da 833#if ALLOW_SOURCE_PING
834 } else if (Config.onoff.source_ping) {
b3264694 835 mem->icp_reply_callback(NULL, ntype, header, mem->ircb_data);
0ab965da 836#endif
837 } else {
838 debug(15, 1) ("Unsolicited SECHO from %s\n", inet_ntoa(from->sin_addr));
090089c4 839 }
27cd7235 840 } else if (opcode == ICP_DENIED) {
b69f7771 841 if (p == NULL) {
e102ebda 842 neighborIgnoreNonPeer(from, opcode);
b69f7771 843 } else if (p->stats.pings_acked > 100) {
27cd7235 844 if (100 * p->stats.counts[ICP_DENIED] / p->stats.pings_acked > 95) {
a3d5953d 845 debug(15, 0) ("95%% of replies from '%s' are UDP_DENIED\n", p->host);
846 debug(15, 0) ("Disabling '%s', please check your configuration.\n", p->host);
b69f7771 847 neighborRemove(p);
848 p = NULL;
e006d372 849 } else {
b69f7771 850 neighborCountIgnored(p, opcode);
30a4f2a8 851 }
852 }
27cd7235 853 } else if (opcode == ICP_MISS_NOFETCH) {
b3264694 854 mem->icp_reply_callback(p, ntype, header, mem->ircb_data);
090089c4 855 } else {
a3d5953d 856 debug(15, 0) ("neighborsUdpAck: Unexpected ICP reply: %s\n", opcode_d);
d2af9477 857 }
090089c4 858}
859
deb79f06 860peer *
40a1495e 861peerFindByName(const char *name)
98ffb7e4 862{
b69f7771 863 peer *p = NULL;
40a1495e 864 for (p = Config.peers; p; p = p->next) {
b69f7771 865 if (!strcasecmp(name, p->host))
98ffb7e4 866 break;
867 }
b69f7771 868 return p;
98ffb7e4 869}
b012353a 870
5269d0bd 871int
b69f7771 872neighborUp(const peer * p)
5269d0bd 873{
b69f7771 874 if (!p->tcp_up)
e924600d 875 return 0;
ae95b16f 876 if (squid_curtime - p->stats.last_query > Config.Timeout.deadPeer)
dc835977 877 return 1;
878 if (p->stats.last_query - p->stats.last_reply >= Config.Timeout.deadPeer)
5269d0bd 879 return 0;
880 return 1;
881}
882
e6e3b09b 883void
b69f7771 884peerDestroy(peer * p)
e6e3b09b 885{
ee4a1f5d 886 struct _domain_ping *l = NULL;
887 struct _domain_ping *nl = NULL;
b69f7771 888 if (p == NULL)
3c6e634f 889 return;
b69f7771 890 if (p->type == PEER_MULTICAST) {
891 if (p->mcast.flags & PEER_COUNT_EVENT_PENDING)
892 eventDelete(peerCountMcastPeersStart, p);
893 if (p->mcast.flags & PEER_COUNTING)
894 eventDelete(peerCountMcastPeersDone, p);
895 }
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);
dd4bd44e 938}
939
940static void
79d39a72 941peerRefreshDNS(void *datanotused)
dd4bd44e 942{
b69f7771 943 peer *p = NULL;
40a1495e 944 peer *next = Config.peers;
79d39a72 945 while ((p = next) != NULL) {
b69f7771 946 next = p->next;
429fdbec 947 /* some random, bogus FD for ipcache */
03a1ee42 948 p->test_fd = Squid_MaxFD + current_time.tv_usec;
8407afee 949 ipcache_nbgethostbyname(p->host, peerDNSConfigure, p);
dd4bd44e 950 }
951 /* Reconfigure the peers every hour */
952 eventAdd("peerRefreshDNS", peerRefreshDNS, NULL, 3600);
953}
e924600d 954
955static void
956peerCheckConnect(void *data)
957{
958 peer *p = data;
959 int fd;
90e675a6 960 int valid = cbdataValid(p);
961 cbdataUnlock(p);
962 if (!valid)
963 return;
e924600d 964 fd = comm_open(SOCK_STREAM, 0, Config.Addrs.tcp_outgoing,
965 0, COMM_NONBLOCKING, p->host);
966 if (fd < 0)
967 return;
03a1ee42 968 p->test_fd = fd;
8407afee 969 ipcache_nbgethostbyname(p->host, peerCheckConnect2, p);
e924600d 970}
971
972static void
79d39a72 973peerCheckConnect2(const ipcache_addrs * ianotused, void *data)
e924600d 974{
975 peer *p = data;
03a1ee42 976 commConnectStart(p->test_fd,
e924600d 977 p->host,
978 p->http_port,
979 peerCheckConnectDone,
980 p);
981}
982
983static void
984peerCheckConnectDone(int fd, int status, void *data)
985{
986 peer *p = data;
987 p->tcp_up = status == COMM_OK ? 1 : 0;
988 if (p->tcp_up) {
a3d5953d 989 debug(15, 0) ("TCP connection to %s/%d succeeded\n",
e924600d 990 p->host, p->http_port);
991 } else {
90e675a6 992 cbdataLock(p);
e924600d 993 eventAdd("peerCheckConnect", peerCheckConnect, p, 80);
994 }
995 comm_close(fd);
996 return;
997}
998
999void
1000peerCheckConnectStart(peer * p)
1001{
1002 if (!p->tcp_up)
1003 return;
a3d5953d 1004 debug(15, 0) ("TCP connection to %s/%d failed\n", p->host, p->http_port);
e924600d 1005 p->tcp_up = 0;
1006 p->last_fail_time = squid_curtime;
90e675a6 1007 cbdataLock(p);
e924600d 1008 eventAdd("peerCheckConnect", peerCheckConnect, p, 80);
1009}
429fdbec 1010
1011static void
1012peerCountMcastPeersSchedule(peer * p, time_t when)
1013{
1014 if (p->mcast.flags & PEER_COUNT_EVENT_PENDING)
1015 return;
1016 eventAdd("peerCountMcastPeersStart",
1017 peerCountMcastPeersStart,
1018 p,
1019 when);
1020 p->mcast.flags |= PEER_COUNT_EVENT_PENDING;
1021}
1022
1023static void
1024peerCountMcastPeersStart(void *data)
1025{
1026 peer *p = data;
1027 ps_state *psstate = xcalloc(1, sizeof(ps_state));
1028 StoreEntry *fake;
1029 MemObject *mem;
1030 icp_common_t *query;
1031 LOCAL_ARRAY(char, url, MAX_URL);
ce66013b 1032 assert(p->type == PEER_MULTICAST);
429fdbec 1033 p->mcast.flags &= ~PEER_COUNT_EVENT_PENDING;
042461c3 1034 snprintf(url, MAX_URL, "http://%s/", inet_ntoa(p->in_addr.sin_addr));
88738790 1035 fake = storeCreateEntry(url, url, 0, METHOD_GET);
429fdbec 1036 psstate->request = requestLink(urlParse(METHOD_GET, url));
1037 psstate->entry = fake;
1038 psstate->callback = NULL;
1039 psstate->fail_callback = NULL;
1040 psstate->callback_data = p;
1041 psstate->icp.start = current_time;
1042 mem = fake->mem_obj;
2db609de 1043 mem->request = requestLink(psstate->request);
429fdbec 1044 mem->start_ping = current_time;
1045 mem->icp_reply_callback = peerCountHandleIcpReply;
1046 mem->ircb_data = psstate;
03a1ee42 1047 mcastSetTtl(theOutIcpConnection, p->mcast.ttl);
9fb13bb6 1048 p->mcast.reqnum = mem->reqnum;
27cd7235 1049 query = icpCreateMessage(ICP_QUERY, 0, url, p->mcast.reqnum, 0);
429fdbec 1050 icpUdpSend(theOutIcpConnection,
1051 &p->in_addr,
1052 query,
721b3dd8 1053 LOG_ICP_QUERY,
aee4e794 1054 0);
429fdbec 1055 fake->ping_status = PING_WAITING;
1056 eventAdd("peerCountMcastPeersDone",
1057 peerCountMcastPeersDone,
2db609de 1058 psstate,
429fdbec 1059 Config.neighborTimeout);
1060 p->mcast.flags |= PEER_COUNTING;
1061 peerCountMcastPeersSchedule(p, MCAST_COUNT_RATE);
1062}
1063
1064static void
1065peerCountMcastPeersDone(void *data)
1066{
1067 ps_state *psstate = data;
1068 peer *p = psstate->callback_data;
1069 StoreEntry *fake = psstate->entry;
429fdbec 1070 p->mcast.flags &= ~PEER_COUNTING;
9e4ad609 1071 p->mcast.avg_n_members = doubleAverage(p->mcast.avg_n_members,
1072 (double) psstate->icp.n_recv,
1073 ++p->mcast.n_times_counted,
1074 10);
a3d5953d 1075 debug(15, 1) ("Group %s: %d replies, %4.1f average\n",
429fdbec 1076 p->host,
1077 psstate->icp.n_recv,
1078 p->mcast.avg_n_members);
1079 p->mcast.n_replies_expected = (int) p->mcast.avg_n_members;
1080 fake->store_status = STORE_ABORTED;
e7a22b88 1081 requestUnlink(fake->mem_obj->request);
f0d5043e 1082 fake->mem_obj->request = NULL;
429fdbec 1083 storeReleaseRequest(fake);
1084 storeUnlockObject(fake);
e7a22b88 1085 requestUnlink(psstate->request);
2db609de 1086 xfree(psstate);
429fdbec 1087}
1088
1089static void
79d39a72 1090peerCountHandleIcpReply(peer * pnotused, peer_t type, icp_common_t * hdrnotused, void *data)
429fdbec 1091{
1092 ps_state *psstate = data;
1093 psstate->icp.n_recv++;
429fdbec 1094}
ed7f5615 1095
1096static void
1097neighborDumpPeers(StoreEntry * sentry)
1098{
1099 dump_peers(sentry, Config.peers);
1100}
1101
1102static void
1103neighborDumpNonPeers(StoreEntry * sentry)
1104{
1105 dump_peers(sentry, non_peers);
1106}
1107
a369131d 1108void
1109dump_peer_options(StoreEntry * sentry, peer * p)
1110{
1111 if (EBIT_TEST(p->options, NEIGHBOR_PROXY_ONLY))
1112 storeAppendPrintf(sentry, " proxy-only");
1113 if (EBIT_TEST(p->options, NEIGHBOR_NO_QUERY))
1114 storeAppendPrintf(sentry, " no-query");
8638fc66 1115 if (EBIT_TEST(p->options, NEIGHBOR_NO_DIGEST))
1116 storeAppendPrintf(sentry, " no-digest");
a369131d 1117 if (EBIT_TEST(p->options, NEIGHBOR_DEFAULT_PARENT))
1118 storeAppendPrintf(sentry, " default");
1119 if (EBIT_TEST(p->options, NEIGHBOR_ROUNDROBIN))
1120 storeAppendPrintf(sentry, " round-robin");
1121 if (EBIT_TEST(p->options, NEIGHBOR_MCAST_RESPONDER))
1122 storeAppendPrintf(sentry, " multicast-responder");
1123 if (EBIT_TEST(p->options, NEIGHBOR_CLOSEST_ONLY))
1124 storeAppendPrintf(sentry, " closest-only");
dc9d133b 1125#if USE_HTCP
e8d185d2 1126 if (EBIT_TEST(p->options, NEIGHBOR_HTCP))
1127 storeAppendPrintf(sentry, " htcp");
dc9d133b 1128#endif
a369131d 1129 if (p->mcast.ttl > 0)
1130 storeAppendPrintf(sentry, " ttl=%d", p->mcast.ttl);
1131 storeAppendPrintf(sentry, "\n");
1132}
1133
ed7f5615 1134static void
1135dump_peers(StoreEntry * sentry, peer * peers)
1136{
1137 peer *e = NULL;
1138 struct _domain_ping *d = NULL;
1139 icp_opcode op;
06e6d12a 1140 int i;
ed7f5615 1141 if (peers == NULL)
1142 storeAppendPrintf(sentry, "There are no neighbors installed.\n");
1143 for (e = peers; e; e = e->next) {
1144 assert(e->host != NULL);
1145 storeAppendPrintf(sentry, "\n%-11.11s: %s/%d/%d\n",
1146 neighborTypeStr(e),
1147 e->host,
1148 e->http_port,
1149 e->icp_port);
a369131d 1150 storeAppendPrintf(sentry, "Flags :");
1151 dump_peer_options(sentry, e);
06e6d12a 1152 for (i = 0; i < e->n_addresses; i++) {
1153 storeAppendPrintf(sentry, "Address[%d] : %s\n", i,
1154 inet_ntoa(e->addresses[i]));
1155 }
ed7f5615 1156 storeAppendPrintf(sentry, "Status : %s\n",
1157 neighborUp(e) ? "Up" : "Down");
1158 storeAppendPrintf(sentry, "AVG RTT : %d msec\n", e->stats.rtt);
1159 storeAppendPrintf(sentry, "LAST QUERY : %8d seconds ago\n",
1160 (int) (squid_curtime - e->stats.last_query));
1161 storeAppendPrintf(sentry, "LAST REPLY : %8d seconds ago\n",
1162 (int) (squid_curtime - e->stats.last_reply));
1163 storeAppendPrintf(sentry, "PINGS SENT : %8d\n", e->stats.pings_sent);
1164 storeAppendPrintf(sentry, "PINGS ACKED: %8d %3d%%\n",
1165 e->stats.pings_acked,
1166 percent(e->stats.pings_acked, e->stats.pings_sent));
1167 storeAppendPrintf(sentry, "FETCHES : %8d %3d%%\n",
1168 e->stats.fetches,
1169 percent(e->stats.fetches, e->stats.pings_acked));
1170 storeAppendPrintf(sentry, "IGNORED : %8d %3d%%\n",
1171 e->stats.ignored_replies,
1172 percent(e->stats.ignored_replies, e->stats.pings_acked));
1173 storeAppendPrintf(sentry, "Histogram of PINGS ACKED:\n");
1174 for (op = ICP_INVALID; op < ICP_END; op++) {
1175 if (e->stats.counts[op] == 0)
1176 continue;
1177 storeAppendPrintf(sentry, " %12.12s : %8d %3d%%\n",
1178 icp_opcode_str[op],
1179 e->stats.counts[op],
1180 percent(e->stats.counts[op], e->stats.pings_acked));
1181 }
1182 if (e->last_fail_time) {
1183 storeAppendPrintf(sentry, "Last failed connect() at: %s\n",
1184 mkhttpdlogtime(&(e->last_fail_time)));
1185 }
1186 if (e->pinglist != NULL)
1187 storeAppendPrintf(sentry, "DOMAIN LIST: ");
1188 for (d = e->pinglist; d; d = d->next) {
1189 if (d->do_ping)
1190 storeAppendPrintf(sentry, "%s ", d->domain);
1191 else
1192 storeAppendPrintf(sentry, "!%s ", d->domain);
1193 }
035f5831 1194 storeAppendPrintf(sentry, "\n");
ed7f5615 1195 storeAppendPrintf(sentry, "Keep-Alive Ratio: %d%%\n",
1196 percent(e->stats.n_keepalives_recv, e->stats.n_keepalives_sent));
1197 }
1198}