⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cache.c

📁 此dns服务器是在mydns基础上改写
💻 C
📖 第 1 页 / 共 2 页
字号:
/**************************************************************************************************	$Id: cache.c,v 1.105 2006/01/18 20:46:46 bboy Exp $	Copyright (C) 2002-2005  Don Moore <bboy@bboy.net>	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-1307  USA**************************************************************************************************/#include "named.h"/* Make this nonzero to enable debugging for this source file */#define	DEBUG_CACHE	1/* Set this to nonzero to debug frequency of SQL queries */#define	DEBUG_SQL_QUERIES 1CACHE *ZoneCache = NULL;							/* Data cache */CACHE *ReplyCache = NULL;							/* Reply cache */#if USE_NEGATIVE_CACHECACHE *NegativeCache = NULL;						/* Negative zone cache */#endif#ifdef DN_COLUMN_NAMESextern char	*dn_default_ns;						/* Default NS for directNIC */#endif/**************************************************************************************************sele_matched_zoneadd by zyl 20080403***************************************************************************************************/int select_matched_zone(SQL	*sqlConn, 			/*perl DBI sql connection*/MYDNS_SOA **rptr, 		/*MYDNS_SOA structure pointer*/char *name, 					/*domain name(label)*/char *origin,				/*origin name*/ const char *ipchs			/*requestor ip section*/){	size_t	querylen;	uchar	query[DNS_QUERYBUFSIZ] = "";	uchar 	namequery[DNS_MAXNAMELEN + DNS_MAXNAMELEN + DNS_MAXNAMELEN + 25] = "";	int		namelen = name ? strlen(name) : 0;	uchar		*wheretype;   register char *c;	SQL_RES	*res;	SQL_ROW	row;	/* Verify args */	if (!sqlConn || !rptr)	{		errno = EINVAL;		return (-1);	}		/* Make sure 'name' and 'origin' (if present) are valid */	if (name)	{		for (c = name; *c; c++)			if (SQL_BADCHAR(*c))				return (0);	}	if (origin)	{		for (c = origin; *c; c++)			if (SQL_BADCHAR(*c))				return (0);	}	/*check for matched zone*/	int i          =  0;   int last_count =  0;   int count      =  0;   int len        =  0;   int flag_rows  =  0;	MYDNS_SOA	*soa_cur;	MYDNS_SOA	*soa_target;	soa_cur = *rptr;	while(soa_cur)	{   	/* Construct query */   	if (name)		{			if (origin)			{				if (!name[0])					snprintf(namequery, sizeof(namequery), "(name='' OR name='%s')", origin);				else					snprintf(namequery, sizeof(namequery), "(name='%s' OR name='%s.%s')",						name, name, origin);			}			else				snprintf(namequery, sizeof(namequery), "name='%s'", name);		}		querylen = snprintf(query, sizeof(query),			"SELECT "MYDNS_RR_FIELDS"%s FROM %s WHERE "				"zone=%u AND type='%s'"				"%s%s%s%s",				(mydns_rr_use_active ? ",active" : ""),				mydns_rr_table_name,				soa_cur->id, "A",				namequery[0] ? " AND " : "",				namequery,				(mydns_rr_where_clause) ? " AND " : "",				(mydns_rr_where_clause) ? mydns_rr_where_clause : "");		/* Submit query */		if (!(res = sql_query(sqlConn, query, querylen)))			return (-1);#if DEBUG_ENABLED && DEBUG_LIB_RR		{			int numresults = sql_num_rows(res);			Debug("[*%s*][*%s*]%s RR query: %d row%s: %s",__FILE__,__LINE__, numresults, S(numresults), query);		}#endif   	len 	= 	strlen(ipchs);		count	=	0;		if((row = sql_getrow(res))){			/*check if cur data is more matched than last data*/      	count = 0;      	for(i=0; i < len + 1; i++)      	{         	if(ipchs[i] == row[3][i])            	count++;      	}		}				if(count > last_count)		{			last_count = count;			soa_target = soa_cur;		}			soa_cur = (*rptr)->next;	}//check for matched zone		rptr = &soa_target;	return 0;}/*--- select_matched_zone() ---------------------------------------------------------------------*/#if (HASH_TYPE == ORIGINAL_HASH) || (HASH_TYPE == ADDITIVE_HASH)/**************************************************************************************************	ISPRIME	Returns 1 if `number' is a prime number, 0 if not.**************************************************************************************************/static intisprime(unsigned int number){	register unsigned int divn = 3;	while (divn * divn < number && number % divn != 0)		divn += 2;	return (number % divn != 0);}/*--- isprime() ---------------------------------------------------------------------------------*/#endif/**************************************************************************************************	_CACHE_INIT	Create, initialize, and return a new CACHE structure.**************************************************************************************************/static CACHE *_cache_init(uint32_t limit, uint32_t expire, const char *desc){	CACHE *C;	if (!(C = calloc(1, sizeof(CACHE))))		Err(_("out of memory"));	C->limit = limit;	C->expire = expire;#if (HASH_TYPE == ORIGINAL_HASH) || (HASH_TYPE == ADDITIVE_HASH)	/* Make `slots' prime */	C->slots = limit * CACHE_SLOT_MULTIPLIER;	C->slots |= 1;	while (!isprime(C->slots))		C->slots += 2;#elif (HASH_TYPE == ROTATING_HASH) || (HASH_TYPE == FNV_HASH)	/* Make `slots' a power of two */	{		int		bits;		uint32_t	slots;		C->slots = limit * CACHE_SLOT_MULTIPLIER;		for (slots = C->slots, bits = 0; slots != 1; )		{			slots >>= 1;			bits++;		}		if (C->slots & ((1 << bits) - 1))			bits++;		slots = 1 << bits;   	C->slots = slots;#if (HASH_TYPE == ROTATING_HASH)		C->mask = C->slots - 1;#endif#if (HASH_TYPE == FNV_HASH)		/* A 16-bit hash lets us use XOR instead of MOD to clamp the value - very fast */		if (C->slots < 65536)			C->slots = 65536;		for (C->bits = 0; C->bits < 32; C->bits++)			if (((uint32_t)1 << C->bits) == C->slots)				break;#endif	}#else#	error Hash method unknown or unspecified#endif	if (!(C->nodes = calloc(C->slots, sizeof(CNODE *))))		Err(_("out of memory"));#if DEBUG_ENABLED && DEBUG_CACHE#if (HASH_TYPE == ORIGINAL_HASH)		Debug("%s cache initialized (%u nodes, %u elements max) (original hash)", desc, C->slots, limit);#elif (HASH_TYPE == ADDITIVE_HASH)		Debug("%s cache initialized (%u nodes, %u elements max) (additive hash)", desc, C->slots, limit);#elif (HASH_TYPE == ROTATING_HASH)		Debug("%s cache initialized (%u nodes, %u elements max) (rotating hash)", desc, C->slots, limit);#elif (HASH_TYPE == FNV_HASH)		Debug("%s cache initialized (%u nodes, %u elements max) (%d-bit FNV hash)", desc, C->slots, limit, C->bits);#else#	error Hash method unknown or unspecified#endif#endif	strncpy(C->name, desc, sizeof(C->name)-1);	return (C);}/*--- _cache_init() -----------------------------------------------------------------------------*//**************************************************************************************************	CACHE_INIT	Create the caches used by MyDNS.**************************************************************************************************/voidcache_init(void){	uint32_t	cache_size, zone_cache_size, reply_cache_size;	int		defaulted;	int		zone_cache_expire, reply_cache_expire;	/* Get ZoneCache size */	zone_cache_size = atou(conf_get(&Conf, "zone-cache-size", &defaulted));	if (defaulted)	{		cache_size = atou(conf_get(&Conf, "cache-size", NULL));		zone_cache_size = cache_size - (cache_size / 3);	}	zone_cache_expire = atou(conf_get(&Conf, "zone-cache-expire", &defaulted));	if (defaulted)		zone_cache_expire = atou(conf_get(&Conf, "cache-expire", NULL));	/* Get ReplyCache size */	reply_cache_size = atou(conf_get(&Conf, "reply-cache-size", &defaulted));	if (defaulted)	{		cache_size = atou(conf_get(&Conf, "cache-size", NULL));		reply_cache_size = cache_size / 3;	}	reply_cache_expire = atou(conf_get(&Conf, "reply-cache-expire", &defaulted));	if (defaulted)		reply_cache_expire = atou(conf_get(&Conf, "cache-expire", NULL)) / 2;	/* Initialize caches */	if (zone_cache_size)		ZoneCache = _cache_init(zone_cache_size, zone_cache_expire, "zone");#if USE_NEGATIVE_CACHE	if (zone_cache_size)		NegativeCache = _cache_init(zone_cache_size, zone_cache_expire, "negative");#endif	if (reply_cache_size)		ReplyCache = _cache_init(reply_cache_size, reply_cache_expire, "reply");}/*--- cache_init() ------------------------------------------------------------------------------*//**************************************************************************************************	CACHE_SIZE_UPDATE	Updates the 'size' variable in a cache.**************************************************************************************************/static voidcache_size_update(CACHE *C){	register int n;	register CNODE *N;	C->size = 0;	C->size += sizeof(CACHE);	/* Get size of all data in cache */	for (n = 0; n < C->slots; n++)		for (N = C->nodes[n]; N; N = N->next_node)		{			C->size += sizeof(CNODE);			if (C == ZoneCache)			{				if (N->data)				{					if (N->type == DNS_QTYPE_SOA)						C->size += mydns_soa_size((MYDNS_SOA *)N->data);					else						C->size += mydns_rr_size((MYDNS_RR *)N->data);				}			}			else 				C->size += N->datalen;		}}/*--- cache_size_update() -----------------------------------------------------------------------*//**************************************************************************************************	CACHE_STATUS	Called when SIGUSR1 is received, returns a string to append to status.**************************************************************************************************/voidcache_status(CACHE *C){	if (C)	{		register int ct, collisions;		register CNODE *n;		/* Update cache size (bytes) */		cache_size_update(C);		/* Count number of collisions */		for (ct = collisions = 0; ct < C->slots; ct++)			if (C->nodes[ct] && C->nodes[ct]->next_node)				for (n = C->nodes[ct]->next_node; n; n = n->next_node)					collisions++;		Notice(_("%s cache %.0f%% useful (%u hits, %u misses),"					" %u collisions (%.0f%%), %.0f%% full (%u records), %u bytes, avg life %u sec"),			C->name, PCT(C->questions, C->hits), C->hits, C->misses,			collisions, PCT(C->slots, collisions),			PCT(C->limit, C->count), C->count, C->size,			(unsigned int)(C->removed ? C->removed_secs / C->removed : (time(NULL) - Status.start_time))		);	}}/*--- cache_status() ----------------------------------------------------------------------------*//**************************************************************************************************	MRULIST_ADD	Adds the specified node to the head of the MRU list.**************************************************************************************************/static voidmrulist_add(CACHE *ThisCache, CNODE *n){	register CNODE *head = ThisCache->mruHead;	if (!n || !ThisCache) return;	if (!ThisCache->mruHead)	{		ThisCache->mruHead = n;		ThisCache->mruHead->mruPrev = NULL;		ThisCache->mruHead->mruNext = NULL;		ThisCache->mruTail = n;	}	else	{		n->mruNext = head;		n->mruPrev = head->mruPrev;		if (head->mruPrev == NULL)			ThisCache->mruHead = n;		else			head->mruPrev->mruNext = n;		head->mruPrev = n;	}}/*--- mrulist_add() -----------------------------------------------------------------------------*//**************************************************************************************************	MRULIST_DEL**************************************************************************************************/static voidmrulist_del(CACHE *ThisCache, CNODE *n){	if (!n || !ThisCache || !ThisCache->mruHead) return;	if (n == ThisCache->mruHead)	{		ThisCache->mruHead = n->mruNext;		if (ThisCache->mruHead == NULL)			ThisCache->mruTail = NULL;		else			n->mruNext->mruPrev = NULL;	}	else	{		n->mruPrev->mruNext = n->mruNext;		if (n->mruNext == NULL)			ThisCache->mruTail = n->mruPrev;		else			n->mruNext->mruPrev = n->mruPrev;	}}/*--- mrulist_del() -----------------------------------------------------------------------------*//**************************************************************************************************	CACHE_FREE_NODE	Frees the node specified and removes it from the cache.**************************************************************************************************/static voidcache_free_node(CACHE *ThisCache, uint32_t hash, CNODE *n){	register CNODE *prev = NULL, *cur, *next;	if (!n || hash >= ThisCache->slots)		return;	for (cur = ThisCache->nodes[hash]; cur; cur = next)	{		next = cur->next_node;		if (cur == n)		/* Delete this node */		{			mrulist_del(ThisCache, n);							/* Remove from MRU/LRU list */			/* Remove the node */			if (cur->datalen)			{				Free(cur->data);			}			else if (cur->type == DNS_QTYPE_SOA)			{				mydns_soa_free(cur->data);			}			else			{				mydns_rr_free(cur->data);			}			if (cur == ThisCache->nodes[hash])				/* Head of node? */				ThisCache->nodes[hash] = cur->next_node;			else if (prev)				prev->next_node = cur->next_node;			Free(cur);			ThisCache->out++;			ThisCache->count--;			return;		}		else			prev = cur;	}	Errx(_("tried to free invalid node %p at %u in cache"), n, hash);}/*--- cache_free_node() -------------------------------------------------------------------------*//**************************************************************************************************	CACHE_EMPTY	Deletes all nodes within the cache.**************************************************************************************************/voidcache_empty(CACHE *ThisCache){	register int ct;	register CNODE *n, *tmp;	if (!ThisCache) return;	for (ct = 0; ct < ThisCache->slots; ct++)		for (n = ThisCache->nodes[ct]; n; n = tmp)		{			tmp = n->next_node;			cache_free_node(ThisCache, ct, n);		}	ThisCache->mruHead = ThisCache->mruTail = NULL;}/*--- cache_empty() -----------------------------------------------------------------------------*//**************************************************************************************************	CACHE_CLEANUP	Deletes all expired nodes within the cache.**************************************************************************************************/voidcache_cleanup(CACHE *ThisCache){	register int	ct;	register CNODE	*n, *tmp;	if (!ThisCache)		return;	for (ct = 0; ct < ThisCache->slots; ct++)		for (n = ThisCache->nodes[ct]; n; n = tmp)		{			tmp = n->next_node;			if (n->expire && (current_time > n->expire))			{				ThisCache->expired++;				cache_free_node(ThisCache, ct, n);			}		}}/*--- cache_cleanup() ---------------------------------------------------------------------------*//**************************************************************************************************	CACHE_PURGE_ZONE	Deletes all nodes within the cache for the specified zone.**************************************************************************************************/voidcache_purge_zone(CACHE *ThisCache, uint32_t zone){	register int	ct;	register CNODE	*n, *tmp;	if (!ThisCache)		return;	for (ct = 0; ct < ThisCache->slots; ct++)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -