]> git.ipfire.org Git - thirdparty/squid.git/blame - src/neighbors.cc
FUM errors. we're accessing 'sc' after it gets freed by a callback.
[thirdparty/squid.git] / src / neighbors.cc
CommitLineData
22f3fd98 1
30a4f2a8 2/*
f720985e 3 * $Id: neighbors.cc,v 1.209 1998/05/14 20:48:05 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;
0e7b6b06 121static EVH peerCheckConnect;
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
4b4cd312 552peerDigestLookup(peer * p, request_t * request, StoreEntry * entry)
26b164ac 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);
69c95dd3 558 debug(15, 5) ("peerDigestLookup: peer %s\n", p->host);
4b4cd312 559 /* does the peeer have a valid digest? */
26b164ac 560 if (EBIT_TEST(p->digest.flags, PD_DISABLED)) {
69c95dd3 561 debug(15, 5) ("peerDigestLookup: Disabled!\n");
26b164ac 562 return LOOKUP_NONE;
4b4cd312 563 } else if (!peerAllowedToUse(p, request)) {
69c95dd3 564 debug(15, 5) ("peerDigestLookup: !peerAllowedToUse()\n");
26b164ac 565 return LOOKUP_NONE;
4b4cd312 566 } else if (EBIT_TEST(p->digest.flags, PD_USABLE)) {
69c95dd3 567 debug(15, 5) ("peerDigestLookup: Usable!\n");
4b4cd312 568 /* fall through; put here to have common case on top */ ;
569 } else if (!EBIT_TEST(p->digest.flags, PD_INITED)) {
69c95dd3 570 debug(15, 5) ("peerDigestLookup: !initialized\n");
571 if (!EBIT_TEST(p->digest.flags, PD_INIT_PENDING)) {
572 EBIT_SET(p->digest.flags, PD_INIT_PENDING);
573 eventAdd("peerDigestInit", peerDigestInit, p, 0);
574 }
26b164ac 575 return LOOKUP_NONE;
576 } else {
69c95dd3 577 debug(15, 5) ("peerDigestLookup: Whatever!\n");
26b164ac 578 return LOOKUP_NONE;
579 }
69c95dd3 580 debug(15, 5) ("peerDigestLookup: OK to lookup peer %s\n", p->host);
26b164ac 581 assert(p->digest.cd);
582 /* does digest predict a hit? */
583 if (!cacheDigestTest(p->digest.cd, key))
584 return LOOKUP_MISS;
69c95dd3 585 debug(15, 5) ("peerDigestLookup: peer %s says HIT!\n", p->host);
26b164ac 586 return LOOKUP_HIT;
587#endif
588 return LOOKUP_NONE;
589}
590
591/* select best peer based on cache digests */
a54d3f8e 592peer *
593neighborsDigestSelect(request_t * request, StoreEntry * entry)
594{
595 peer *best_p = NULL;
6cfa8966 596#if USE_CACHE_DIGESTS
a54d3f8e 597 const cache_key *key;
598 int best_rtt = 0;
599 int choice_count = 0;
600 int ichoice_count = 0;
601 peer *p;
602 int p_rtt;
603 int i;
604
605 key = storeKeyPublic(storeUrl(entry), request->method);
606 for (i = 0, p = first_ping; i++ < Config.npeers; p = p->next) {
26b164ac 607 lookup_t lookup;
a54d3f8e 608 if (!p)
609 p = Config.peers;
610 if (i == 1)
611 first_ping = p;
26b164ac 612 lookup = peerDigestLookup(p, request, entry);
613 if (lookup == LOOKUP_NONE)
a54d3f8e 614 continue;
a54d3f8e 615 choice_count++;
26b164ac 616 if (lookup == LOOKUP_MISS)
a54d3f8e 617 continue;
26b164ac 618 p_rtt = netdbHostRtt(p->host);
619 debug(15, 5) ("neighborsDigestSelect: peer %s rtt: %d\n",
a54d3f8e 620 p->host, p_rtt);
621 /* is this peer better than others in terms of rtt ? */
622 if (!best_p || (p_rtt && p_rtt < best_rtt)) {
623 best_p = p;
624 best_rtt = p_rtt;
4b4cd312 625 if (p_rtt) /* informative choice (aka educated guess) */
a54d3f8e 626 ichoice_count++;
627 debug(15, 4) ("neighborsDigestSelect: peer %s leads with rtt %d\n",
628 p->host, best_rtt);
629 }
630 }
26b164ac 631 debug(15, 4) ("neighborsDigestSelect: choices: %d (%d)\n",
632 choice_count, ichoice_count);
633 peerNoteDigestLookup(request, best_p,
634 best_p ? LOOKUP_HIT : (choice_count ? LOOKUP_MISS : LOOKUP_NONE));
a54d3f8e 635 request->hier.n_choices = choice_count;
636 request->hier.n_ichoices = ichoice_count;
637#endif
638 return best_p;
639}
640
26b164ac 641void
4b4cd312 642peerNoteDigestLookup(request_t * request, peer * p, lookup_t lookup)
26b164ac 643{
6cfa8966 644#if USE_CACHE_DIGESTS
26b164ac 645 if (p)
646 strncpy(request->hier.cd_host, p->host, sizeof(request->hier.cd_host));
647 else
648 *request->hier.cd_host = '\0';
649 request->hier.cd_lookup = lookup;
650 debug(15, 4) ("peerNoteDigestLookup: peer %s, lookup: %s\n",
651 p ? p->host : "<none>", lookup_t_str[lookup]);
652#endif
653}
654
d73844ca 655static void
b69f7771 656neighborAlive(peer * p, const MemObject * mem, const icp_common_t * header)
4eda6afe 657{
658 int rtt;
659 int n;
39ac34a9 660 if (p->stats.logged_state == PEER_DEAD && p->tcp_up) {
ab4b78e9 661 debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n",
b69f7771 662 neighborTypeStr(p),
663 p->host, p->http_port, p->icp_port);
dc835977 664 p->stats.logged_state = PEER_ALIVE;
4eda6afe 665 }
dc835977 666 p->stats.last_reply = squid_curtime;
b69f7771 667 n = ++p->stats.pings_acked;
27cd7235 668 if ((icp_opcode) header->opcode <= ICP_END)
b69f7771 669 p->stats.counts[header->opcode]++;
4eda6afe 670 if (mem) {
671 rtt = tvSubMsec(mem->start_ping, current_time);
9e4ad609 672 p->stats.rtt = intAverage(p->stats.rtt, rtt, n, RTT_AV_FACTOR);
b69f7771 673 p->icp_version = (int) header->version;
4eda6afe 674 }
675}
090089c4 676
38792624 677static void
79d39a72 678neighborCountIgnored(peer * p, icp_opcode opnotused)
a7e59001 679{
b69f7771 680 if (p == NULL)
a7e59001 681 return;
b69f7771 682 p->stats.ignored_replies++;
c7a3724d 683 NLateReplies++;
a7e59001 684}
685
e102ebda 686static peer *non_peers = NULL;
687
688static void
689neighborIgnoreNonPeer(const struct sockaddr_in *from, icp_opcode opcode)
690{
691 peer *np;
692 double x;
693 for (np = non_peers; np; np = np->next) {
694 if (np->in_addr.sin_addr.s_addr != from->sin_addr.s_addr)
695 continue;
696 if (np->in_addr.sin_port != from->sin_port)
697 continue;
698 break;
699 }
700 if (np == NULL) {
701 np = xcalloc(1, sizeof(peer));
702 np->in_addr.sin_addr = from->sin_addr;
703 np->in_addr.sin_port = from->sin_port;
704 np->icp_port = ntohl(from->sin_port);
705 np->type = PEER_NONE;
706 np->host = xstrdup(inet_ntoa(from->sin_addr));
707 np->next = non_peers;
708 non_peers = np;
709 }
710 np->stats.ignored_replies++;
711 np->stats.counts[opcode]++;
712 x = log(np->stats.ignored_replies) / log(10.0);
713 if (0.0 != x - (double) (int) x)
714 return;
715 debug(15, 1) ("WARNING: Ignored %d replies from non-peer %s\n",
716 np->stats.ignored_replies, np->host);
717}
718
429fdbec 719/* ignoreMulticastReply
720 *
721 * We want to ignore replies from multicast peers if the
722 * cache_host_domain rules would normally prevent the peer
723 * from being used
724 */
725static int
b69f7771 726ignoreMulticastReply(peer * p, MemObject * mem)
429fdbec 727{
b69f7771 728 if (p == NULL)
429fdbec 729 return 0;
79a15e0a 730 if (!EBIT_TEST(p->options, NEIGHBOR_MCAST_RESPONDER))
429fdbec 731 return 0;
b69f7771 732 if (peerHTTPOkay(p, mem->request))
429fdbec 733 return 0;
734 return 1;
735}
736
737/* I should attach these records to the entry. We take the first
738 * hit we get our wait until everyone misses. The timeout handler
739 * call needs to nip this shopping list or call one of the misses.
740 *
741 * If a hit process is already started, then sobeit
742 */
b8d8561b 743void
5ad33356 744neighborsUdpAck(const cache_key * key, icp_common_t * header, const struct sockaddr_in *from)
090089c4 745{
b69f7771 746 peer *p = NULL;
5ad33356 747 StoreEntry *entry;
748 MemObject *mem = NULL;
b6c0e933 749 peer_t ntype = PEER_NONE;
5e5126cc 750 char *opcode_d;
a7e59001 751 icp_opcode opcode = (icp_opcode) header->opcode;
090089c4 752
5ad33356 753 debug(15, 6) ("neighborsUdpAck: opcode %d '%s'\n",
754 (int) opcode, storeKeyText(key));
755 if (NULL != (entry = storeGet(key)))
756 mem = entry->mem_obj;
b69f7771 757 if ((p = whichPeer(from)))
758 neighborAlive(p, mem, header);
27cd7235 759 if (opcode > ICP_END)
d2af9477 760 return;
27cd7235 761 opcode_d = icp_opcode_str[opcode];
5ad33356 762 /* Does the entry exist? */
763 if (NULL == entry) {
764 debug(12, 3) ("neighborsUdpAck: Cache key '%s' not found\n",
765 storeKeyText(key));
766 neighborCountIgnored(p, opcode);
767 return;
768 }
2d1c6a4f 769 /* check if someone is already fetching it */
79a15e0a 770 if (EBIT_TEST(entry->flag, ENTRY_DISPATCHED)) {
5ad33356 771 debug(15, 3) ("neighborsUdpAck: '%s' already being fetched.\n",
772 storeKeyText(key));
b69f7771 773 neighborCountIgnored(p, opcode);
d2af9477 774 return;
775 }
2d1c6a4f 776 if (mem == NULL) {
5ad33356 777 debug(15, 2) ("Ignoring %s for missing mem_obj: %s\n",
778 opcode_d, storeKeyText(key));
b69f7771 779 neighborCountIgnored(p, opcode);
8de2f7ad 780 return;
781 }
782 if (entry->ping_status != PING_WAITING) {
5ad33356 783 debug(15, 2) ("neighborsUdpAck: Unexpected %s for %s\n",
784 opcode_d, storeKeyText(key));
b69f7771 785 neighborCountIgnored(p, opcode);
8de2f7ad 786 return;
787 }
4eda6afe 788 if (entry->lock_count == 0) {
5ad33356 789 debug(12, 1) ("neighborsUdpAck: '%s' has no locks\n",
790 storeKeyText(key));
b69f7771 791 neighborCountIgnored(p, opcode);
4eda6afe 792 return;
090089c4 793 }
a3d5953d 794 debug(15, 3) ("neighborsUdpAck: %s for '%s' from %s \n",
5ad33356 795 opcode_d, storeKeyText(key), p ? p->host : "source");
b69f7771 796 if (p)
797 ntype = neighborType(p, mem->request);
798 if (ignoreMulticastReply(p, mem)) {
799 neighborCountIgnored(p, opcode);
27cd7235 800 } else if (opcode == ICP_SECHO) {
429fdbec 801 /* Received source-ping reply */
b69f7771 802 if (p) {
a3d5953d 803 debug(15, 1) ("Ignoring SECHO from neighbor %s\n", p->host);
b69f7771 804 neighborCountIgnored(p, opcode);
429fdbec 805 } else {
806 /* if we reach here, source-ping reply is the first 'parent',
807 * so fetch directly from the source */
a3d5953d 808 debug(15, 6) ("Source is the first to respond.\n");
b3264694 809 mem->icp_reply_callback(NULL, ntype, header, mem->ircb_data);
429fdbec 810 }
27cd7235 811 } else if (opcode == ICP_MISS) {
b69f7771 812 if (p == NULL) {
e102ebda 813 neighborIgnoreNonPeer(from, opcode);
d2af9477 814 } else {
b3264694 815 mem->icp_reply_callback(p, ntype, header, mem->ircb_data);
30a4f2a8 816 }
a7c05555 817 } else if (opcode == ICP_HIT) {
b69f7771 818 if (p == NULL) {
e102ebda 819 neighborIgnoreNonPeer(from, opcode);
d2af9477 820 } else {
27cd7235 821 header->opcode = ICP_HIT;
b3264694 822 mem->icp_reply_callback(p, ntype, header, mem->ircb_data);
090089c4 823 }
27cd7235 824 } else if (opcode == ICP_DECHO) {
b69f7771 825 if (p == NULL) {
e102ebda 826 neighborIgnoreNonPeer(from, opcode);
deb79f06 827 } else if (ntype == PEER_SIBLING) {
5e604a0e 828 debug_trap("neighborsUdpAck: Found non-ICP cache as SIBLING\n");
829 debug_trap("neighborsUdpAck: non-ICP neighbors must be a PARENT\n");
090089c4 830 } else {
b3264694 831 mem->icp_reply_callback(p, ntype, header, mem->ircb_data);
090089c4 832 }
27cd7235 833 } else if (opcode == ICP_SECHO) {
b69f7771 834 if (p) {
a3d5953d 835 debug(15, 1) ("Ignoring SECHO from neighbor %s\n", p->host);
b69f7771 836 neighborCountIgnored(p, opcode);
0ab965da 837#if ALLOW_SOURCE_PING
838 } else if (Config.onoff.source_ping) {
b3264694 839 mem->icp_reply_callback(NULL, ntype, header, mem->ircb_data);
0ab965da 840#endif
841 } else {
842 debug(15, 1) ("Unsolicited SECHO from %s\n", inet_ntoa(from->sin_addr));
090089c4 843 }
27cd7235 844 } else if (opcode == ICP_DENIED) {
b69f7771 845 if (p == NULL) {
e102ebda 846 neighborIgnoreNonPeer(from, opcode);
b69f7771 847 } else if (p->stats.pings_acked > 100) {
27cd7235 848 if (100 * p->stats.counts[ICP_DENIED] / p->stats.pings_acked > 95) {
a3d5953d 849 debug(15, 0) ("95%% of replies from '%s' are UDP_DENIED\n", p->host);
850 debug(15, 0) ("Disabling '%s', please check your configuration.\n", p->host);
b69f7771 851 neighborRemove(p);
852 p = NULL;
e006d372 853 } else {
b69f7771 854 neighborCountIgnored(p, opcode);
30a4f2a8 855 }
856 }
27cd7235 857 } else if (opcode == ICP_MISS_NOFETCH) {
b3264694 858 mem->icp_reply_callback(p, ntype, header, mem->ircb_data);
090089c4 859 } else {
a3d5953d 860 debug(15, 0) ("neighborsUdpAck: Unexpected ICP reply: %s\n", opcode_d);
d2af9477 861 }
090089c4 862}
863
deb79f06 864peer *
40a1495e 865peerFindByName(const char *name)
98ffb7e4 866{
b69f7771 867 peer *p = NULL;
40a1495e 868 for (p = Config.peers; p; p = p->next) {
b69f7771 869 if (!strcasecmp(name, p->host))
98ffb7e4 870 break;
871 }
b69f7771 872 return p;
98ffb7e4 873}
b012353a 874
5269d0bd 875int
b69f7771 876neighborUp(const peer * p)
5269d0bd 877{
b69f7771 878 if (!p->tcp_up)
e924600d 879 return 0;
ae95b16f 880 if (squid_curtime - p->stats.last_query > Config.Timeout.deadPeer)
dc835977 881 return 1;
882 if (p->stats.last_query - p->stats.last_reply >= Config.Timeout.deadPeer)
5269d0bd 883 return 0;
884 return 1;
885}
886
e6e3b09b 887void
b69f7771 888peerDestroy(peer * p)
e6e3b09b 889{
ee4a1f5d 890 struct _domain_ping *l = NULL;
891 struct _domain_ping *nl = NULL;
b69f7771 892 if (p == NULL)
3c6e634f 893 return;
b69f7771 894 if (p->type == PEER_MULTICAST) {
895 if (p->mcast.flags & PEER_COUNT_EVENT_PENDING)
896 eventDelete(peerCountMcastPeersStart, p);
897 if (p->mcast.flags & PEER_COUNTING)
898 eventDelete(peerCountMcastPeersDone, p);
899 }
900 for (l = p->pinglist; l; l = nl) {
ee4a1f5d 901 nl = l->next;
902 safe_free(l->domain);
903 safe_free(l);
904 }
b69f7771 905 safe_free(p->host);
8407afee 906 cbdataFree(p);
e6e3b09b 907}
c7a3724d 908
dd4bd44e 909static void
03a1ee42 910peerDNSConfigure(const ipcache_addrs * ia, void *data)
dd4bd44e 911{
b69f7771 912 peer *p = data;
dd4bd44e 913 struct sockaddr_in *ap;
914 int j;
b69f7771 915 if (p->n_addresses == 0) {
a3d5953d 916 debug(15, 1) ("Configuring %s %s/%d/%d\n", neighborTypeStr(p),
b69f7771 917 p->host, p->http_port, p->icp_port);
918 if (p->type == PEER_MULTICAST)
a3d5953d 919 debug(15, 1) (" Multicast TTL = %d\n", p->mcast.ttl);
b69f7771 920 }
921 p->n_addresses = 0;
dd4bd44e 922 if (ia == NULL) {
a3d5953d 923 debug(0, 0) ("WARNING: DNS lookup for '%s' failed!\n", p->host);
dd4bd44e 924 return;
925 }
c04fe656 926 if ((int) ia->count < 1) {
a3d5953d 927 debug(0, 0) ("WARNING: No IP address found for '%s'!\n", p->host);
dd4bd44e 928 return;
929 }
c04fe656 930 for (j = 0; j < (int) ia->count && j < PEER_MAX_ADDRESSES; j++) {
b69f7771 931 p->addresses[j] = ia->in_addrs[j];
a3d5953d 932 debug(15, 2) ("--> IP address #%d: %s\n", j, inet_ntoa(p->addresses[j]));
b69f7771 933 p->n_addresses++;
dd4bd44e 934 }
b69f7771 935 ap = &p->in_addr;
dd4bd44e 936 memset(ap, '\0', sizeof(struct sockaddr_in));
937 ap->sin_family = AF_INET;
b69f7771 938 ap->sin_addr = p->addresses[0];
939 ap->sin_port = htons(p->icp_port);
940 if (p->type == PEER_MULTICAST)
941 peerCountMcastPeersSchedule(p, 10);
f720985e 942 eventAddIsh("netdbExchangeStart", netdbExchangeStart, p, 30, 1);
dd4bd44e 943}
944
945static void
79d39a72 946peerRefreshDNS(void *datanotused)
dd4bd44e 947{
b69f7771 948 peer *p = NULL;
40a1495e 949 peer *next = Config.peers;
79d39a72 950 while ((p = next) != NULL) {
b69f7771 951 next = p->next;
429fdbec 952 /* some random, bogus FD for ipcache */
03a1ee42 953 p->test_fd = Squid_MaxFD + current_time.tv_usec;
8407afee 954 ipcache_nbgethostbyname(p->host, peerDNSConfigure, p);
dd4bd44e 955 }
956 /* Reconfigure the peers every hour */
f720985e 957 eventAddIsh("peerRefreshDNS", peerRefreshDNS, NULL, 3600, 1);
dd4bd44e 958}
e924600d 959
0e7b6b06 960/*
961 * peerCheckConnect will NOT be called by eventRun if the peer/data
962 * pointer becomes invalid.
963 */
e924600d 964static void
965peerCheckConnect(void *data)
966{
967 peer *p = data;
968 int fd;
969 fd = comm_open(SOCK_STREAM, 0, Config.Addrs.tcp_outgoing,
970 0, COMM_NONBLOCKING, p->host);
971 if (fd < 0)
972 return;
03a1ee42 973 p->test_fd = fd;
8407afee 974 ipcache_nbgethostbyname(p->host, peerCheckConnect2, p);
e924600d 975}
976
977static void
79d39a72 978peerCheckConnect2(const ipcache_addrs * ianotused, void *data)
e924600d 979{
980 peer *p = data;
03a1ee42 981 commConnectStart(p->test_fd,
e924600d 982 p->host,
983 p->http_port,
984 peerCheckConnectDone,
985 p);
986}
987
988static void
989peerCheckConnectDone(int fd, int status, void *data)
990{
991 peer *p = data;
992 p->tcp_up = status == COMM_OK ? 1 : 0;
993 if (p->tcp_up) {
a3d5953d 994 debug(15, 0) ("TCP connection to %s/%d succeeded\n",
e924600d 995 p->host, p->http_port);
996 } else {
f720985e 997 eventAdd("peerCheckConnect", peerCheckConnect, p, 80, 1);
e924600d 998 }
999 comm_close(fd);
1000 return;
1001}
1002
1003void
1004peerCheckConnectStart(peer * p)
1005{
1006 if (!p->tcp_up)
1007 return;
a3d5953d 1008 debug(15, 0) ("TCP connection to %s/%d failed\n", p->host, p->http_port);
e924600d 1009 p->tcp_up = 0;
1010 p->last_fail_time = squid_curtime;
f720985e 1011 eventAdd("peerCheckConnect", peerCheckConnect, p, 80, 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,
f720985e 1022 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;
1045 mem = fake->mem_obj;
2db609de 1046 mem->request = requestLink(psstate->request);
429fdbec 1047 mem->start_ping = current_time;
1048 mem->icp_reply_callback = peerCountHandleIcpReply;
1049 mem->ircb_data = psstate;
03a1ee42 1050 mcastSetTtl(theOutIcpConnection, p->mcast.ttl);
9fb13bb6 1051 p->mcast.reqnum = mem->reqnum;
27cd7235 1052 query = icpCreateMessage(ICP_QUERY, 0, url, p->mcast.reqnum, 0);
429fdbec 1053 icpUdpSend(theOutIcpConnection,
1054 &p->in_addr,
1055 query,
721b3dd8 1056 LOG_ICP_QUERY,
aee4e794 1057 0);
429fdbec 1058 fake->ping_status = PING_WAITING;
1059 eventAdd("peerCountMcastPeersDone",
1060 peerCountMcastPeersDone,
2db609de 1061 psstate,
f720985e 1062 Config.neighborTimeout, 1);
429fdbec 1063 p->mcast.flags |= PEER_COUNTING;
1064 peerCountMcastPeersSchedule(p, MCAST_COUNT_RATE);
1065}
1066
1067static void
1068peerCountMcastPeersDone(void *data)
1069{
1070 ps_state *psstate = data;
1071 peer *p = psstate->callback_data;
1072 StoreEntry *fake = psstate->entry;
429fdbec 1073 p->mcast.flags &= ~PEER_COUNTING;
9e4ad609 1074 p->mcast.avg_n_members = doubleAverage(p->mcast.avg_n_members,
1075 (double) psstate->icp.n_recv,
1076 ++p->mcast.n_times_counted,
1077 10);
a3d5953d 1078 debug(15, 1) ("Group %s: %d replies, %4.1f average\n",
429fdbec 1079 p->host,
1080 psstate->icp.n_recv,
1081 p->mcast.avg_n_members);
1082 p->mcast.n_replies_expected = (int) p->mcast.avg_n_members;
1083 fake->store_status = STORE_ABORTED;
e7a22b88 1084 requestUnlink(fake->mem_obj->request);
f0d5043e 1085 fake->mem_obj->request = NULL;
429fdbec 1086 storeReleaseRequest(fake);
1087 storeUnlockObject(fake);
e7a22b88 1088 requestUnlink(psstate->request);
2db609de 1089 xfree(psstate);
429fdbec 1090}
1091
1092static void
79d39a72 1093peerCountHandleIcpReply(peer * pnotused, peer_t type, icp_common_t * hdrnotused, void *data)
429fdbec 1094{
1095 ps_state *psstate = data;
1096 psstate->icp.n_recv++;
429fdbec 1097}
ed7f5615 1098
1099static void
1100neighborDumpPeers(StoreEntry * sentry)
1101{
1102 dump_peers(sentry, Config.peers);
1103}
1104
1105static void
1106neighborDumpNonPeers(StoreEntry * sentry)
1107{
1108 dump_peers(sentry, non_peers);
1109}
1110
a369131d 1111void
1112dump_peer_options(StoreEntry * sentry, peer * p)
1113{
1114 if (EBIT_TEST(p->options, NEIGHBOR_PROXY_ONLY))
1115 storeAppendPrintf(sentry, " proxy-only");
1116 if (EBIT_TEST(p->options, NEIGHBOR_NO_QUERY))
1117 storeAppendPrintf(sentry, " no-query");
8638fc66 1118 if (EBIT_TEST(p->options, NEIGHBOR_NO_DIGEST))
1119 storeAppendPrintf(sentry, " no-digest");
a369131d 1120 if (EBIT_TEST(p->options, NEIGHBOR_DEFAULT_PARENT))
1121 storeAppendPrintf(sentry, " default");
1122 if (EBIT_TEST(p->options, NEIGHBOR_ROUNDROBIN))
1123 storeAppendPrintf(sentry, " round-robin");
1124 if (EBIT_TEST(p->options, NEIGHBOR_MCAST_RESPONDER))
1125 storeAppendPrintf(sentry, " multicast-responder");
1126 if (EBIT_TEST(p->options, NEIGHBOR_CLOSEST_ONLY))
1127 storeAppendPrintf(sentry, " closest-only");
dc9d133b 1128#if USE_HTCP
e8d185d2 1129 if (EBIT_TEST(p->options, NEIGHBOR_HTCP))
1130 storeAppendPrintf(sentry, " htcp");
dc9d133b 1131#endif
a369131d 1132 if (p->mcast.ttl > 0)
1133 storeAppendPrintf(sentry, " ttl=%d", p->mcast.ttl);
1134 storeAppendPrintf(sentry, "\n");
1135}
1136
ed7f5615 1137static void
1138dump_peers(StoreEntry * sentry, peer * peers)
1139{
1140 peer *e = NULL;
1141 struct _domain_ping *d = NULL;
1142 icp_opcode op;
06e6d12a 1143 int i;
ed7f5615 1144 if (peers == NULL)
1145 storeAppendPrintf(sentry, "There are no neighbors installed.\n");
1146 for (e = peers; e; e = e->next) {
1147 assert(e->host != NULL);
1148 storeAppendPrintf(sentry, "\n%-11.11s: %s/%d/%d\n",
1149 neighborTypeStr(e),
1150 e->host,
1151 e->http_port,
1152 e->icp_port);
a369131d 1153 storeAppendPrintf(sentry, "Flags :");
1154 dump_peer_options(sentry, e);
06e6d12a 1155 for (i = 0; i < e->n_addresses; i++) {
1156 storeAppendPrintf(sentry, "Address[%d] : %s\n", i,
1157 inet_ntoa(e->addresses[i]));
1158 }
ed7f5615 1159 storeAppendPrintf(sentry, "Status : %s\n",
1160 neighborUp(e) ? "Up" : "Down");
1161 storeAppendPrintf(sentry, "AVG RTT : %d msec\n", e->stats.rtt);
1162 storeAppendPrintf(sentry, "LAST QUERY : %8d seconds ago\n",
1163 (int) (squid_curtime - e->stats.last_query));
1164 storeAppendPrintf(sentry, "LAST REPLY : %8d seconds ago\n",
1165 (int) (squid_curtime - e->stats.last_reply));
1166 storeAppendPrintf(sentry, "PINGS SENT : %8d\n", e->stats.pings_sent);
1167 storeAppendPrintf(sentry, "PINGS ACKED: %8d %3d%%\n",
1168 e->stats.pings_acked,
1169 percent(e->stats.pings_acked, e->stats.pings_sent));
1170 storeAppendPrintf(sentry, "FETCHES : %8d %3d%%\n",
1171 e->stats.fetches,
1172 percent(e->stats.fetches, e->stats.pings_acked));
1173 storeAppendPrintf(sentry, "IGNORED : %8d %3d%%\n",
1174 e->stats.ignored_replies,
1175 percent(e->stats.ignored_replies, e->stats.pings_acked));
1176 storeAppendPrintf(sentry, "Histogram of PINGS ACKED:\n");
1177 for (op = ICP_INVALID; op < ICP_END; op++) {
1178 if (e->stats.counts[op] == 0)
1179 continue;
1180 storeAppendPrintf(sentry, " %12.12s : %8d %3d%%\n",
1181 icp_opcode_str[op],
1182 e->stats.counts[op],
1183 percent(e->stats.counts[op], e->stats.pings_acked));
1184 }
1185 if (e->last_fail_time) {
1186 storeAppendPrintf(sentry, "Last failed connect() at: %s\n",
1187 mkhttpdlogtime(&(e->last_fail_time)));
1188 }
1189 if (e->pinglist != NULL)
1190 storeAppendPrintf(sentry, "DOMAIN LIST: ");
1191 for (d = e->pinglist; d; d = d->next) {
1192 if (d->do_ping)
1193 storeAppendPrintf(sentry, "%s ", d->domain);
1194 else
1195 storeAppendPrintf(sentry, "!%s ", d->domain);
1196 }
035f5831 1197 storeAppendPrintf(sentry, "\n");
99edd1c3 1198 storeAppendPrintf(sentry, "keep-alive ratio: %d%%\n",
ed7f5615 1199 percent(e->stats.n_keepalives_recv, e->stats.n_keepalives_sent));
1200 }
1201}