📄 fqdncache.c
字号:
/* * $Id: fqdncache.c,v 1.126 1998/12/05 00:54:24 wessels Exp $ * * DEBUG: section 35 FQDN 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"#define FQDN_LOW_WATER 90#define FQDN_HIGH_WATER 95static struct { int requests; int replies; int hits; int misses; int pending_hits; int negative_hits; int errors; int ghba_calls; /* # calls to blocking gethostbyaddr() */} FqdncacheStats;static dlink_list lru_list;static HLPCB fqdncacheHandleReply;static fqdncache_entry *fqdncacheParse(const char *buf);static void fqdncache_release(fqdncache_entry *);static fqdncache_entry *fqdncache_create(const char *name);static void fqdncache_call_pending(fqdncache_entry *);static void fqdncacheAddHostent(fqdncache_entry *, const struct hostent *);static fqdncache_entry *fqdncache_get(const char *);static FQDNH dummy_handler;static int fqdncacheExpiredEntry(const fqdncache_entry *);static void fqdncacheAddPending(fqdncache_entry *, FQDNH *, void *);static void fqdncacheChangeKey(fqdncache_entry * i);static void fqdncacheLockEntry(fqdncache_entry * f);static void fqdncacheUnlockEntry(fqdncache_entry * f);static FREE fqdncacheFreeEntry;static hash_table *fqdn_table = NULL;static char fqdncache_status_char[] ={ 'C', 'N', 'P', 'D'};static long fqdncache_low = 180;static long fqdncache_high = 200;/* removes the given fqdncache entry */static voidfqdncache_release(fqdncache_entry * f){ int k; assert(f->status != FQDN_PENDING); assert(f->status != FQDN_DISPATCHED); assert(f->pending_head == NULL); hash_remove_link(fqdn_table, (hash_link *) f); if (f->status == FQDN_CACHED) { for (k = 0; k < (int) f->name_count; k++) safe_free(f->names[k]); debug(35, 5) ("fqdncache_release: Released FQDN record for '%s'.\n", f->name); } dlinkDelete(&f->lru, &lru_list); safe_free(f->name); safe_free(f->error_message); memFree(f, MEM_FQDNCACHE_ENTRY);}/* return match for given name */static fqdncache_entry *fqdncache_get(const char *name){ hash_link *e; static fqdncache_entry *f; f = NULL; if (fqdn_table) { if ((e = hash_lookup(fqdn_table, name)) != NULL) f = (fqdncache_entry *) e; } return f;}static intfqdncacheExpiredEntry(const fqdncache_entry * f){ if (f->status == FQDN_PENDING) return 0; if (f->status == FQDN_DISPATCHED) return 0; if (f->locks != 0) return 0; if (f->expires > squid_curtime) return 0; return 1;}voidfqdncache_purgelru(void *notused){ dlink_node *m; dlink_node *prev = NULL; fqdncache_entry *f; int removed = 0; eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 10.0, 1); for (m = lru_list.tail; m; m = prev) { if (memInUse(MEM_FQDNCACHE_ENTRY) < fqdncache_low) break; prev = m->prev; f = m->data; if (f->status == FQDN_PENDING) continue; if (f->status == FQDN_DISPATCHED) continue; if (f->locks != 0) continue; fqdncache_release(f); removed++; } debug(35, 9) ("fqdncache_purgelru: removed %d entries\n", removed);}/* create blank fqdncache_entry */static fqdncache_entry *fqdncache_create(const char *name){ static fqdncache_entry *f; f = memAllocate(MEM_FQDNCACHE_ENTRY); f->name = xstrdup(name); f->expires = squid_curtime + Config.negativeDnsTtl; hash_join(fqdn_table, (hash_link *) f); dlinkAdd(f, &f->lru, &lru_list); return f;}static voidfqdncacheAddHostent(fqdncache_entry * f, const struct hostent *hp){ int k; f->name_count = 0; f->names[f->name_count++] = xstrdup((char *) hp->h_name); for (k = 0; hp->h_aliases[k]; k++) { f->names[f->name_count++] = xstrdup(hp->h_aliases[k]); if (f->name_count == FQDN_MAX_NAMES) break; }}static fqdncache_entry *fqdncacheAddNew(const char *name, const struct hostent *hp, fqdncache_status_t status){ fqdncache_entry *f; assert(fqdncache_get(name) == NULL); debug(35, 10) ("fqdncacheAddNew: Adding '%s', status=%c\n", name, fqdncache_status_char[status]); f = fqdncache_create(name); if (hp) fqdncacheAddHostent(f, hp); f->status = status; f->lastref = squid_curtime; return f;}/* walks down the pending list, calling handlers */static voidfqdncache_call_pending(fqdncache_entry * f){ fqdn_pending *p = NULL; int nhandler = 0; f->lastref = squid_curtime; fqdncacheLockEntry(f); while (f->pending_head != NULL) { p = f->pending_head; f->pending_head = p->next; if (p->handler) { nhandler++; dns_error_message = f->error_message; p->handler((f->status == FQDN_CACHED) ? f->names[0] : NULL, p->handlerData); } memFree(p, MEM_FQDNCACHE_PENDING); } f->pending_head = NULL; /* nuke list */ debug(35, 10) ("fqdncache_call_pending: Called %d handlers.\n", nhandler); fqdncacheUnlockEntry(f);}static fqdncache_entry *fqdncacheParse(const char *inbuf){ LOCAL_ARRAY(char, buf, DNS_INBUF_SZ); char *token; static fqdncache_entry f; int ttl; xstrncpy(buf, inbuf, DNS_INBUF_SZ); debug(35, 5) ("fqdncacheParse: parsing: {%s}\n", buf); memset(&f, '\0', sizeof(f)); f.expires = squid_curtime; f.status = FQDN_NEGATIVE_CACHED; if (inbuf == NULL) { debug(35, 1) ("fqdncacheParse: Got <NULL> reply\n"); return &f; } token = strtok(buf, w_space); if (NULL == token) { debug(35, 1) ("fqdncacheParse: Got <NULL>, expecting '$name'\n"); return &f; } if (0 == strcmp(token, "$fail")) { f.expires = squid_curtime + Config.negativeDnsTtl; token = strtok(NULL, "\n"); assert(NULL != token); f.error_message = xstrdup(token); return &f; } if (0 != strcmp(token, "$name")) { debug(35, 1) ("fqdncacheParse: Got '%s', expecting '$name'\n", token); return &f; } token = strtok(NULL, w_space); if (NULL == token) { debug(35, 1) ("fqdncacheParse: Got <NULL>, expecting TTL\n"); return &f; } f.status = FQDN_CACHED; ttl = atoi(token); if (ttl > 0) f.expires = squid_curtime + ttl; else f.expires = squid_curtime + Config.positiveDnsTtl; token = strtok(NULL, w_space); if (NULL != token) { f.names[0] = xstrdup(token); f.name_count = 1; } return &f;}static voidfqdncacheHandleReply(void *data, char *reply){ int n; generic_cbdata *c = data; fqdncache_entry *f = c->data; fqdncache_entry *x = NULL; assert(f->status == FQDN_DISPATCHED); assert(f->locks); cbdataFree(c); c = NULL; n = ++FqdncacheStats.replies; statHistCount(&Counter.dns.svc_time, tvSubMsec(f->request_time, current_time)); x = fqdncacheParse(reply); assert(x); f->name_count = x->name_count; for (n = 0; n < (int) f->name_count; n++) f->names[n] = x->names[n]; f->error_message = x->error_message; f->status = x->status; f->expires = x->expires; fqdncache_call_pending(f); fqdncacheUnlockEntry(f); /* unlock from FQDN_DISPATCHED */}static voidfqdncacheAddPending(fqdncache_entry * f, FQDNH * handler, void *handlerData){ fqdn_pending *pending = memAllocate(MEM_FQDNCACHE_PENDING); fqdn_pending **I = NULL; f->lastref = squid_curtime; pending->handler = handler; pending->handlerData = handlerData; for (I = &(f->pending_head); *I; I = &((*I)->next)); *I = pending;}voidfqdncache_nbgethostbyaddr(struct in_addr addr, FQDNH * handler, void *handlerData){ fqdncache_entry *f = NULL; char *name = inet_ntoa(addr); generic_cbdata *c; assert(handler); debug(35, 4) ("fqdncache_nbgethostbyaddr: Name '%s'.\n", name); FqdncacheStats.requests++; if (name == NULL || name[0] == '\0') { debug(35, 4) ("fqdncache_nbgethostbyaddr: Invalid name!\n"); handler(NULL, handlerData); return; } if ((f = fqdncache_get(name))) { if (fqdncacheExpiredEntry(f)) { fqdncache_release(f); f = NULL; } } if (f == NULL) { /* MISS: No entry, create the new one */ debug(35, 5) ("fqdncache_nbgethostbyaddr: MISS for '%s'\n", name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -