neighbors.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:36k
源码类别:

代理服务器

开发平台:

Unix_Linux

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