예제 #1
0
파일: infra.c 프로젝트: 2asoft/freebsd
/** 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);
}
예제 #2
0
파일: dns.c 프로젝트: coyizumi/cs111
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);
}
예제 #3
0
파일: infra.c 프로젝트: 2asoft/freebsd
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;
}
예제 #4
0
/** 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;
}
예제 #5
0
/** 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;
}
예제 #6
0
파일: infra.c 프로젝트: 2asoft/freebsd
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;
}
예제 #7
0
/** 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);
}
예제 #8
0
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);
}
예제 #9
0
파일: dns.c 프로젝트: derekmarcotte/freebsd
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);
}
예제 #10
0
파일: infra.c 프로젝트: 2asoft/freebsd
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;
}
예제 #11
0
파일: infra.c 프로젝트: 2asoft/freebsd
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;
}