📄 ipcache.c
字号:
/* * $Id: ipcache.c,v 1.210 1998/12/05 00:54:30 wessels Exp $ * * DEBUG: section 14 IP Cache * AUTHOR: Harvest Derived * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from the * Internet community. Development is led by Duane Wessels of the * National Laboratory for Applied Network Research and funded by the * National Science Foundation. Squid is Copyrighted (C) 1998 by * Duane Wessels and the University of California San Diego. Please * see the COPYRIGHT file for full details. Squid incorporates * software developed and/or copyrighted by other sources. Please see * the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */#include "squid.h"static struct { int requests; int replies; int hits; int misses; int pending_hits; int negative_hits; int errors; int ghbn_calls; /* # calls to blocking gethostbyname() */ int release_locked;} IpcacheStats;static dlink_list lru_list;static FREE ipcacheFreeEntry;static HLPCB ipcacheHandleReply;static IPH dummy_handler;static int ipcacheExpiredEntry(ipcache_entry *);static int ipcache_testname(void);static ipcache_entry *ipcacheAddNew(const char *, const struct hostent *, ipcache_status_t);static ipcache_entry *ipcacheParse(const char *buf);static ipcache_entry *ipcache_create(const char *name);static ipcache_entry *ipcache_get(const char *);static void ipcacheAddHostent(ipcache_entry *, const struct hostent *);static void ipcacheAddPending(ipcache_entry *, IPH *, void *);static void ipcacheChangeKey(ipcache_entry * i);static void ipcacheLockEntry(ipcache_entry *);static void ipcacheStatPrint(ipcache_entry *, StoreEntry *);static void ipcacheUnlockEntry(ipcache_entry *);static void ipcache_call_pending(ipcache_entry *);static void ipcache_release(ipcache_entry *);static ipcache_addrs static_addrs;static hash_table *ip_table = NULL;static char ipcache_status_char[] ={ 'C', 'N', 'P', 'D'};static long ipcache_low = 180;static long ipcache_high = 200;#if LIBRESOLV_DNS_TTL_HACKextern int _dns_ttl_;#endifstatic intipcache_testname(void){ wordlist *w = NULL; debug(14, 1) ("Performing DNS Tests...\n"); if ((w = Config.dns_testname_list) == NULL) return 1; for (; w; w = w->next) { IpcacheStats.ghbn_calls++; if (gethostbyname(w->key) != NULL) return 1; } return 0;}/* removes the given ipcache entry */static voidipcache_release(ipcache_entry * i){ hash_link *table_entry = NULL; if ((table_entry = hash_lookup(ip_table, i->name)) == NULL) { snprintf(tmp_error_buf, ERROR_BUF_SZ, "ipcache_release: key '%s' not found\n", i->name); fatal_dump(tmp_error_buf); } assert(i == (ipcache_entry *) table_entry); if (i->locks) { i->expires = squid_curtime; ipcacheChangeKey(i); IpcacheStats.release_locked++; return; } hash_remove_link(ip_table, table_entry); dlinkDelete(&i->lru, &lru_list); if (i->status == IP_CACHED) { safe_free(i->addrs.in_addrs); safe_free(i->addrs.bad_mask); debug(14, 5) ("ipcache_release: Released IP cached record for '%s'.\n", i->name); } safe_free(i->name); safe_free(i->error_message); memFree(i, MEM_IPCACHE_ENTRY); return;}static ipcache_entry *ipcache_get(const char *name){ assert(ip_table != NULL); return (ipcache_entry *) hash_lookup(ip_table, name);}static intipcacheExpiredEntry(ipcache_entry * i){ if (i->status == IP_PENDING) return 0; if (i->status == IP_DISPATCHED) return 0; if (i->locks != 0) return 0; if (i->addrs.count == 0) return 1; if (i->expires > squid_curtime) return 0; return 1;}voidipcache_purgelru(void *voidnotused){ dlink_node *m; dlink_node *prev = NULL; ipcache_entry *i; int removed = 0; eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1); for (m = lru_list.tail; m; m = prev) { if (memInUse(MEM_IPCACHE_ENTRY) < ipcache_low) break; prev = m->prev; i = m->data; if (i->status == IP_PENDING) continue; if (i->status == IP_DISPATCHED) continue; if (i->locks != 0) continue; ipcache_release(i); removed++; } debug(14, 9) ("ipcache_purgelru: removed %d entries\n", removed);}/* create blank ipcache_entry */static ipcache_entry *ipcache_create(const char *name){ static ipcache_entry *i; i = memAllocate(MEM_IPCACHE_ENTRY); i->name = xstrdup(name); i->expires = squid_curtime + Config.negativeDnsTtl; hash_join(ip_table, (hash_link *) i); dlinkAdd(i, &i->lru, &lru_list); return i;}static voidipcacheAddHostent(ipcache_entry * i, const struct hostent *hp){ int addr_count = 0; int k; safe_free(i->addrs.in_addrs); safe_free(i->addrs.bad_mask); while ((addr_count < 255) && *(hp->h_addr_list + addr_count)) ++addr_count; i->addrs.count = (unsigned char) addr_count; i->addrs.in_addrs = xcalloc(addr_count, sizeof(struct in_addr)); i->addrs.bad_mask = xcalloc(addr_count, sizeof(unsigned char)); i->addrs.badcount = 0; for (k = 0; k < addr_count; k++) xmemcpy(&i->addrs.in_addrs[k].s_addr, *(hp->h_addr_list + k), hp->h_length);}static ipcache_entry *ipcacheAddNew(const char *name, const struct hostent *hp, ipcache_status_t status){ ipcache_entry *i; if (ipcache_get(name)) fatal_dump("ipcacheAddNew: somebody adding a duplicate!"); debug(14, 10) ("ipcacheAddNew: Adding '%s', status=%c\n", name, ipcache_status_char[status]); i = ipcache_create(name); if (hp) ipcacheAddHostent(i, hp); i->status = status; i->lastref = squid_curtime; return i;}/* walks down the pending list, calling handlers */static voidipcache_call_pending(ipcache_entry * i){ ip_pending *p = NULL; int nhandler = 0; i->lastref = squid_curtime; ipcacheLockEntry(i); while (i->pending_head != NULL) { p = i->pending_head; i->pending_head = p->next; if (p->handler) { nhandler++; dns_error_message = i->error_message; if (cbdataValid(p->handlerData)) { p->handler(i->status == IP_CACHED ? &i->addrs : NULL, p->handlerData); } cbdataUnlock(p->handlerData); } memFree(p, MEM_IPCACHE_PENDING); } i->pending_head = NULL; /* nuke list */ debug(14, 10) ("ipcache_call_pending: Called %d handlers.\n", nhandler); ipcacheUnlockEntry(i);}static ipcache_entry *ipcacheParse(const char *inbuf){ LOCAL_ARRAY(char, buf, DNS_INBUF_SZ); char *token; static ipcache_entry i; int j; int k; int ipcount = 0; int ttl; char A[32][16]; memset(&i, '\0', sizeof(i)); i.expires = squid_curtime; i.status = IP_NEGATIVE_CACHED; if (inbuf == NULL) { debug(14, 1) ("ipcacheParse: Got <NULL> reply\n"); i.error_message = xstrdup("Internal Squid Error"); return &i; } xstrncpy(buf, inbuf, DNS_INBUF_SZ); debug(14, 5) ("ipcacheParse: parsing: {%s}\n", buf); token = strtok(buf, w_space); if (NULL == token) { debug(14, 1) ("ipcacheParse: Got <NULL>, expecting '$addr'\n"); return &i; } if (0 == strcmp(token, "$fail")) { i.expires = squid_curtime + Config.negativeDnsTtl; token = strtok(NULL, "\n"); assert(NULL != token); i.error_message = xstrdup(token); return &i; } if (0 != strcmp(token, "$addr")) { debug(14, 1) ("ipcacheParse: Got '%s', expecting '$addr'\n", token); return &i; } token = strtok(NULL, w_space); if (NULL == token) { debug(14, 1) ("ipcacheParse: Got <NULL>, expecting TTL\n"); return &i; } i.status = IP_CACHED; ttl = atoi(token); if (ttl > 0) i.expires = squid_curtime + ttl; else i.expires = squid_curtime + Config.positiveDnsTtl; while (NULL != (token = strtok(NULL, w_space))) { xstrncpy(A[ipcount], token, 16); if (++ipcount == 32) break; } if (0 == ipcount) { i.addrs.in_addrs = NULL; i.addrs.bad_mask = NULL; } else { i.addrs.in_addrs = xcalloc(ipcount, sizeof(struct in_addr)); i.addrs.bad_mask = xcalloc(ipcount, sizeof(unsigned char)); } for (j = 0, k = 0; k < ipcount; k++) { if (safe_inet_addr(A[k], &i.addrs.in_addrs[j])) j++; else debug(14, 1) ("ipcacheParse: Invalid IP address '%s'\n", A[k]); } i.addrs.count = (unsigned char) j; return &i;}static voidipcacheHandleReply(void *data, char *reply){ int n; generic_cbdata *c = data; ipcache_entry *i = c->data; ipcache_entry *x = NULL; assert(i->status == IP_DISPATCHED); assert(i->locks); cbdataFree(c); c = NULL; n = ++IpcacheStats.replies; statHistCount(&Counter.dns.svc_time, tvSubMsec(i->request_time, current_time)); x = ipcacheParse(reply); assert(x); i->status = x->status; i->addrs = x->addrs; i->error_message = x->error_message; i->expires = x->expires; ipcache_call_pending(i); ipcacheUnlockEntry(i); /* unlock from IP_DISPATCHED */}static voidipcacheAddPending(ipcache_entry * i, IPH * handler, void *handlerData){ ip_pending *pending = memAllocate(MEM_IPCACHE_PENDING); ip_pending **I = NULL; i->lastref = squid_curtime; pending->handler = handler; pending->handlerData = handlerData; cbdataLock(handlerData); for (I = &(i->pending_head); *I; I = &((*I)->next)); *I = pending;}voidipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData){ ipcache_entry *i = NULL; const ipcache_addrs *addrs = NULL; generic_cbdata *c; assert(handler != NULL); debug(14, 4) ("ipcache_nbgethostbyname: Name '%s'.\n", name); IpcacheStats.requests++; if (name == NULL || name[0] == '\0') { debug(14, 4) ("ipcache_nbgethostbyname: Invalid name!\n"); handler(NULL, handlerData); return; } if ((addrs = ipcacheCheckNumeric(name))) { handler(addrs, handlerData); return; } if ((i = ipcache_get(name))) { if (ipcacheExpiredEntry(i)) { ipcache_release(i); i = NULL; } } if (i == NULL) { /* MISS: No entry, create the new one */ debug(14, 5) ("ipcache_nbgethostbyname: MISS for '%s'\n", name); IpcacheStats.misses++; i = ipcacheAddNew(name, NULL, IP_PENDING); ipcacheAddPending(i, handler, handlerData); i->request_time = current_time; } else if (i->status == IP_CACHED || i->status == IP_NEGATIVE_CACHED) { /* HIT */ debug(14, 4) ("ipcache_nbgethostbyname: HIT for '%s'\n", name); if (i->status == IP_NEGATIVE_CACHED) IpcacheStats.negative_hits++; else IpcacheStats.hits++; ipcacheAddPending(i, handler, handlerData); ipcache_call_pending(i); return; } else if (i->status == IP_PENDING || i->status == IP_DISPATCHED) { debug(14, 4) ("ipcache_nbgethostbyname: PENDING for '%s'\n", name); IpcacheStats.pending_hits++; ipcacheAddPending(i, handler, handlerData); if (squid_curtime - i->expires > 600) { debug(14, 0) ("ipcache_nbgethostbyname: '%s' PENDING for %d seconds, aborting\n", name, (int) (squid_curtime + Config.negativeDnsTtl - i->expires)); ipcacheChangeKey(i); ipcache_call_pending(i); } return; } else { fatal_dump("ipcache_nbgethostbyname: BAD ipcache_entry status"); } /* for HIT, PENDING, DISPATCHED we've returned. For MISS we submit */ c = xcalloc(1, sizeof(*c)); c->data = i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -