📄 cache.c~
字号:
/************************************************************************************************** CACHE_HASH Returns hash value.**************************************************************************************************/static inline uint32_tcache_hash(CACHE *ThisCache, uint32_t initval, void *buf, register size_t buflen)#if (HASH_TYPE == ORIGINAL_HASH){ register uint32_t hash; register unsigned char *p; /* Generate hash value */ for (hash = initval, p = (unsigned char *)buf; p < (unsigned char *)(buf + buflen); p++) { register int tmp; hash = (hash << 4) + (*p); if ((tmp = (hash & 0xf0000000))) { hash = hash ^ (tmp >> 24); hash = hash ^ tmp; } } return (hash % ThisCache->slots);}#elif (HASH_TYPE == ADDITIVE_HASH){ register uint32_t hash; register unsigned char *p; for (hash = initval, p = (unsigned char *)buf; p < (unsigned char *)(buf + buflen); p++) hash += *p; return (hash % ThisCache->slots);}#elif (HASH_TYPE == ROTATING_HASH){ register uint32_t hash; register unsigned char *p; for (hash = initval, p = (unsigned char *)buf; p < (unsigned char *)(buf + buflen); p++) hash = (hash << 4) ^ (hash >> 28) ^ (*p); return ((hash ^ (hash>>10) ^ (hash>>20)) & ThisCache->mask);}#elif (HASH_TYPE == FNV_HASH){ register uint32_t hash = FNV_32_INIT; unsigned char *bp = (unsigned char *)buf; unsigned char *be = bp + buflen; while (bp < be) { hash *= FNV_32_PRIME; hash ^= (uint32_t)*bp++; } hash *= FNV_32_PRIME; hash ^= (uint32_t)initval; if (ThisCache->bits == 16) return ((hash >> 16) ^ (hash & (((uint32_t)1 << 16) - 1))); else return (hash % ThisCache->slots);}#else# error Hash method unknown or unspecified#endif/*--- cache_hash() ------------------------------------------------------------------------------*//************************************************************************************************** ZONE_CACHE_FIND Returns the SOA/RR from cache (or via the database) or NULL if `name' doesn't match.**************************************************************************************************/void *zone_cache_find(TASK *t, uint32_t zone, char *origin, dns_qtype_t type, char *name, size_t namelen, int *errflag, MYDNS_SOA *parent){ register uint32_t hash = 0; register CNODE *n; MYDNS_SOA *soa = NULL; MYDNS_RR *rr = NULL; CACHE *C; /* Which cache to use when inserting */#if DEBUG_ENABLED && DEBUG_CACHE Debug("%s: zone_cache_find(zone=%u, origin='%s', name='%s', qtype=%s)", desctask(t), zone, origin, name, mydns_qtype_str(type));#endif *errflag = 0; if (!name) return (NULL); /*add by zyl 20080331 --begin*/ char ipchs[9]; memset(ipchs,0,9); iplong_to_ipchs(ipchs, 9, t->addr4.sin_addr.s_addr); /*add by zyl 20080331 --end*/ if (ZoneCache) { hash = cache_hash(ZoneCache, zone + type, name, namelen);#if USE_NEGATIVE_CACHE /* Check negative reply cache */ if (NegativeCache) { NegativeCache->questions++; /* Look at the appropriate node. Descend list and find match. */ for (n = NegativeCache->nodes[hash]; n; n = n->next_node) if ((n->namelen == namelen) && (n->zone == zone) && (n->type == type)) { if (!n->name) Errx(_("negative cache node %p at hash %u has NULL name"), n, hash); if (!memcmp(n->name, name, namelen)) { /* Is the node expired? */ if (n->expire && (current_time > n->expire)) { cache_free_node(NegativeCache, hash, n); break; } NegativeCache->hits++; /* Found in cache; move to head of usefulness list */ mrulist_del(NegativeCache, n); mrulist_add(NegativeCache, n); return NULL; } } NegativeCache->misses++; }#endif /* Not in negative cache, so look in zone cache */ ZoneCache->questions++; /* Look at the appropriate node. Descend list and find match. */ for (n = ZoneCache->nodes[hash]; n; n = n->next_node) { if ((n->namelen == namelen) && (n->zone == zone) && (n->type == type)) { if (!n->name) Errx(_("zone cache node %p at hash %u has NULL name"), n, hash); if (!memcmp(n->name, name, namelen)) { /* Is the node expired? */ if (n->expire && (current_time > n->expire)) { cache_free_node(ZoneCache, hash, n); break; } ZoneCache->hits++; /* Found in cache; move to head of usefulness list */ mrulist_del(ZoneCache, n); mrulist_add(ZoneCache, n); if (type == DNS_QTYPE_SOA) return (n->data ? mydns_soa_dup(n->data, 1) : NULL); else return (n->data ? mydns_rr_dup(n->data, 1) : NULL); } } } } /* Result not found in cache; Get answer from database */ if (type == DNS_QTYPE_SOA) { /* Try to load from database */#if DEBUG_ENABLED && DEBUG_SQL_QUERIES Debug("%s: SQL query: table \"%s\", origin=\"%s\"", desctask(t), mydns_soa_table_name, name);#endif if (mydns_soa_load(sql, &soa, name) != 0) { sql_reopen(); if (mydns_soa_load(sql, &soa, name) != 0) { WarnSQL(sql, "%s: %s", name, _("error loading SOA")); *errflag = 1; return (NULL); } } /*add by zyl 20080403 __begin*/ /*select the most matched soa*/ //select_matched_zone(sql,&soa,name,type,origin,ipchs); /*add by zyl 20080403 __end*/#ifdef DN_COLUMN_NAMES if (soa && dn_default_ns) strncpy(soa->ns, dn_default_ns, sizeof(soa->ns)-1);#endif#if USE_NEGATIVE_CACHE if (!(C = soa ? ZoneCache : NegativeCache))#else if (!(soa && (C = ZoneCache)))#endif return ((void *)soa); /* Don't cache if TTL is 0 */ if (soa && !soa->ttl) return ((void *)soa); } else {#if DEBUG_ENABLED && DEBUG_SQL_QUERIES Debug("%s: SQL query: table \"%s\", zone=%u,type=\"%s\",name=\"%s\", requestor_ip_section=\"%s\"", desctask(t), mydns_rr_table_name, zone, mydns_qtype_str(type), name,ipchs);#endif if (mydns_rr_load(sql, &rr, zone, type, name, origin, ipchs) != 0) { sql_reopen(); if (mydns_rr_load(sql, &rr, zone, type, name, origin, ipchs) != 0) { WarnSQL(sql, _("error finding %s type resource records for name `%s' in zone %u"), mydns_qtype_str(type), name, zone); sql_reopen(); *errflag = 1; return (NULL); } }#ifdef DN_COLUMN_NAMES /* DN database has no TTL - use parent's */ if (rr && parent && parent->ttl) rr->ttl = parent->ttl;#endif#if USE_NEGATIVE_CACHE if (!(C = rr ? ZoneCache : NegativeCache))#else if (!(rr && (C = ZoneCache)))#endif return ((void *)rr); /* Don't cache if TTL of this RR (or the parent SOA) is 0 */ if ((rr && !rr->ttl) || (parent && !parent->ttl)) return ((void *)rr); } C->misses++; /* If the cache is full, delete the least recently used node and add new node */ if (C->count >= C->limit) { if (C->mruTail) { C->removed++; C->removed_secs += current_time - C->mruTail->insert_time; cache_free_node(C, C->mruTail->hash, C->mruTail); } else return (type == DNS_QTYPE_SOA ? (void *)soa : (void *)rr); } /* Add to cache */ C->in++; if (!(n = calloc(1, sizeof(CNODE)))) Err(_("out of memory")); n->hash = hash; n->zone = zone; n->type = type; strncpy(n->name, name, sizeof(n->name)-1); n->namelen = namelen; n->insert_time = current_time; if (type == DNS_QTYPE_SOA) { if (C == ZoneCache) n->data = mydns_soa_dup(soa, 1); if (soa && (soa->ttl < C->expire)) n->expire = current_time + soa->ttl; else if (C->expire) n->expire = current_time + C->expire; } else { if (C == ZoneCache) n->data = mydns_rr_dup(rr, 1); if (rr && (rr->ttl < C->expire)) n->expire = current_time + rr->ttl; else if (C->expire) n->expire = current_time + C->expire; } n->next_node = C->nodes[hash];#if DEBUG_ENABLED && DEBUG_CACHE Debug("%s: Added to cache: zone=%u, type=%s, name='%s'", desctask(t), zone, mydns_qtype_str(type), name);#endif /* Add node to cache */ C->nodes[hash] = n; C->count++; /* Add node to head of MRU list */ mrulist_add(C, n); return (type == DNS_QTYPE_SOA ? (void *)soa : (void *)rr);}/*--- zone_cache_find() --------------------------------------------------------------------------*//************************************************************************************************** REPLY_CACHE_FIND Attempt to find the reply data whole in the cache. Returns nonzero if found, 0 if not found. If found, fills in t->reply and t->replylen.**************************************************************************************************/intreply_cache_find(TASK *t){ register uint32_t hash; register CNODE *n; register void *p;#if DEBUG_ENABLED && DEBUG_CACHE Debug("%s: reply_cache_find(qdlen=%d proto=%d)", desctask(t), t->qdlen, t->protocol);#endif if (!ReplyCache || t->qdlen > DNS_MAXPACKETLEN_UDP) return (0);#if STATUS_ENABLED /* Status requests aren't cached */ if (t->qclass == DNS_CLASS_CHAOS) return (0);#endif hash = cache_hash(ReplyCache, t->qtype, t->qd, t->qdlen); ReplyCache->questions++; /* Look at the appropriate node. Descend list and find match. */ for (n = ReplyCache->nodes[hash]; n; n = n->next_node) { if ((n->namelen == t->qdlen) && (n->type == t->qtype) && (n->protocol == t->protocol)) { if (!n->name) Errx(_("reply cache node %p at hash %u has NULL name"), n, hash); if (!memcmp(n->name, t->qd, t->qdlen)) { /* Is the node expired? */ if (n->expire && (current_time > n->expire)) { cache_free_node(ReplyCache, hash, n); break; } /* Found in cache; move to head of usefulness list */ mrulist_del(ReplyCache, n); mrulist_add(ReplyCache, n); /* Allocate space for reply data */ t->replylen = n->datalen - sizeof(DNS_HEADER) - sizeof(task_error_t); if (!(t->reply = malloc(t->replylen))) Err(_("out of memory")); p = n->data; /* Copy DNS header */ memcpy(&t->hdr, p, sizeof(DNS_HEADER)); p += sizeof(DNS_HEADER); /* Copy reason */ memcpy(&t->reason, p, sizeof(task_error_t)); p += sizeof(task_error_t); /* Copy reply data */ memcpy(t->reply, p, t->replylen); /* Set count of records in each section */ p = t->reply + SIZE16 + SIZE16 + SIZE16; DNS_GET16(t->an.size, p); DNS_GET16(t->ns.size, p); DNS_GET16(t->ar.size, p); t->zone = n->zone; t->reply_from_cache = 1; ReplyCache->hits++;#if DEBUG_ENABLED && DEBUG_CACHE Debug(_("%s: %d octet reply found in cache"), desctask(t), t->replylen);#endif return (1); } } } ReplyCache->misses++; return (0);}/*--- reply_cache_find() ------------------------------------------------------------------------*//************************************************************************************************** ADD_REPLY_TO_CACHE Adds the current reply to the reply cache.**************************************************************************************************/voidadd_reply_to_cache(TASK *t){ register uint32_t hash; register CNODE *n; register void *p;#if DEBUG_ENABLED && DEBUG_CACHE Debug("%s: add_reply_to_cache(qdlen=%d rcode=%s rd=%d proto=%d)", desctask(t), t->qdlen, mydns_rcode_str(t->hdr.rcode), t->hdr.rd, t->protocol);#endif if (!ReplyCache || t->qdlen > DNS_MAXPACKETLEN_UDP || t->hdr.rcode == DNS_RCODE_SERVFAIL) {#if DEBUG_ENABLED && DEBUG_CACHE Debug("reply should not be cached");#endif return; } /* Don't cache replies from recursive forwarder */ if (t->forwarded) return;#if STATUS_ENABLED /* Don't cache status requests */ if (t->qclass == DNS_CLASS_CHAOS) return;#endif /* Don't cache negative replies if recursive forwarding is enabled */ if (forward_recursive && t->hdr.rcode != DNS_RCODE_NOERROR) return; hash = cache_hash(ReplyCache, t->qtype, t->qd, t->qdlen); /* Look at the appropriate node. Descend list and find match. */ for (n = ReplyCache->nodes[hash]; n; n = n->next_node) { if ((n->namelen == t->qdlen) && (n->type == t->qtype) && (n->protocol == t->protocol)) { if (!n->name) Errx(_("reply cache node %p at hash %u has NULL name"), n, hash); if (!memcmp(n->name, t->qd, t->qdlen)) { /* Is the node expired? */ if (n->expire && (current_time > n->expire)) { cache_free_node(ReplyCache, hash, n); break; } /* Found in cache; move to head of usefulness list */ mrulist_del(ReplyCache, n); mrulist_add(ReplyCache, n); return; } } } /* If the cache is full, delete the least recently used node and add new node */ if (ReplyCache->count >= ReplyCache->limit) { if (ReplyCache->mruTail) { ReplyCache->removed++; ReplyCache->removed_secs += current_time - ReplyCache->mruTail->insert_time; cache_free_node(ReplyCache, ReplyCache->mruTail->hash, ReplyCache->mruTail); } else return; } /* Add to cache */ ReplyCache->in++; if (!(n = calloc(1, sizeof(CNODE)))) Err(_("out of memory")); n->hash = hash; n->zone = t->zone; n->type = t->qtype; n->protocol = t->protocol; memcpy(n->name, t->qd, t->qdlen); n->namelen = t->qdlen; /* The data is the DNS_HEADER, the reason, then the reply */ n->datalen = sizeof(DNS_HEADER) + sizeof(task_error_t) + t->replylen; if (!(n->data = malloc(n->datalen))) Err(_("out of memory")); p = n->data; /* Save DNS header */ memcpy(p, &t->hdr, sizeof(DNS_HEADER)); p += sizeof(DNS_HEADER); /* Save reason for error, if any */ memcpy(p, &t->reason, sizeof(task_error_t)); p += sizeof(task_error_t); /* Save reply data */ memcpy(p, t->reply, t->replylen); n->insert_time = current_time; if (ReplyCache->expire) n->expire = current_time + ReplyCache->expire; n->next_node = ReplyCache->nodes[hash]; /* Add node to cache */ ReplyCache->nodes[hash] = n; ReplyCache->count++; /* Add node to head of MRU list */ mrulist_add(ReplyCache, n);#if DEBUG_ENABLED && DEBUG_CACHE Debug("%s: %s (qtype=%s qdlen=%d rd=%d proto=%d)", desctask(t), _("reply cached"), mydns_qtype_str(t->qtype), t->qdlen, t->hdr.rd, t->protocol);#endif}/*--- add_reply_to_cache() ----------------------------------------------------------------------*//* vi:set ts=3: *//* NEED_PO */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -