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