/** create rate data item for name, number 1 in now */ static void infra_create_ratedata(struct infra_cache* infra, uint8_t* name, size_t namelen, time_t timenow) { hashvalue_t h = dname_query_hash(name, 0xab); struct rate_key* k = (struct rate_key*)calloc(1, sizeof(*k)); struct rate_data* d = (struct rate_data*)calloc(1, sizeof(*d)); if(!k || !d) { free(k); free(d); return; /* alloc failure */ } k->namelen = namelen; k->name = memdup(name, namelen); if(!k->name) { free(k); free(d); return; /* alloc failure */ } lock_rw_init(&k->entry.lock); k->entry.hash = h; k->entry.key = k; k->entry.data = d; d->qps[0] = 1; d->timestamp[0] = timenow; slabhash_insert(infra->domain_rates, h, &k->entry, d, NULL); }
void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, hashvalue_t hash, struct reply_info* rep, time_t leeway, int pside, struct reply_info* qrep, struct regional* region) { struct msgreply_entry* e; time_t ttl = rep->ttl; size_t i; /* store RRsets */ for(i=0; i<rep->rrset_count; i++) { rep->ref[i].key = rep->rrsets[i]; rep->ref[i].id = rep->rrsets[i]->id; } /* there was a reply_info_sortref(rep) here but it seems to be * unnecessary, because the cache gets locked per rrset. */ reply_info_set_ttls(rep, *env->now); store_rrsets(env, rep, *env->now, leeway, pside, qrep, region); if(ttl == 0) { /* we do not store the message, but we did store the RRs, * which could be useful for delegation information */ verbose(VERB_ALGO, "TTL 0: dropped msg from cache"); free(rep); return; } /* store msg in the cache */ reply_info_sortref(rep); if(!(e = query_info_entrysetup(qinfo, rep, hash))) { log_err("store_msg: malloc failed"); return; } slabhash_insert(env->msg_cache, hash, &e->entry, rep, env->alloc); }
int infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, size_t nmlen, int edns_version, time_t timenow) { struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); struct infra_data* data; int needtoinsert = 0; if(!e) { if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) return 0; needtoinsert = 1; } else if(((struct infra_data*)e->data)->ttl < timenow) { data_entry_init(infra, e, timenow); } /* have an entry, update the rtt, and the ttl */ data = (struct infra_data*)e->data; /* do not update if noEDNS and stored is yesEDNS */ if(!(edns_version == -1 && (data->edns_version != -1 && data->edns_lame_known))) { data->edns_version = edns_version; data->edns_lame_known = 1; } if(needtoinsert) slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); else { lock_rw_unlock(&e->lock); } return 1; }
/** test adding a random element */ static void testadd(struct slabhash* table, testdata_type* ref[]) { int numtoadd = random() % HASHTESTMAX; testdata_type* data = newdata(numtoadd); testkey_type* key = newkey(numtoadd); key->entry.data = data; slabhash_insert(table, myhash(numtoadd), &key->entry, data, NULL); ref[numtoadd] = data; }
/** test adding a random element (unlimited range) */ static void testadd_unlim(struct slabhash* table, testdata_t** ref) { int numtoadd = random() % (HASHTESTMAX * 10); testdata_t* data = newdata(numtoadd); testkey_t* key = newkey(numtoadd); key->entry.data = data; slabhash_insert(table, myhash(numtoadd), &key->entry, data, NULL); if(ref) ref[numtoadd] = data; }
int infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, size_t nmlen, int qtype, int roundtrip, int orig_rtt, time_t timenow) { struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); struct infra_data* data; int needtoinsert = 0; int rto = 1; if(!e) { if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) return 0; needtoinsert = 1; } else if(((struct infra_data*)e->data)->ttl < timenow) { data_entry_init(infra, e, timenow); } /* have an entry, update the rtt */ data = (struct infra_data*)e->data; if(roundtrip == -1) { rtt_lost(&data->rtt, orig_rtt); if(qtype == LDNS_RR_TYPE_A) { if(data->timeout_A < TIMEOUT_COUNT_MAX) data->timeout_A++; } else if(qtype == LDNS_RR_TYPE_AAAA) { if(data->timeout_AAAA < TIMEOUT_COUNT_MAX) data->timeout_AAAA++; } else { if(data->timeout_other < TIMEOUT_COUNT_MAX) data->timeout_other++; } } else { /* if we got a reply, but the old timeout was above server * selection height, delete the timeout so the server is * fully available again */ if(rtt_unclamped(&data->rtt) >= USEFUL_SERVER_TOP_TIMEOUT) rtt_init(&data->rtt); rtt_update(&data->rtt, roundtrip); data->probedelay = 0; if(qtype == LDNS_RR_TYPE_A) data->timeout_A = 0; else if(qtype == LDNS_RR_TYPE_AAAA) data->timeout_AAAA = 0; else data->timeout_other = 0; } if(data->rtt.rto > 0) rto = data->rtt.rto; if(needtoinsert) slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); else { lock_rw_unlock(&e->lock); } return rto; }
/** test hashtable using short sequence */ static void test_short_table(struct slabhash* table) { testkey_type* k = newkey(12); testkey_type* k2 = newkey(14); testdata_type* d = newdata(128); testdata_type* d2 = newdata(129); k->entry.data = d; k2->entry.data = d2; slabhash_insert(table, myhash(12), &k->entry, d, NULL); slabhash_insert(table, myhash(14), &k2->entry, d2, NULL); unit_assert( slabhash_lookup(table, myhash(12), k, 0) == &k->entry); lock_rw_unlock( &k->entry.lock ); unit_assert( slabhash_lookup(table, myhash(14), k2, 0) == &k2->entry); lock_rw_unlock( &k2->entry.lock ); slabhash_remove(table, myhash(12), k); slabhash_remove(table, myhash(14), k2); }
void key_cache_insert(struct key_cache* kcache, struct key_entry_key* kkey, struct module_qstate* qstate) { struct key_entry_key* k = key_entry_copy(kkey); if(!k) return; if(key_entry_isbad(k) && qstate->errinf && qstate->env->cfg->val_log_level >= 2) { /* on malloc failure there is simply no reason string */ key_entry_set_reason(k, errinf_to_str(qstate)); } key_entry_hash(k); slabhash_insert(kcache->slab, k->entry.hash, &k->entry, k->entry.data, NULL); }
void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, hashvalue_type hash, struct reply_info* rep, time_t leeway, int pside, struct reply_info* qrep, uint32_t flags, struct regional* region) { struct msgreply_entry* e; time_t ttl = rep->ttl; size_t i; /* store RRsets */ for(i=0; i<rep->rrset_count; i++) { rep->ref[i].key = rep->rrsets[i]; rep->ref[i].id = rep->rrsets[i]->id; } /* there was a reply_info_sortref(rep) here but it seems to be * unnecessary, because the cache gets locked per rrset. */ reply_info_set_ttls(rep, *env->now); store_rrsets(env, rep, *env->now, leeway, pside, qrep, region); if(ttl == 0 && !(flags & DNSCACHE_STORE_ZEROTTL)) { /* we do not store the message, but we did store the RRs, * which could be useful for delegation information */ verbose(VERB_ALGO, "TTL 0: dropped msg from cache"); free(rep); /* if the message is SERVFAIL in cache, remove that SERVFAIL, * so that the TTL 0 response can be returned for future * responses (i.e. don't get answered by the servfail from * cache, but instead go to recursion to get this TTL0 * response). */ msg_del_servfail(env, qinfo, flags); return; } /* store msg in the cache */ reply_info_sortref(rep); if(!(e = query_info_entrysetup(qinfo, rep, hash))) { log_err("store_msg: malloc failed"); return; } slabhash_insert(env->msg_cache, hash, &e->entry, rep, env->alloc); }
int infra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow, int dnsseclame, int reclame, uint16_t qtype) { struct infra_data* data; struct lruhash_entry* e; int needtoinsert = 0; e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); if(!e) { /* insert it */ if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) { log_err("set_lame: malloc failure"); return 0; } needtoinsert = 1; } else if( ((struct infra_data*)e->data)->ttl < timenow) { /* expired, reuse existing entry */ data_entry_init(infra, e, timenow); } /* got an entry, now set the zone lame */ data = (struct infra_data*)e->data; /* merge data (if any) */ if(dnsseclame) data->isdnsseclame = 1; if(reclame) data->rec_lame = 1; if(!dnsseclame && !reclame && qtype == LDNS_RR_TYPE_A) data->lame_type_A = 1; if(!dnsseclame && !reclame && qtype != LDNS_RR_TYPE_A) data->lame_other = 1; /* done */ if(needtoinsert) slabhash_insert(infra->hosts, e->hash, e, e->data, NULL); else { lock_rw_unlock(&e->lock); } return 1; }
int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow, int* edns_vs, uint8_t* edns_lame_known, int* to) { struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 0); struct infra_data* data; int wr = 0; if(e && ((struct infra_data*)e->data)->ttl < timenow) { /* it expired, try to reuse existing entry */ int old = ((struct infra_data*)e->data)->rtt.rto; uint8_t tA = ((struct infra_data*)e->data)->timeout_A; uint8_t tAAAA = ((struct infra_data*)e->data)->timeout_AAAA; uint8_t tother = ((struct infra_data*)e->data)->timeout_other; lock_rw_unlock(&e->lock); e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); if(e) { /* if its still there we have a writelock, init */ /* re-initialise */ /* do not touch lameness, it may be valid still */ data_entry_init(infra, e, timenow); wr = 1; /* TOP_TIMEOUT remains on reuse */ if(old >= USEFUL_SERVER_TOP_TIMEOUT) { ((struct infra_data*)e->data)->rtt.rto = USEFUL_SERVER_TOP_TIMEOUT; ((struct infra_data*)e->data)->timeout_A = tA; ((struct infra_data*)e->data)->timeout_AAAA = tAAAA; ((struct infra_data*)e->data)->timeout_other = tother; } } } if(!e) { /* insert new entry */ if(!(e = new_entry(infra, addr, addrlen, nm, nmlen, timenow))) return 0; data = (struct infra_data*)e->data; *edns_vs = data->edns_version; *edns_lame_known = data->edns_lame_known; *to = rtt_timeout(&data->rtt); slabhash_insert(infra->hosts, e->hash, e, data, NULL); return 1; } /* use existing entry */ data = (struct infra_data*)e->data; *edns_vs = data->edns_version; *edns_lame_known = data->edns_lame_known; *to = rtt_timeout(&data->rtt); if(*to >= PROBE_MAXRTO && rtt_notimeout(&data->rtt)*4 <= *to) { /* delay other queries, this is the probe query */ if(!wr) { lock_rw_unlock(&e->lock); e = infra_lookup_nottl(infra, addr,addrlen,nm,nmlen, 1); if(!e) { /* flushed from cache real fast, no use to allocate just for the probedelay */ return 1; } data = (struct infra_data*)e->data; } /* add 999 to round up the timeout value from msec to sec, * then add a whole second so it is certain that this probe * has timed out before the next is allowed */ data->probedelay = timenow + ((*to)+1999)/1000; } lock_rw_unlock(&e->lock); return 1; }