3 * $Id: neighbors.cc,v 1.277 1999/12/30 17:36:43 wessels Exp $
5 * DEBUG: section 15 Neighbor Routines
6 * AUTHOR: Harvest Derived
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
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 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.
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.
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.
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
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
38 /* count mcast group peers every 15 minutes */
39 #define MCAST_COUNT_RATE 900
41 static int peerAllowedToUse(const peer
*, request_t
*);
42 static int peerWouldBePinged(const peer
*, request_t
*);
43 static void neighborRemove(peer
*);
44 static void neighborAlive(peer
*, const MemObject
*, const icp_common_t
*);
46 static void neighborAliveHtcp(peer
*, const MemObject
*, const htcpReplyData
*);
48 static void neighborCountIgnored(peer
*);
49 static void peerRefreshDNS(void *);
50 static IPH peerDNSConfigure
;
51 static EVH peerCheckConnect
;
52 static IPH peerCheckConnect2
;
53 static CNCB peerCheckConnectDone
;
54 static void peerCountMcastPeersDone(void *data
);
55 static void peerCountMcastPeersStart(void *data
);
56 static void peerCountMcastPeersSchedule(peer
* p
, time_t when
);
57 static IRCB peerCountHandleIcpReply
;
58 static void neighborIgnoreNonPeer(const struct sockaddr_in
*, icp_opcode
);
59 static OBJH neighborDumpPeers
;
60 static OBJH neighborDumpNonPeers
;
61 static void dump_peers(StoreEntry
* sentry
, peer
* peers
);
63 static icp_common_t echo_hdr
;
64 static u_short echo_port
;
66 static int NLateReplies
= 0;
67 static peer
*first_ping
= NULL
;
70 neighborTypeStr(const peer
* p
)
72 if (p
->type
== PEER_NONE
)
74 if (p
->type
== PEER_SIBLING
)
76 if (p
->type
== PEER_MULTICAST
)
77 return "Multicast Group";
83 whichPeer(const struct sockaddr_in
* from
)
86 u_short port
= ntohs(from
->sin_port
);
87 struct in_addr ip
= from
->sin_addr
;
89 debug(15, 3) ("whichPeer: from %s port %d\n", inet_ntoa(ip
), port
);
90 for (p
= Config
.peers
; p
; p
= p
->next
) {
91 for (j
= 0; j
< p
->n_addresses
; j
++) {
92 if (ip
.s_addr
== p
->addresses
[j
].s_addr
&& port
== p
->icp
.port
) {
101 neighborType(const peer
* p
, const request_t
* request
)
103 const struct _domain_type
*d
= NULL
;
104 for (d
= p
->typelist
; d
; d
= d
->next
) {
105 if (0 == matchDomainName(request
->host
, d
->domain
))
106 if (d
->type
!= PEER_NONE
)
115 * this function figures out if it is appropriate to fetch REQUEST
119 peerAllowedToUse(const peer
* p
, request_t
* request
)
121 const struct _domain_ping
*d
= NULL
;
123 aclCheck_t checklist
;
124 assert(request
!= NULL
);
125 if (neighborType(p
, request
) == PEER_SIBLING
) {
126 if (request
->flags
.nocache
)
128 if (request
->flags
.refresh
)
130 if (request
->flags
.loopdetect
)
132 if (request
->flags
.need_validation
)
135 if (p
->peer_domain
== NULL
&& p
->access
== NULL
)
138 for (d
= p
->peer_domain
; d
; d
= d
->next
) {
139 if (0 == matchDomainName(request
->host
, d
->domain
)) {
140 do_ping
= d
->do_ping
;
143 do_ping
= !d
->do_ping
;
145 if (p
->peer_domain
&& 0 == do_ping
)
147 if (p
->access
== NULL
)
149 checklist
.src_addr
= request
->client_addr
;
150 checklist
.my_addr
= request
->my_addr
;
151 checklist
.my_port
= request
->my_port
;
152 checklist
.request
= request
;
153 return aclCheckFast(p
->access
, &checklist
);
156 /* Return TRUE if it is okay to send an ICP request to this peer. */
158 peerWouldBePinged(const peer
* p
, request_t
* request
)
160 if (!peerAllowedToUse(p
, request
))
162 if (p
->options
.no_query
)
164 if (p
->options
.mcast_responder
)
166 /* the case below seems strange, but can happen if the
167 * URL host is on the other side of a firewall */
168 if (p
->type
== PEER_SIBLING
)
169 if (!request
->flags
.hierarchical
)
171 if (p
->icp
.port
== echo_port
)
174 if (p
->n_addresses
== 0)
179 /* Return TRUE if it is okay to send an HTTP request to this peer. */
181 peerHTTPOkay(const peer
* p
, request_t
* request
)
183 if (!peerAllowedToUse(p
, request
))
191 neighborsCount(request_t
* request
)
195 for (p
= Config
.peers
; p
; p
= p
->next
)
196 if (peerWouldBePinged(p
, request
))
198 debug(15, 3) ("neighborsCount: %d\n", count
);
203 getSingleParent(request_t
* request
)
207 for (q
= Config
.peers
; q
; q
= q
->next
) {
208 if (!peerHTTPOkay(q
, request
))
210 if (neighborType(q
, request
) != PEER_PARENT
)
211 return NULL
; /* oops, found SIBLING */
213 return NULL
; /* oops, found second parent */
216 if (p
!= NULL
&& !p
->options
.no_query
)
218 debug(15, 3) ("getSingleParent: returning %s\n", p
? p
->host
: "NULL");
223 getFirstUpParent(request_t
* request
)
226 for (p
= Config
.peers
; p
; p
= p
->next
) {
229 if (neighborType(p
, request
) != PEER_PARENT
)
231 if (!peerHTTPOkay(p
, request
))
235 debug(15, 3) ("getFirstUpParent: returning %s\n", p
? p
->host
: "NULL");
240 getRoundRobinParent(request_t
* request
)
244 for (p
= Config
.peers
; p
; p
= p
->next
) {
245 if (!p
->options
.roundrobin
)
247 if (neighborType(p
, request
) != PEER_PARENT
)
249 if (!peerHTTPOkay(p
, request
))
251 if (q
&& q
->rr_count
< p
->rr_count
)
257 debug(15, 3) ("getRoundRobinParent: returning %s\n", q
? q
->host
: "NULL");
262 getDefaultParent(request_t
* request
)
265 for (p
= Config
.peers
; p
; p
= p
->next
) {
266 if (neighborType(p
, request
) != PEER_PARENT
)
268 if (!p
->options
.default_parent
)
270 if (!peerHTTPOkay(p
, request
))
272 debug(15, 3) ("getDefaultParent: returning %s\n", p
->host
);
275 debug(15, 3) ("getDefaultParent: returning NULL\n");
280 getAnyParent(request_t
* request
)
283 for (p
= Config
.peers
; p
; p
= p
->next
) {
284 if (neighborType(p
, request
) != PEER_PARENT
)
286 if (!peerHTTPOkay(p
, request
))
288 debug(15, 3) ("getAnyParent: returning %s\n", p
->host
);
291 debug(15, 3) ("getAnyParent: returning NULL\n");
296 getNextPeer(peer
* p
)
308 neighborRemove(peer
* target
)
325 first_ping
= Config
.peers
;
329 neighbors_open(int fd
)
331 struct sockaddr_in name
;
332 socklen_t len
= sizeof(struct sockaddr_in
);
333 struct servent
*sep
= NULL
;
334 memset(&name
, '\0', sizeof(struct sockaddr_in
));
335 if (getsockname(fd
, (struct sockaddr
*) &name
, &len
) < 0)
336 debug(15, 1) ("getsockname(%d,%p,%p) failed.\n", fd
, &name
, &len
);
337 peerRefreshDNS((void *) 1);
338 if (0 == echo_hdr
.opcode
) {
339 echo_hdr
.opcode
= ICP_SECHO
;
340 echo_hdr
.version
= ICP_VERSION_CURRENT
;
345 echo_hdr
.shostid
= name
.sin_addr
.s_addr
;
346 sep
= getservbyname("echo", "udp");
347 echo_port
= sep
? ntohs((u_short
) sep
->s_port
) : 7;
349 first_ping
= Config
.peers
;
350 cachemgrRegister("server_list",
351 "Peer Cache Statistics",
352 neighborDumpPeers
, 0, 1);
353 cachemgrRegister("non_peers",
354 "List of Unknown sites sending ICP messages",
355 neighborDumpNonPeers
, 0, 1);
359 neighborsUdpPing(request_t
* request
,
366 const char *url
= storeUrl(entry
);
367 MemObject
*mem
= entry
->mem_obj
;
373 int queries_sent
= 0;
374 int peers_pinged
= 0;
376 if (Config
.peers
== NULL
)
378 if (theOutIcpConnection
< 0)
379 fatal("neighborsUdpPing: There is no ICP socket!");
380 assert(entry
->swap_status
== SWAPOUT_NONE
);
381 mem
->start_ping
= current_time
;
382 mem
->ping_reply_callback
= callback
;
383 mem
->ircb_data
= callback_data
;
385 reqnum
= icpSetCacheKey(entry
->key
);
386 for (i
= 0, p
= first_ping
; i
++ < Config
.npeers
; p
= p
->next
) {
389 debug(15, 5) ("neighborsUdpPing: Peer %s\n", p
->host
);
390 if (!peerWouldBePinged(p
, request
))
391 continue; /* next peer */
393 debug(15, 4) ("neighborsUdpPing: pinging peer %s for '%s'\n",
395 if (p
->type
== PEER_MULTICAST
)
396 mcastSetTtl(theOutIcpConnection
, p
->mcast
.ttl
);
397 debug(15, 3) ("neighborsUdpPing: key = '%s'\n", storeKeyText(entry
->key
));
398 debug(15, 3) ("neighborsUdpPing: reqnum = %d\n", reqnum
);
401 if (p
->options
.htcp
) {
402 debug(15, 3) ("neighborsUdpPing: sending HTCP query\n");
403 htcpQuery(entry
, request
, p
);
406 if (p
->icp
.port
== echo_port
) {
407 debug(15, 4) ("neighborsUdpPing: Looks like a dumb cache, send DECHO ping\n");
408 echo_hdr
.reqnum
= reqnum
;
409 query
= icpCreateMessage(ICP_DECHO
, 0, url
, reqnum
, 0);
410 icpUdpSend(theOutIcpConnection
,
417 if (Config
.onoff
.query_icmp
)
418 if (p
->icp
.version
== ICP_VERSION_2
)
419 flags
|= ICP_FLAG_SRC_RTT
;
420 query
= icpCreateMessage(ICP_QUERY
, flags
, url
, reqnum
, 0);
421 icpUdpSend(theOutIcpConnection
,
429 p
->stats
.pings_sent
++;
430 if (p
->type
== PEER_MULTICAST
) {
432 * set a bogus last_reply time so neighborUp() never
433 * says a multicast peer is dead.
435 p
->stats
.last_reply
= squid_curtime
;
436 (*exprep
) += p
->mcast
.n_replies_expected
;
437 } else if (squid_curtime
- p
->stats
.last_query
> Config
.Timeout
.deadPeer
) {
439 * fake a recent reply if its been a long time since our
442 p
->stats
.last_reply
= squid_curtime
;
444 * We used to not expect a reply in this case; we assumed
445 * the peer was DEAD if we hadn't queried it in a long
446 * time. However, the number of people whining to
447 * squid-users that ICP is broken became unbearable. They
448 * tried a single request which, to their amazement, was
449 * forwarded directly to the origin server, even thought
450 * they KNEW it was in a neighbor cache. Ok, I give up, you
455 } else if (neighborUp(p
)) {
456 /* its alive, expect a reply from it */
458 (*timeout
) += p
->stats
.rtt
;
460 /* Neighbor is dead; ping it anyway, but don't expect a reply */
461 /* log it once at the threshold */
462 if (p
->stats
.logged_state
== PEER_ALIVE
) {
463 debug(15, 1) ("Detected DEAD %s: %s/%d/%d\n",
465 p
->host
, p
->http_port
, p
->icp
.port
);
466 p
->stats
.logged_state
= PEER_DEAD
;
469 p
->stats
.last_query
= squid_curtime
;
471 if ((first_ping
= first_ping
->next
) == NULL
)
472 first_ping
= Config
.peers
;
474 #if ALLOW_SOURCE_PING
475 /* only do source_ping if we have neighbors */
477 const ipcache_addrs
*ia
= NULL
;
478 struct sockaddr_in to_addr
;
479 char *host
= request
->host
;
480 if (!Config
.onoff
.source_ping
) {
481 debug(15, 6) ("neighborsUdpPing: Source Ping is disabled.\n");
482 } else if ((ia
= ipcache_gethostbyname(host
, 0))) {
483 debug(15, 6) ("neighborsUdpPing: Source Ping: to %s for '%s'\n",
485 echo_hdr
.reqnum
= reqnum
;
486 if (icmp_sock
!= -1) {
487 icmpSourcePing(ia
->in_addrs
[ia
->cur
], &echo_hdr
, url
);
489 to_addr
.sin_family
= AF_INET
;
490 to_addr
.sin_addr
= ia
->in_addrs
[ia
->cur
];
491 to_addr
.sin_port
= htons(echo_port
);
492 query
= icpCreateMessage(ICP_SECHO
, 0, url
, reqnum
, 0);
493 icpUdpSend(theOutIcpConnection
,
500 debug(15, 6) ("neighborsUdpPing: Source Ping: unknown host: %s\n",
506 * If there is a configured timeout, use it
508 if (Config
.Timeout
.icp_query
)
509 *timeout
= Config
.Timeout
.icp_query
;
512 (*timeout
) = 2 * (*timeout
) / (*exprep
);
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
;
522 /* lookup the digest of a given peer */
524 peerDigestLookup(peer
* p
, request_t
* request
, StoreEntry
* entry
)
526 #if USE_CACHE_DIGESTS
527 const cache_key
*key
= request
? storeKeyPublic(storeUrl(entry
), request
->method
) : NULL
;
530 debug(15, 5) ("peerDigestLookup: peer %s\n", p
->host
);
531 /* does the peeer have a valid digest? */
533 debug(15, 5) ("peerDigestLookup: gone!\n");
535 } else if (!peerHTTPOkay(p
, request
)) {
536 debug(15, 5) ("peerDigestLookup: !peerHTTPOkay\n");
538 } else if (p
->digest
->flags
.usable
) {
539 debug(15, 5) ("peerDigestLookup: usable\n");
540 /* fall through; put here to have common case on top */ ;
541 } else if (!p
->digest
->flags
.needed
) {
542 debug(15, 5) ("peerDigestLookup: note need\n");
543 peerDigestNeeded(p
->digest
);
546 debug(15, 5) ("peerDigestLookup: !ready && %srequested\n",
547 p
->digest
->flags
.requested
? "" : "!");
550 debug(15, 5) ("peerDigestLookup: OK to lookup peer %s\n", p
->host
);
551 assert(p
->digest
->cd
);
552 /* does digest predict a hit? */
553 if (!cacheDigestTest(p
->digest
->cd
, key
))
555 debug(15, 5) ("peerDigestLookup: peer %s says HIT!\n", p
->host
);
561 /* select best peer based on cache digests */
563 neighborsDigestSelect(request_t
* request
, StoreEntry
* entry
)
566 #if USE_CACHE_DIGESTS
567 const cache_key
*key
;
569 int choice_count
= 0;
570 int ichoice_count
= 0;
574 if (!request
->flags
.hierarchical
)
576 key
= storeKeyPublic(storeUrl(entry
), request
->method
);
577 for (i
= 0, p
= first_ping
; i
++ < Config
.npeers
; p
= p
->next
) {
583 lookup
= peerDigestLookup(p
, request
, entry
);
584 if (lookup
== LOOKUP_NONE
)
587 if (lookup
== LOOKUP_MISS
)
589 p_rtt
= netdbHostRtt(p
->host
);
590 debug(15, 5) ("neighborsDigestSelect: peer %s rtt: %d\n",
592 /* is this peer better than others in terms of rtt ? */
593 if (!best_p
|| (p_rtt
&& p_rtt
< best_rtt
)) {
596 if (p_rtt
) /* informative choice (aka educated guess) */
598 debug(15, 4) ("neighborsDigestSelect: peer %s leads with rtt %d\n",
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
));
606 request
->hier
.n_choices
= choice_count
;
607 request
->hier
.n_ichoices
= ichoice_count
;
613 peerNoteDigestLookup(request_t
* request
, peer
* p
, lookup_t lookup
)
615 #if USE_CACHE_DIGESTS
617 strncpy(request
->hier
.cd_host
, p
->host
, sizeof(request
->hier
.cd_host
));
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
]);
627 neighborAlive(peer
* p
, const MemObject
* mem
, const icp_common_t
* header
)
629 if (p
->stats
.logged_state
== PEER_DEAD
&& p
->tcp_up
) {
630 debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n",
632 p
->host
, p
->http_port
, p
->icp
.port
);
633 p
->stats
.logged_state
= PEER_ALIVE
;
635 p
->stats
.last_reply
= squid_curtime
;
636 p
->stats
.pings_acked
++;
637 if ((icp_opcode
) header
->opcode
<= ICP_END
)
638 p
->icp
.counts
[header
->opcode
]++;
639 p
->icp
.version
= (int) header
->version
;
643 neighborUpdateRtt(peer
* p
, MemObject
* mem
)
648 if (!mem
->start_ping
.tv_sec
)
650 rtt
= tvSubMsec(mem
->start_ping
, current_time
);
651 if (rtt
< 1 || rtt
> 10000)
653 p
->stats
.rtt
= intAverage(p
->stats
.rtt
, rtt
,
654 p
->stats
.pings_acked
, RTT_AV_FACTOR
);
659 neighborAliveHtcp(peer
* p
, const MemObject
* mem
, const htcpReplyData
* htcp
)
661 if (p
->stats
.logged_state
== PEER_DEAD
&& p
->tcp_up
) {
662 debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n",
664 p
->host
, p
->http_port
, p
->icp
.port
);
665 p
->stats
.logged_state
= PEER_ALIVE
;
667 p
->stats
.last_reply
= squid_curtime
;
668 p
->stats
.pings_acked
++;
669 p
->htcp
.counts
[htcp
->hit
? 1 : 0]++;
670 p
->htcp
.version
= htcp
->version
;
675 neighborCountIgnored(peer
* p
)
679 p
->stats
.ignored_replies
++;
683 static peer
*non_peers
= NULL
;
686 neighborIgnoreNonPeer(const struct sockaddr_in
*from
, icp_opcode opcode
)
690 for (np
= non_peers
; np
; np
= np
->next
) {
691 if (np
->in_addr
.sin_addr
.s_addr
!= from
->sin_addr
.s_addr
)
693 if (np
->in_addr
.sin_port
!= from
->sin_port
)
698 np
= xcalloc(1, sizeof(peer
));
699 np
->in_addr
.sin_addr
= from
->sin_addr
;
700 np
->in_addr
.sin_port
= from
->sin_port
;
701 np
->icp
.port
= ntohl(from
->sin_port
);
702 np
->type
= PEER_NONE
;
703 np
->host
= xstrdup(inet_ntoa(from
->sin_addr
));
704 np
->next
= non_peers
;
707 np
->stats
.ignored_replies
++;
708 np
->icp
.counts
[opcode
]++;
709 x
= log(np
->stats
.ignored_replies
) / log(10.0);
710 if (0.0 != x
- (double) (int) x
)
712 debug(15, 1) ("WARNING: Ignored %d replies from non-peer %s\n",
713 np
->stats
.ignored_replies
, np
->host
);
716 /* ignoreMulticastReply
718 * We want to ignore replies from multicast peers if the
719 * cache_host_domain rules would normally prevent the peer
723 ignoreMulticastReply(peer
* p
, MemObject
* mem
)
727 if (!p
->options
.mcast_responder
)
729 if (peerHTTPOkay(p
, mem
->request
))
734 /* I should attach these records to the entry. We take the first
735 * hit we get our wait until everyone misses. The timeout handler
736 * call needs to nip this shopping list or call one of the misses.
738 * If a hit process is already started, then sobeit
741 neighborsUdpAck(const cache_key
* key
, icp_common_t
* header
, const struct sockaddr_in
*from
)
745 MemObject
*mem
= NULL
;
746 peer_t ntype
= PEER_NONE
;
748 icp_opcode opcode
= (icp_opcode
) header
->opcode
;
750 debug(15, 6) ("neighborsUdpAck: opcode %d '%s'\n",
751 (int) opcode
, storeKeyText(key
));
752 if (NULL
!= (entry
= storeGet(key
)))
753 mem
= entry
->mem_obj
;
754 if ((p
= whichPeer(from
)))
755 neighborAlive(p
, mem
, header
);
756 if (opcode
> ICP_END
)
758 opcode_d
= icp_opcode_str
[opcode
];
760 neighborUpdateRtt(p
, mem
);
761 /* Does the entry exist? */
763 debug(12, 3) ("neighborsUdpAck: Cache key '%s' not found\n",
765 neighborCountIgnored(p
);
768 /* check if someone is already fetching it */
769 if (EBIT_TEST(entry
->flags
, ENTRY_DISPATCHED
)) {
770 debug(15, 3) ("neighborsUdpAck: '%s' already being fetched.\n",
772 neighborCountIgnored(p
);
776 debug(15, 2) ("Ignoring %s for missing mem_obj: %s\n",
777 opcode_d
, storeKeyText(key
));
778 neighborCountIgnored(p
);
781 if (entry
->ping_status
!= PING_WAITING
) {
782 debug(15, 2) ("neighborsUdpAck: Late %s for %s\n",
783 opcode_d
, storeKeyText(key
));
784 neighborCountIgnored(p
);
787 if (entry
->lock_count
== 0) {
788 debug(12, 1) ("neighborsUdpAck: '%s' has no locks\n",
790 neighborCountIgnored(p
);
793 debug(15, 3) ("neighborsUdpAck: %s for '%s' from %s \n",
794 opcode_d
, storeKeyText(key
), p
? p
->host
: "source");
796 ntype
= neighborType(p
, mem
->request
);
798 if (ignoreMulticastReply(p
, mem
)) {
799 neighborCountIgnored(p
);
800 } else if (opcode
== ICP_MISS
) {
802 neighborIgnoreNonPeer(from
, opcode
);
804 mem
->ping_reply_callback(p
, ntype
, PROTO_ICP
, header
, mem
->ircb_data
);
806 } else if (opcode
== ICP_HIT
) {
808 neighborIgnoreNonPeer(from
, opcode
);
810 header
->opcode
= ICP_HIT
;
811 mem
->ping_reply_callback(p
, ntype
, PROTO_ICP
, header
, mem
->ircb_data
);
813 } else if (opcode
== ICP_DECHO
) {
815 neighborIgnoreNonPeer(from
, opcode
);
816 } else if (ntype
== PEER_SIBLING
) {
817 debug_trap("neighborsUdpAck: Found non-ICP cache as SIBLING\n");
818 debug_trap("neighborsUdpAck: non-ICP neighbors must be a PARENT\n");
820 mem
->ping_reply_callback(p
, ntype
, PROTO_ICP
, header
, mem
->ircb_data
);
822 } else if (opcode
== ICP_SECHO
) {
824 debug(15, 1) ("Ignoring SECHO from neighbor %s\n", p
->host
);
825 neighborCountIgnored(p
);
826 #if ALLOW_SOURCE_PING
827 } else if (Config
.onoff
.source_ping
) {
828 mem
->ping_reply_callback(NULL
, ntype
, PROTO_ICP
, header
, mem
->ircb_data
);
831 debug(15, 1) ("Unsolicited SECHO from %s\n", inet_ntoa(from
->sin_addr
));
833 } else if (opcode
== ICP_DENIED
) {
835 neighborIgnoreNonPeer(from
, opcode
);
836 } else if (p
->stats
.pings_acked
> 100) {
837 if (100 * p
->icp
.counts
[ICP_DENIED
] / p
->stats
.pings_acked
> 95) {
838 debug(15, 0) ("95%% of replies from '%s' are UDP_DENIED\n", p
->host
);
839 debug(15, 0) ("Disabling '%s', please check your configuration.\n", p
->host
);
843 neighborCountIgnored(p
);
846 } else if (opcode
== ICP_MISS_NOFETCH
) {
847 mem
->ping_reply_callback(p
, ntype
, PROTO_ICP
, header
, mem
->ircb_data
);
849 debug(15, 0) ("neighborsUdpAck: Unexpected ICP reply: %s\n", opcode_d
);
854 peerFindByName(const char *name
)
857 for (p
= Config
.peers
; p
; p
= p
->next
) {
858 if (!strcasecmp(name
, p
->host
))
865 peerFindByNameAndPort(const char *name
, unsigned short port
)
868 for (p
= Config
.peers
; p
; p
= p
->next
) {
869 if (strcasecmp(name
, p
->host
))
871 if (port
!= p
->http_port
)
879 neighborUp(const peer
* p
)
883 if (squid_curtime
- p
->stats
.last_query
> Config
.Timeout
.deadPeer
)
885 if (p
->stats
.last_query
- p
->stats
.last_reply
> Config
.Timeout
.deadPeer
)
891 peerDestroy(void *data
, int unused
)
894 struct _domain_ping
*l
= NULL
;
895 struct _domain_ping
*nl
= NULL
;
898 for (l
= p
->peer_domain
; l
; l
= nl
) {
900 safe_free(l
->domain
);
904 #if USE_CACHE_DIGESTS
906 PeerDigest
*pd
= p
->digest
;
915 peerNoteDigestGone(peer
* p
)
917 #if USE_CACHE_DIGESTS
919 PeerDigest
*pd
= p
->digest
;
927 peerDNSConfigure(const ipcache_addrs
* ia
, void *data
)
930 struct sockaddr_in
*ap
;
932 if (p
->n_addresses
== 0) {
933 debug(15, 1) ("Configuring %s %s/%d/%d\n", neighborTypeStr(p
),
934 p
->host
, p
->http_port
, p
->icp
.port
);
935 if (p
->type
== PEER_MULTICAST
)
936 debug(15, 1) (" Multicast TTL = %d\n", p
->mcast
.ttl
);
940 debug(0, 0) ("WARNING: DNS lookup for '%s' failed!\n", p
->host
);
943 if ((int) ia
->count
< 1) {
944 debug(0, 0) ("WARNING: No IP address found for '%s'!\n", p
->host
);
947 for (j
= 0; j
< (int) ia
->count
&& j
< PEER_MAX_ADDRESSES
; j
++) {
948 p
->addresses
[j
] = ia
->in_addrs
[j
];
949 debug(15, 2) ("--> IP address #%d: %s\n", j
, inet_ntoa(p
->addresses
[j
]));
953 memset(ap
, '\0', sizeof(struct sockaddr_in
));
954 ap
->sin_family
= AF_INET
;
955 ap
->sin_addr
= p
->addresses
[0];
956 ap
->sin_port
= htons(p
->icp
.port
);
957 if (p
->type
== PEER_MULTICAST
)
958 peerCountMcastPeersSchedule(p
, 10);
959 if (p
->type
!= PEER_MULTICAST
)
960 if (!p
->options
.no_netdb_exchange
)
961 eventAddIsh("netdbExchangeStart", netdbExchangeStart
, p
, 30.0, 1);
965 peerRefreshDNS(void *data
)
968 if (eventFind(peerRefreshDNS
, NULL
))
969 eventDelete(peerRefreshDNS
, NULL
);
970 if (!data
&& 0 == stat5minClientRequests()) {
971 /* no recent client traffic, wait a bit */
972 eventAddIsh("peerRefreshDNS", peerRefreshDNS
, NULL
, 180.0, 1);
975 for (p
= Config
.peers
; p
; p
= p
->next
)
976 ipcache_nbgethostbyname(p
->host
, peerDNSConfigure
, p
);
977 /* Reconfigure the peers every hour */
978 eventAddIsh("peerRefreshDNS", peerRefreshDNS
, NULL
, 3600.0, 1);
982 * peerCheckConnect will NOT be called by eventRun if the peer/data
983 * pointer becomes invalid.
986 peerCheckConnect(void *data
)
990 fd
= comm_open(SOCK_STREAM
, 0, Config
.Addrs
.tcp_outgoing
,
991 0, COMM_NONBLOCKING
, p
->host
);
995 ipcache_nbgethostbyname(p
->host
, peerCheckConnect2
, p
);
999 peerCheckConnect2(const ipcache_addrs
* ianotused
, void *data
)
1002 commConnectStart(p
->test_fd
,
1005 peerCheckConnectDone
,
1010 peerCheckConnectDone(int fd
, int status
, void *data
)
1013 if (status
== COMM_OK
) {
1014 p
->tcp_up
= PEER_TCP_MAGIC_COUNT
;
1015 debug(15, 1) ("TCP connection to %s/%d succeeded\n",
1016 p
->host
, p
->http_port
);
1018 eventAdd("peerCheckConnect", peerCheckConnect
, p
, 60.0, 1);
1025 peerCheckConnectStart(peer
* p
)
1029 debug(15, 1) ("TCP connection to %s/%d failed\n", p
->host
, p
->http_port
);
1031 if (p
->tcp_up
!= (PEER_TCP_MAGIC_COUNT
- 1))
1033 p
->last_fail_time
= squid_curtime
;
1034 eventAdd("peerCheckConnect", peerCheckConnect
, p
, 30.0, 1);
1038 peerCountMcastPeersSchedule(peer
* p
, time_t when
)
1040 if (p
->mcast
.flags
.count_event_pending
)
1042 eventAdd("peerCountMcastPeersStart",
1043 peerCountMcastPeersStart
,
1046 p
->mcast
.flags
.count_event_pending
= 1;
1050 peerCountMcastPeersStart(void *data
)
1053 ps_state
*psstate
= xcalloc(1, sizeof(ps_state
));
1056 icp_common_t
*query
;
1058 LOCAL_ARRAY(char, url
, MAX_URL
);
1059 assert(p
->type
== PEER_MULTICAST
);
1060 p
->mcast
.flags
.count_event_pending
= 0;
1061 snprintf(url
, MAX_URL
, "http://%s/", inet_ntoa(p
->in_addr
.sin_addr
));
1062 fake
= storeCreateEntry(url
, url
, null_request_flags
, METHOD_GET
);
1063 psstate
->request
= requestLink(urlParse(METHOD_GET
, url
));
1064 psstate
->entry
= fake
;
1065 psstate
->callback
= NULL
;
1066 psstate
->callback_data
= p
;
1067 psstate
->ping
.start
= current_time
;
1068 cbdataAdd(psstate
, cbdataXfree
, 0);
1069 mem
= fake
->mem_obj
;
1070 mem
->request
= requestLink(psstate
->request
);
1071 mem
->start_ping
= current_time
;
1072 mem
->ping_reply_callback
= peerCountHandleIcpReply
;
1073 mem
->ircb_data
= psstate
;
1074 mcastSetTtl(theOutIcpConnection
, p
->mcast
.ttl
);
1075 p
->mcast
.id
= mem
->id
;
1076 reqnum
= icpSetCacheKey(fake
->key
);
1077 query
= icpCreateMessage(ICP_QUERY
, 0, url
, reqnum
, 0);
1078 icpUdpSend(theOutIcpConnection
,
1083 fake
->ping_status
= PING_WAITING
;
1084 eventAdd("peerCountMcastPeersDone",
1085 peerCountMcastPeersDone
,
1087 (double) Config
.Timeout
.mcast_icp_query
, 1);
1088 p
->mcast
.flags
.counting
= 1;
1089 peerCountMcastPeersSchedule(p
, MCAST_COUNT_RATE
);
1093 peerCountMcastPeersDone(void *data
)
1095 ps_state
*psstate
= data
;
1096 peer
*p
= psstate
->callback_data
;
1097 StoreEntry
*fake
= psstate
->entry
;
1098 p
->mcast
.flags
.counting
= 0;
1099 p
->mcast
.avg_n_members
= doubleAverage(p
->mcast
.avg_n_members
,
1100 (double) psstate
->ping
.n_recv
,
1101 ++p
->mcast
.n_times_counted
,
1103 debug(15, 1) ("Group %s: %d replies, %4.1f average, RTT %d\n",
1105 psstate
->ping
.n_recv
,
1106 p
->mcast
.avg_n_members
,
1108 p
->mcast
.n_replies_expected
= (int) p
->mcast
.avg_n_members
;
1109 EBIT_SET(fake
->flags
, ENTRY_ABORTED
);
1110 requestUnlink(fake
->mem_obj
->request
);
1111 fake
->mem_obj
->request
= NULL
;
1112 storeReleaseRequest(fake
);
1113 storeUnlockObject(fake
);
1114 requestUnlink(psstate
->request
);
1115 cbdataFree(psstate
);
1119 peerCountHandleIcpReply(peer
* p
, peer_t type
, protocol_t proto
, void *hdrnotused
, void *data
)
1121 ps_state
*psstate
= data
;
1122 StoreEntry
*fake
= psstate
->entry
;
1123 MemObject
*mem
= fake
->mem_obj
;
1124 int rtt
= tvSubMsec(mem
->start_ping
, current_time
);
1125 assert(proto
== PROTO_ICP
);
1128 psstate
->ping
.n_recv
++;
1129 p
->stats
.rtt
= intAverage(p
->stats
.rtt
, rtt
, psstate
->ping
.n_recv
, RTT_AV_FACTOR
);
1133 neighborDumpPeers(StoreEntry
* sentry
)
1135 dump_peers(sentry
, Config
.peers
);
1139 neighborDumpNonPeers(StoreEntry
* sentry
)
1141 dump_peers(sentry
, non_peers
);
1145 dump_peer_options(StoreEntry
* sentry
, peer
* p
)
1147 if (p
->options
.proxy_only
)
1148 storeAppendPrintf(sentry
, " proxy-only");
1149 if (p
->options
.no_query
)
1150 storeAppendPrintf(sentry
, " no-query");
1151 if (p
->options
.no_digest
)
1152 storeAppendPrintf(sentry
, " no-digest");
1153 if (p
->options
.default_parent
)
1154 storeAppendPrintf(sentry
, " default");
1155 if (p
->options
.roundrobin
)
1156 storeAppendPrintf(sentry
, " round-robin");
1157 if (p
->options
.mcast_responder
)
1158 storeAppendPrintf(sentry
, " multicast-responder");
1159 if (p
->options
.closest_only
)
1160 storeAppendPrintf(sentry
, " closest-only");
1162 if (p
->options
.htcp
)
1163 storeAppendPrintf(sentry
, " htcp");
1165 if (p
->options
.no_netdb_exchange
)
1166 storeAppendPrintf(sentry
, " no-netdb-exchange");
1168 if (p
->options
.no_delay
)
1169 storeAppendPrintf(sentry
, " no-delay");
1172 storeAppendPrintf(sentry
, " login=%s", p
->login
);
1173 if (p
->mcast
.ttl
> 0)
1174 storeAppendPrintf(sentry
, " ttl=%d", p
->mcast
.ttl
);
1175 storeAppendPrintf(sentry
, "\n");
1179 dump_peers(StoreEntry
* sentry
, peer
* peers
)
1182 struct _domain_ping
*d
= NULL
;
1186 storeAppendPrintf(sentry
, "There are no neighbors installed.\n");
1187 for (e
= peers
; e
; e
= e
->next
) {
1188 assert(e
->host
!= NULL
);
1189 storeAppendPrintf(sentry
, "\n%-11.11s: %s/%d/%d\n",
1194 storeAppendPrintf(sentry
, "Flags :");
1195 dump_peer_options(sentry
, e
);
1196 for (i
= 0; i
< e
->n_addresses
; i
++) {
1197 storeAppendPrintf(sentry
, "Address[%d] : %s\n", i
,
1198 inet_ntoa(e
->addresses
[i
]));
1200 storeAppendPrintf(sentry
, "Status : %s\n",
1201 neighborUp(e
) ? "Up" : "Down");
1202 storeAppendPrintf(sentry
, "AVG RTT : %d msec\n", e
->stats
.rtt
);
1203 storeAppendPrintf(sentry
, "LAST QUERY : %8d seconds ago\n",
1204 (int) (squid_curtime
- e
->stats
.last_query
));
1205 storeAppendPrintf(sentry
, "LAST REPLY : %8d seconds ago\n",
1206 (int) (squid_curtime
- e
->stats
.last_reply
));
1207 storeAppendPrintf(sentry
, "PINGS SENT : %8d\n", e
->stats
.pings_sent
);
1208 storeAppendPrintf(sentry
, "PINGS ACKED: %8d %3d%%\n",
1209 e
->stats
.pings_acked
,
1210 percent(e
->stats
.pings_acked
, e
->stats
.pings_sent
));
1211 storeAppendPrintf(sentry
, "FETCHES : %8d %3d%%\n",
1213 percent(e
->stats
.fetches
, e
->stats
.pings_acked
));
1214 storeAppendPrintf(sentry
, "IGNORED : %8d %3d%%\n",
1215 e
->stats
.ignored_replies
,
1216 percent(e
->stats
.ignored_replies
, e
->stats
.pings_acked
));
1217 storeAppendPrintf(sentry
, "Histogram of PINGS ACKED:\n");
1219 if (e
->options
.htcp
) {
1220 storeAppendPrintf(sentry
, "\tMisses\t%8d %3d%%\n",
1222 percent(e
->htcp
.counts
[0], e
->stats
.pings_acked
));
1223 storeAppendPrintf(sentry
, "\tHits\t%8d %3d%%\n",
1225 percent(e
->htcp
.counts
[1], e
->stats
.pings_acked
));
1228 for (op
= ICP_INVALID
; op
< ICP_END
; op
++) {
1229 if (e
->icp
.counts
[op
] == 0)
1231 storeAppendPrintf(sentry
, " %12.12s : %8d %3d%%\n",
1234 percent(e
->icp
.counts
[op
], e
->stats
.pings_acked
));
1239 if (e
->last_fail_time
) {
1240 storeAppendPrintf(sentry
, "Last failed connect() at: %s\n",
1241 mkhttpdlogtime(&(e
->last_fail_time
)));
1243 if (e
->peer_domain
!= NULL
) {
1244 storeAppendPrintf(sentry
, "DOMAIN LIST: ");
1245 for (d
= e
->peer_domain
; d
; d
= d
->next
) {
1246 storeAppendPrintf(sentry
, "%s%s ",
1247 d
->do_ping
? null_string
: "!", d
->domain
);
1249 storeAppendPrintf(sentry
, "\n");
1251 storeAppendPrintf(sentry
, "keep-alive ratio: %d%%\n",
1252 percent(e
->stats
.n_keepalives_recv
, e
->stats
.n_keepalives_sent
));
1258 neighborsHtcpReply(const cache_key
* key
, htcpReplyData
* htcp
, const struct sockaddr_in
*from
)
1260 StoreEntry
*e
= storeGet(key
);
1261 MemObject
*mem
= NULL
;
1263 peer_t ntype
= PEER_NONE
;
1264 debug(15, 6) ("neighborsHtcpReply: %s %s\n",
1265 htcp
->hit
? "HIT" : "MISS", storeKeyText(key
));
1266 if (NULL
!= (e
= storeGet(key
)))
1268 if ((p
= whichPeer(from
)))
1269 neighborAliveHtcp(p
, mem
, htcp
);
1270 /* Does the entry exist? */
1272 debug(12, 3) ("neighyborsHtcpReply: Cache key '%s' not found\n",
1274 neighborCountIgnored(p
);
1277 /* check if someone is already fetching it */
1278 if (EBIT_TEST(e
->flags
, ENTRY_DISPATCHED
)) {
1279 debug(15, 3) ("neighborsUdpAck: '%s' already being fetched.\n",
1281 neighborCountIgnored(p
);
1285 debug(15, 2) ("Ignoring reply for missing mem_obj: %s\n",
1287 neighborCountIgnored(p
);
1290 if (e
->ping_status
!= PING_WAITING
) {
1291 debug(15, 2) ("neighborsUdpAck: Entry %s is not PING_WAITING\n",
1293 neighborCountIgnored(p
);
1296 if (e
->lock_count
== 0) {
1297 debug(12, 1) ("neighborsUdpAck: '%s' has no locks\n",
1299 neighborCountIgnored(p
);
1303 ntype
= neighborType(p
, mem
->request
);
1304 neighborUpdateRtt(p
, mem
);
1306 if (ignoreMulticastReply(p
, mem
)) {
1307 neighborCountIgnored(p
);
1310 debug(15, 3) ("neighborsHtcpReply: e = %p\n", e
);
1311 mem
->ping_reply_callback(p
, ntype
, PROTO_HTCP
, htcp
, mem
->ircb_data
);