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

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: ipcache.c,v 1.210 1998/12/05 00:54:30 wessels Exp $
  3.  *
  4.  * DEBUG: section 14    IP Cache
  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. static struct {
  36.     int requests;
  37.     int replies;
  38.     int hits;
  39.     int misses;
  40.     int pending_hits;
  41.     int negative_hits;
  42.     int errors;
  43.     int ghbn_calls; /* # calls to blocking gethostbyname() */
  44.     int release_locked;
  45. } IpcacheStats;
  46. static dlink_list lru_list;
  47. static FREE ipcacheFreeEntry;
  48. static HLPCB ipcacheHandleReply;
  49. static IPH dummy_handler;
  50. static int ipcacheExpiredEntry(ipcache_entry *);
  51. static int ipcache_testname(void);
  52. static ipcache_entry *ipcacheAddNew(const char *, const struct hostent *, ipcache_status_t);
  53. static ipcache_entry *ipcacheParse(const char *buf);
  54. static ipcache_entry *ipcache_create(const char *name);
  55. static ipcache_entry *ipcache_get(const char *);
  56. static void ipcacheAddHostent(ipcache_entry *, const struct hostent *);
  57. static void ipcacheAddPending(ipcache_entry *, IPH *, void *);
  58. static void ipcacheChangeKey(ipcache_entry * i);
  59. static void ipcacheLockEntry(ipcache_entry *);
  60. static void ipcacheStatPrint(ipcache_entry *, StoreEntry *);
  61. static void ipcacheUnlockEntry(ipcache_entry *);
  62. static void ipcache_call_pending(ipcache_entry *);
  63. static void ipcache_release(ipcache_entry *);
  64. static ipcache_addrs static_addrs;
  65. static hash_table *ip_table = NULL;
  66. static char ipcache_status_char[] =
  67. {
  68.     'C',
  69.     'N',
  70.     'P',
  71.     'D'
  72. };
  73. static long ipcache_low = 180;
  74. static long ipcache_high = 200;
  75. #if LIBRESOLV_DNS_TTL_HACK
  76. extern int _dns_ttl_;
  77. #endif
  78. static int
  79. ipcache_testname(void)
  80. {
  81.     wordlist *w = NULL;
  82.     debug(14, 1) ("Performing DNS Tests...n");
  83.     if ((w = Config.dns_testname_list) == NULL)
  84. return 1;
  85.     for (; w; w = w->next) {
  86. IpcacheStats.ghbn_calls++;
  87. if (gethostbyname(w->key) != NULL)
  88.     return 1;
  89.     }
  90.     return 0;
  91. }
  92. /* removes the given ipcache entry */
  93. static void
  94. ipcache_release(ipcache_entry * i)
  95. {
  96.     hash_link *table_entry = NULL;
  97.     if ((table_entry = hash_lookup(ip_table, i->name)) == NULL) {
  98. snprintf(tmp_error_buf, ERROR_BUF_SZ, "ipcache_release: key '%s' not foundn", i->name);
  99. fatal_dump(tmp_error_buf);
  100.     }
  101.     assert(i == (ipcache_entry *) table_entry);
  102.     if (i->locks) {
  103. i->expires = squid_curtime;
  104. ipcacheChangeKey(i);
  105. IpcacheStats.release_locked++;
  106. return;
  107.     }
  108.     hash_remove_link(ip_table, table_entry);
  109.     dlinkDelete(&i->lru, &lru_list);
  110.     if (i->status == IP_CACHED) {
  111. safe_free(i->addrs.in_addrs);
  112. safe_free(i->addrs.bad_mask);
  113. debug(14, 5) ("ipcache_release: Released IP cached record for '%s'.n",
  114.     i->name);
  115.     }
  116.     safe_free(i->name);
  117.     safe_free(i->error_message);
  118.     memFree(i, MEM_IPCACHE_ENTRY);
  119.     return;
  120. }
  121. static ipcache_entry *
  122. ipcache_get(const char *name)
  123. {
  124.     assert(ip_table != NULL);
  125.     return (ipcache_entry *) hash_lookup(ip_table, name);
  126. }
  127. static int
  128. ipcacheExpiredEntry(ipcache_entry * i)
  129. {
  130.     if (i->status == IP_PENDING)
  131. return 0;
  132.     if (i->status == IP_DISPATCHED)
  133. return 0;
  134.     if (i->locks != 0)
  135. return 0;
  136.     if (i->addrs.count == 0)
  137. return 1;
  138.     if (i->expires > squid_curtime)
  139. return 0;
  140.     return 1;
  141. }
  142. void
  143. ipcache_purgelru(void *voidnotused)
  144. {
  145.     dlink_node *m;
  146.     dlink_node *prev = NULL;
  147.     ipcache_entry *i;
  148.     int removed = 0;
  149.     eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
  150.     for (m = lru_list.tail; m; m = prev) {
  151. if (memInUse(MEM_IPCACHE_ENTRY) < ipcache_low)
  152.     break;
  153. prev = m->prev;
  154. i = m->data;
  155. if (i->status == IP_PENDING)
  156.     continue;
  157. if (i->status == IP_DISPATCHED)
  158.     continue;
  159. if (i->locks != 0)
  160.     continue;
  161. ipcache_release(i);
  162. removed++;
  163.     }
  164.     debug(14, 9) ("ipcache_purgelru: removed %d entriesn", removed);
  165. }
  166. /* create blank ipcache_entry */
  167. static ipcache_entry *
  168. ipcache_create(const char *name)
  169. {
  170.     static ipcache_entry *i;
  171.     i = memAllocate(MEM_IPCACHE_ENTRY);
  172.     i->name = xstrdup(name);
  173.     i->expires = squid_curtime + Config.negativeDnsTtl;
  174.     hash_join(ip_table, (hash_link *) i);
  175.     dlinkAdd(i, &i->lru, &lru_list);
  176.     return i;
  177. }
  178. static void
  179. ipcacheAddHostent(ipcache_entry * i, const struct hostent *hp)
  180. {
  181.     int addr_count = 0;
  182.     int k;
  183.     safe_free(i->addrs.in_addrs);
  184.     safe_free(i->addrs.bad_mask);
  185.     while ((addr_count < 255) && *(hp->h_addr_list + addr_count))
  186. ++addr_count;
  187.     i->addrs.count = (unsigned char) addr_count;
  188.     i->addrs.in_addrs = xcalloc(addr_count, sizeof(struct in_addr));
  189.     i->addrs.bad_mask = xcalloc(addr_count, sizeof(unsigned char));
  190.     i->addrs.badcount = 0;
  191.     for (k = 0; k < addr_count; k++)
  192. xmemcpy(&i->addrs.in_addrs[k].s_addr,
  193.     *(hp->h_addr_list + k),
  194.     hp->h_length);
  195. }
  196. static ipcache_entry *
  197. ipcacheAddNew(const char *name, const struct hostent *hp, ipcache_status_t status)
  198. {
  199.     ipcache_entry *i;
  200.     if (ipcache_get(name))
  201. fatal_dump("ipcacheAddNew: somebody adding a duplicate!");
  202.     debug(14, 10) ("ipcacheAddNew: Adding '%s', status=%cn",
  203. name,
  204. ipcache_status_char[status]);
  205.     i = ipcache_create(name);
  206.     if (hp)
  207. ipcacheAddHostent(i, hp);
  208.     i->status = status;
  209.     i->lastref = squid_curtime;
  210.     return i;
  211. }
  212. /* walks down the pending list, calling handlers */
  213. static void
  214. ipcache_call_pending(ipcache_entry * i)
  215. {
  216.     ip_pending *p = NULL;
  217.     int nhandler = 0;
  218.     i->lastref = squid_curtime;
  219.     ipcacheLockEntry(i);
  220.     while (i->pending_head != NULL) {
  221. p = i->pending_head;
  222. i->pending_head = p->next;
  223. if (p->handler) {
  224.     nhandler++;
  225.     dns_error_message = i->error_message;
  226.     if (cbdataValid(p->handlerData)) {
  227. p->handler(i->status == IP_CACHED ? &i->addrs : NULL,
  228.     p->handlerData);
  229.     }
  230.     cbdataUnlock(p->handlerData);
  231. }
  232. memFree(p, MEM_IPCACHE_PENDING);
  233.     }
  234.     i->pending_head = NULL; /* nuke list */
  235.     debug(14, 10) ("ipcache_call_pending: Called %d handlers.n", nhandler);
  236.     ipcacheUnlockEntry(i);
  237. }
  238. static ipcache_entry *
  239. ipcacheParse(const char *inbuf)
  240. {
  241.     LOCAL_ARRAY(char, buf, DNS_INBUF_SZ);
  242.     char *token;
  243.     static ipcache_entry i;
  244.     int j;
  245.     int k;
  246.     int ipcount = 0;
  247.     int ttl;
  248.     char A[32][16];
  249.     memset(&i, '', sizeof(i));
  250.     i.expires = squid_curtime;
  251.     i.status = IP_NEGATIVE_CACHED;
  252.     if (inbuf == NULL) {
  253. debug(14, 1) ("ipcacheParse: Got <NULL> replyn");
  254. i.error_message = xstrdup("Internal Squid Error");
  255. return &i;
  256.     }
  257.     xstrncpy(buf, inbuf, DNS_INBUF_SZ);
  258.     debug(14, 5) ("ipcacheParse: parsing: {%s}n", buf);
  259.     token = strtok(buf, w_space);
  260.     if (NULL == token) {
  261. debug(14, 1) ("ipcacheParse: Got <NULL>, expecting '$addr'n");
  262. return &i;
  263.     }
  264.     if (0 == strcmp(token, "$fail")) {
  265. i.expires = squid_curtime + Config.negativeDnsTtl;
  266. token = strtok(NULL, "n");
  267. assert(NULL != token);
  268. i.error_message = xstrdup(token);
  269. return &i;
  270.     }
  271.     if (0 != strcmp(token, "$addr")) {
  272. debug(14, 1) ("ipcacheParse: Got '%s', expecting '$addr'n", token);
  273. return &i;
  274.     }
  275.     token = strtok(NULL, w_space);
  276.     if (NULL == token) {
  277. debug(14, 1) ("ipcacheParse: Got <NULL>, expecting TTLn");
  278. return &i;
  279.     }
  280.     i.status = IP_CACHED;
  281.     ttl = atoi(token);
  282.     if (ttl > 0)
  283. i.expires = squid_curtime + ttl;
  284.     else
  285. i.expires = squid_curtime + Config.positiveDnsTtl;
  286.     while (NULL != (token = strtok(NULL, w_space))) {
  287. xstrncpy(A[ipcount], token, 16);
  288. if (++ipcount == 32)
  289.     break;
  290.     }
  291.     if (0 == ipcount) {
  292. i.addrs.in_addrs = NULL;
  293. i.addrs.bad_mask = NULL;
  294.     } else {
  295. i.addrs.in_addrs = xcalloc(ipcount, sizeof(struct in_addr));
  296. i.addrs.bad_mask = xcalloc(ipcount, sizeof(unsigned char));
  297.     }
  298.     for (j = 0, k = 0; k < ipcount; k++) {
  299. if (safe_inet_addr(A[k], &i.addrs.in_addrs[j]))
  300.     j++;
  301. else
  302.     debug(14, 1) ("ipcacheParse: Invalid IP address '%s'n", A[k]);
  303.     }
  304.     i.addrs.count = (unsigned char) j;
  305.     return &i;
  306. }
  307. static void
  308. ipcacheHandleReply(void *data, char *reply)
  309. {
  310.     int n;
  311.     generic_cbdata *c = data;
  312.     ipcache_entry *i = c->data;
  313.     ipcache_entry *x = NULL;
  314.     assert(i->status == IP_DISPATCHED);
  315.     assert(i->locks);
  316.     cbdataFree(c);
  317.     c = NULL;
  318.     n = ++IpcacheStats.replies;
  319.     statHistCount(&Counter.dns.svc_time, tvSubMsec(i->request_time, current_time));
  320.     x = ipcacheParse(reply);
  321.     assert(x);
  322.     i->status = x->status;
  323.     i->addrs = x->addrs;
  324.     i->error_message = x->error_message;
  325.     i->expires = x->expires;
  326.     ipcache_call_pending(i);
  327.     ipcacheUnlockEntry(i); /* unlock from IP_DISPATCHED */
  328. }
  329. static void
  330. ipcacheAddPending(ipcache_entry * i, IPH * handler, void *handlerData)
  331. {
  332.     ip_pending *pending = memAllocate(MEM_IPCACHE_PENDING);
  333.     ip_pending **I = NULL;
  334.     i->lastref = squid_curtime;
  335.     pending->handler = handler;
  336.     pending->handlerData = handlerData;
  337.     cbdataLock(handlerData);
  338.     for (I = &(i->pending_head); *I; I = &((*I)->next));
  339.     *I = pending;
  340. }
  341. void
  342. ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
  343. {
  344.     ipcache_entry *i = NULL;
  345.     const ipcache_addrs *addrs = NULL;
  346.     generic_cbdata *c;
  347.     assert(handler != NULL);
  348.     debug(14, 4) ("ipcache_nbgethostbyname: Name '%s'.n", name);
  349.     IpcacheStats.requests++;
  350.     if (name == NULL || name[0] == '') {
  351. debug(14, 4) ("ipcache_nbgethostbyname: Invalid name!n");
  352. handler(NULL, handlerData);
  353. return;
  354.     }
  355.     if ((addrs = ipcacheCheckNumeric(name))) {
  356. handler(addrs, handlerData);
  357. return;
  358.     }
  359.     if ((i = ipcache_get(name))) {
  360. if (ipcacheExpiredEntry(i)) {
  361.     ipcache_release(i);
  362.     i = NULL;
  363. }
  364.     }
  365.     if (i == NULL) {
  366. /* MISS: No entry, create the new one */
  367. debug(14, 5) ("ipcache_nbgethostbyname: MISS for '%s'n", name);
  368. IpcacheStats.misses++;
  369. i = ipcacheAddNew(name, NULL, IP_PENDING);
  370. ipcacheAddPending(i, handler, handlerData);
  371. i->request_time = current_time;
  372.     } else if (i->status == IP_CACHED || i->status == IP_NEGATIVE_CACHED) {
  373. /* HIT */
  374. debug(14, 4) ("ipcache_nbgethostbyname: HIT for '%s'n", name);
  375. if (i->status == IP_NEGATIVE_CACHED)
  376.     IpcacheStats.negative_hits++;
  377. else
  378.     IpcacheStats.hits++;
  379. ipcacheAddPending(i, handler, handlerData);
  380. ipcache_call_pending(i);
  381. return;
  382.     } else if (i->status == IP_PENDING || i->status == IP_DISPATCHED) {
  383. debug(14, 4) ("ipcache_nbgethostbyname: PENDING for '%s'n", name);
  384. IpcacheStats.pending_hits++;
  385. ipcacheAddPending(i, handler, handlerData);
  386. if (squid_curtime - i->expires > 600) {
  387.     debug(14, 0) ("ipcache_nbgethostbyname: '%s' PENDING for %d seconds, abortingn", name, (int) (squid_curtime + Config.negativeDnsTtl - i->expires));
  388.     ipcacheChangeKey(i);
  389.     ipcache_call_pending(i);
  390. }
  391. return;
  392.     } else {
  393. fatal_dump("ipcache_nbgethostbyname: BAD ipcache_entry status");
  394.     }
  395.     /* for HIT, PENDING, DISPATCHED we've returned.  For MISS we submit */
  396.     c = xcalloc(1, sizeof(*c));
  397.     c->data = i;
  398.     cbdataAdd(c, cbdataXfree, 0);
  399.     i->status = IP_DISPATCHED;
  400.     ipcacheLockEntry(i);
  401.     dnsSubmit(i->name, ipcacheHandleReply, c);
  402. }
  403. /* initialize the ipcache */
  404. void
  405. ipcache_init(void)
  406. {
  407.     int n;
  408.     debug(14, 3) ("Initializing IP Cache...n");
  409.     memset(&IpcacheStats, '', sizeof(IpcacheStats));
  410.     memset(&lru_list, '', sizeof(lru_list));
  411.     /* test naming lookup */
  412.     if (!opt_dns_tests) {
  413. debug(14, 4) ("ipcache_init: Skipping DNS name lookup tests.n");
  414.     } else if (!ipcache_testname()) {
  415. fatal("ipcache_init: DNS name lookup tests failed.");
  416.     } else {
  417. debug(14, 1) ("Successful DNS name lookup tests...n");
  418.     }
  419.     memset(&static_addrs, '', sizeof(ipcache_addrs));
  420.     static_addrs.in_addrs = xcalloc(1, sizeof(struct in_addr));
  421.     static_addrs.bad_mask = xcalloc(1, sizeof(unsigned char));
  422.     ipcache_high = (long) (((float) Config.ipcache.size *
  423.     (float) Config.ipcache.high) / (float) 100);
  424.     ipcache_low = (long) (((float) Config.ipcache.size *
  425.     (float) Config.ipcache.low) / (float) 100);
  426.     n = hashPrime(ipcache_high / 4);
  427.     ip_table = hash_create((HASHCMP *) strcmp, n, hash4);
  428.     cachemgrRegister("ipcache",
  429. "IP Cache Stats and Contents",
  430. stat_ipcache_get, 0, 1);
  431. }
  432. int
  433. ipcacheUnregister(const char *name, void *data)
  434. {
  435.     ipcache_entry *i = NULL;
  436.     ip_pending *p = NULL;
  437.     int n = 0;
  438.     debug(14, 3) ("ipcacheUnregister: name '%s'n", name);
  439.     if ((i = ipcache_get(name)) == NULL)
  440. return 0;
  441.     if (i->status == IP_PENDING || i->status == IP_DISPATCHED) {
  442. for (p = i->pending_head; p; p = p->next) {
  443.     if (p->handlerData != data)
  444. continue;
  445.     p->handler = NULL;
  446.     n++;
  447. }
  448.     }
  449.     assert(n > 0);
  450.     debug(14, 3) ("ipcacheUnregister: unregistered %d handlersn", n);
  451.     return n;
  452. }
  453. const ipcache_addrs *
  454. ipcache_gethostbyname(const char *name, int flags)
  455. {
  456.     ipcache_entry *i = NULL;
  457.     ipcache_addrs *addrs;
  458.     if (!name)
  459. fatal_dump("ipcache_gethostbyname: NULL name");
  460.     debug(14, 3) ("ipcache_gethostbyname: '%s', flags=%xn", name, flags);
  461.     IpcacheStats.requests++;
  462.     if ((i = ipcache_get(name))) {
  463. if (ipcacheExpiredEntry(i)) {
  464.     ipcache_release(i);
  465.     i = NULL;
  466. }
  467.     }
  468.     if (i) {
  469. if (i->status == IP_NEGATIVE_CACHED) {
  470.     IpcacheStats.negative_hits++;
  471.     dns_error_message = i->error_message;
  472.     return NULL;
  473. } else if (i->addrs.count == 0) {
  474.     (void) 0;
  475. } else {
  476.     IpcacheStats.hits++;
  477.     i->lastref = squid_curtime;
  478.     return &i->addrs;
  479. }
  480.     }
  481.     if ((addrs = ipcacheCheckNumeric(name)))
  482. return addrs;
  483.     IpcacheStats.misses++;
  484.     if (flags & IP_LOOKUP_IF_MISS)
  485. ipcache_nbgethostbyname(name, dummy_handler, NULL);
  486.     return NULL;
  487. }
  488. static void
  489. ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry)
  490. {
  491.     int k;
  492.     storeAppendPrintf(sentry, " %-32.32s  %c%c %6d %6d %2d(%2d)",
  493. i->name,
  494. ipcache_status_char[i->status],
  495. i->locks ? 'L' : ' ',
  496. (int) (squid_curtime - i->lastref),
  497. (int) (i->expires - squid_curtime),
  498. (int) i->addrs.count,
  499. (int) i->addrs.badcount);
  500.     for (k = 0; k < (int) i->addrs.count; k++) {
  501. storeAppendPrintf(sentry, " %15s-%3s", inet_ntoa(i->addrs.in_addrs[k]),
  502.     i->addrs.bad_mask[k] ? "BAD" : "OK ");
  503.     }
  504.     storeAppendPrintf(sentry, "n");
  505. }
  506. /* process objects list */
  507. void
  508. stat_ipcache_get(StoreEntry * sentry)
  509. {
  510.     dlink_node *m;
  511.     assert(ip_table != NULL);
  512.     storeAppendPrintf(sentry, "IP Cache Statistics:n");
  513.     storeAppendPrintf(sentry, "IPcache Entries: %dn",
  514. memInUse(MEM_IPCACHE_ENTRY));
  515.     storeAppendPrintf(sentry, "IPcache Requests: %dn",
  516. IpcacheStats.requests);
  517.     storeAppendPrintf(sentry, "IPcache Hits: %dn",
  518. IpcacheStats.hits);
  519.     storeAppendPrintf(sentry, "IPcache Pending Hits: %dn",
  520. IpcacheStats.pending_hits);
  521.     storeAppendPrintf(sentry, "IPcache Negative Hits: %dn",
  522. IpcacheStats.negative_hits);
  523.     storeAppendPrintf(sentry, "IPcache Misses: %dn",
  524. IpcacheStats.misses);
  525.     storeAppendPrintf(sentry, "Blocking calls to gethostbyname(): %dn",
  526. IpcacheStats.ghbn_calls);
  527.     storeAppendPrintf(sentry, "Attempts to release locked entries: %dn",
  528. IpcacheStats.release_locked);
  529.     storeAppendPrintf(sentry, "nn");
  530.     storeAppendPrintf(sentry, "IP Cache Contents:nn");
  531.     storeAppendPrintf(sentry, " %-29.29s %5s %6s %6s %1sn",
  532. "Hostname",
  533. "Flags",
  534. "lstref",
  535. "TTL",
  536. "N");
  537.     for (m = lru_list.head; m; m = m->next)
  538. ipcacheStatPrint(m->data, sentry);
  539. }
  540. static void
  541. dummy_handler(const ipcache_addrs * addrsnotused, void *datanotused)
  542. {
  543.     return;
  544. }
  545. void
  546. ipcacheReleaseInvalid(const char *name)
  547. {
  548.     ipcache_entry *i;
  549.     if (NULL == name) {
  550. debug(14, 1) ("ipcacheReleaseInvalid: NULL namen");
  551. return;
  552.     }
  553.     if (0 == strlen(name)) {
  554. debug(14, 1) ("ipcacheReleaseInvalid: Empty namen");
  555. return;
  556.     }
  557.     if ((i = ipcache_get(name)) == NULL)
  558. return;
  559.     if (i->status != IP_NEGATIVE_CACHED)
  560. return;
  561.     ipcache_release(i);
  562. }
  563. void
  564. ipcacheInvalidate(const char *name)
  565. {
  566.     ipcache_entry *i;
  567.     if ((i = ipcache_get(name)) == NULL)
  568. return;
  569.     i->expires = squid_curtime;
  570.     /* NOTE, don't call ipcache_release here becuase we might be here due
  571.      * to a thread started from ipcache_call_pending() which will cause a
  572.      * FMR */
  573. }
  574. ipcache_addrs *
  575. ipcacheCheckNumeric(const char *name)
  576. {
  577.     struct in_addr ip;
  578.     /* check if it's already a IP address in text form. */
  579.     if (!safe_inet_addr(name, &ip))
  580. return NULL;
  581.     static_addrs.count = 1;
  582.     static_addrs.cur = 0;
  583.     static_addrs.in_addrs[0].s_addr = ip.s_addr;
  584.     static_addrs.bad_mask[0] = FALSE;
  585.     static_addrs.badcount = 0;
  586.     return &static_addrs;
  587. }
  588. static void
  589. ipcacheLockEntry(ipcache_entry * i)
  590. {
  591.     if (i->locks++ == 0) {
  592. dlinkDelete(&i->lru, &lru_list);
  593. dlinkAdd(i, &i->lru, &lru_list);
  594.     }
  595. }
  596. static void
  597. ipcacheUnlockEntry(ipcache_entry * i)
  598. {
  599.     assert(i->locks > 0);
  600.     i->locks--;
  601.     if (ipcacheExpiredEntry(i))
  602. ipcache_release(i);
  603. }
  604. void
  605. ipcacheCycleAddr(const char *name, ipcache_addrs * ia)
  606. {
  607.     ipcache_entry *i;
  608.     unsigned char k;
  609.     assert(name || ia);
  610.     if (NULL == ia) {
  611. if ((i = ipcache_get(name)) == NULL)
  612.     return;
  613. if (i->status != IP_CACHED)
  614.     return;
  615. ia = &i->addrs;
  616.     }
  617.     for (k = 0; k < ia->count; k++) {
  618. if (++ia->cur == ia->count)
  619.     ia->cur = 0;
  620. if (!ia->bad_mask[ia->cur])
  621.     break;;
  622.     }
  623.     if (k == ia->count) {
  624. /* All bad, reset to All good */
  625. debug(14, 3) ("ipcacheCycleAddr: Changing ALL %s addrs from BAD to OKn",
  626.     name);
  627. for (k = 0; k < ia->count; k++)
  628.     ia->bad_mask[k] = 0;
  629. ia->badcount = 0;
  630. ia->cur = 0;
  631.     }
  632.     debug(14, 3) ("ipcacheCycleAddr: %s now at %sn", name,
  633. inet_ntoa(ia->in_addrs[ia->cur]));
  634. }
  635. /*
  636.  * Marks the given address as BAD and calls ipcacheCycleAddr to
  637.  * advance the current pointer to the next OK address.
  638.  */
  639. void
  640. ipcacheMarkBadAddr(const char *name, struct in_addr addr)
  641. {
  642.     ipcache_entry *i;
  643.     ipcache_addrs *ia;
  644.     int k;
  645.     if ((i = ipcache_get(name)) == NULL)
  646. return;
  647.     ia = &i->addrs;
  648.     for (k = 0; k < (int) ia->count; k++) {
  649. if (ia->in_addrs[k].s_addr == addr.s_addr)
  650.     break;
  651.     }
  652.     if (k == (int) ia->count) /* not found */
  653. return;
  654.     if (!ia->bad_mask[k]) {
  655. ia->bad_mask[k] = TRUE;
  656. ia->badcount++;
  657. debug(14, 2) ("ipcacheMarkBadAddr: %s [%s]n", name, inet_ntoa(addr));
  658.     }
  659.     ipcacheCycleAddr(name, ia);
  660. }
  661. void
  662. ipcacheMarkGoodAddr(const char *name, struct in_addr addr)
  663. {
  664.     ipcache_entry *i;
  665.     ipcache_addrs *ia;
  666.     int k;
  667.     if ((i = ipcache_get(name)) == NULL)
  668. return;
  669.     ia = &i->addrs;
  670.     for (k = 0; k < (int) ia->count; k++) {
  671. if (ia->in_addrs[k].s_addr == addr.s_addr)
  672.     break;
  673.     }
  674.     if (k == (int) ia->count) /* not found */
  675. return;
  676.     if (!ia->bad_mask[k]) /* already OK */
  677. return;
  678.     ia->bad_mask[k] = FALSE;
  679.     ia->badcount--;
  680.     debug(14, 2) ("ipcacheMarkGoodAddr: %s [%s]n", name, inet_ntoa(addr));
  681. }
  682. static void
  683. ipcacheFreeEntry(void *data)
  684. {
  685.     ipcache_entry *i = data;
  686.     ip_pending *p;
  687.     while ((p = i->pending_head)) {
  688. i->pending_head = p->next;
  689. memFree(p, MEM_IPCACHE_PENDING);
  690.     }
  691.     safe_free(i->addrs.in_addrs);
  692.     safe_free(i->addrs.bad_mask);
  693.     safe_free(i->name);
  694.     safe_free(i->error_message);
  695.     memFree(i, MEM_IPCACHE_ENTRY);
  696. }
  697. void
  698. ipcacheFreeMemory(void)
  699. {
  700.     hashFreeItems(ip_table, ipcacheFreeEntry);
  701.     hashFreeMemory(ip_table);
  702.     ip_table = NULL;
  703. }
  704. static void
  705. ipcacheChangeKey(ipcache_entry * i)
  706. {
  707.     static int index = 0;
  708.     LOCAL_ARRAY(char, new_key, 256);
  709.     hash_link *table_entry = hash_lookup(ip_table, i->name);
  710.     if (table_entry == NULL) {
  711. debug(14, 0) ("ipcacheChangeKey: Could not find key '%s'n", i->name);
  712. return;
  713.     }
  714.     assert(i == (ipcache_entry *) table_entry);
  715.     hash_remove_link(ip_table, table_entry);
  716.     snprintf(new_key, 256, "%d/%s", ++index, i->name);
  717.     debug(14, 1) ("ipcacheChangeKey: from '%s' to '%s'n", i->name, new_key);
  718.     safe_free(i->name);
  719.     i->name = xstrdup(new_key);
  720.     hash_join(ip_table, (hash_link *) i);
  721. }
  722. /* call during reconfigure phase to clear out all the 
  723.  * pending and dispatched reqeusts that got lost */
  724. void
  725. ipcache_restart(void)
  726. {
  727.     ipcache_entry *this;
  728.     assert(ip_table != NULL);
  729.     hash_first(ip_table);
  730.     while ((this = (ipcache_entry *) hash_next(ip_table))) {
  731. if (this->status == IP_CACHED)
  732.     continue;
  733. if (this->status == IP_NEGATIVE_CACHED)
  734.     continue;
  735.     }
  736.     /* recalculate these while we're at it */
  737.     ipcache_high = (long) (((float) Config.ipcache.size *
  738.     (float) Config.ipcache.high) / (float) 100);
  739.     ipcache_low = (long) (((float) Config.ipcache.size *
  740.     (float) Config.ipcache.low) / (float) 100);
  741. }
  742. #ifdef SQUID_SNMP
  743. /*
  744.  * The function to return the ip cache statistics to via SNMP
  745.  */
  746. variable_list *
  747. snmp_netIpFn(variable_list * Var, snint * ErrP)
  748. {
  749.     variable_list *Answer;
  750.     debug(49, 5) ("snmp_netIpFn: Processing request:n", Var->name[LEN_SQ_NET + 1]);
  751.     snmpDebugOid(5, Var->name, Var->name_length);
  752.     Answer = snmp_var_new(Var->name, Var->name_length);
  753.     *ErrP = SNMP_ERR_NOERROR;
  754.     Answer->val_len = sizeof(snint);
  755.     Answer->val.integer = xmalloc(Answer->val_len);
  756.     Answer->type = SMI_COUNTER32;
  757.     switch (Var->name[LEN_SQ_NET + 1]) {
  758.     case IP_ENT:
  759. *(Answer->val.integer) = memInUse(MEM_IPCACHE_ENTRY);
  760. Answer->type = SMI_GAUGE32;
  761. break;
  762.     case IP_REQ:
  763. *(Answer->val.integer) = IpcacheStats.requests;
  764. break;
  765.     case IP_HITS:
  766. *(Answer->val.integer) = IpcacheStats.hits;
  767. break;
  768.     case IP_PENDHIT:
  769. *(Answer->val.integer) = IpcacheStats.pending_hits;
  770. Answer->type = SMI_GAUGE32;
  771. break;
  772.     case IP_NEGHIT:
  773. *(Answer->val.integer) = IpcacheStats.negative_hits;
  774. break;
  775.     case IP_MISS:
  776. *(Answer->val.integer) = IpcacheStats.misses;
  777. break;
  778.     case IP_GHBN:
  779. *(Answer->val.integer) = IpcacheStats.ghbn_calls;
  780. break;
  781.     case IP_LOC:
  782. *(Answer->val.integer) = IpcacheStats.release_locked;
  783. break;
  784.     default:
  785. *ErrP = SNMP_ERR_NOSUCHNAME;
  786. snmp_var_free(Answer);
  787. return (NULL);
  788.     }
  789.     return Answer;
  790. }
  791. #endif /*SQUID_SNMP */