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