tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
	struct regional* region, time_t now, int allow_expired,
	struct regional* scratch)
{
	struct dns_msg* msg;
	size_t i;
	int is_expired = 0;
	time_t now_control = now;
	if(now > r->ttl) {
		/* Check if we are allowed to serve expired */
		if(allow_expired) {
			if(env->cfg->serve_expired_ttl &&
				r->serve_expired_ttl < now) {
				return NULL;
			}
		} else {
			return NULL;
		}
		/* Change the current time so we can pass the below TTL checks when
		 * serving expired data. */
		now_control = r->ttl - env->cfg->serve_expired_reply_ttl;
		is_expired = 1;
	}

	msg = gen_dns_msg(region, q, r->rrset_count);
	if(!msg) return NULL;
	msg->rep->flags = r->flags;
	msg->rep->qdcount = r->qdcount;
	msg->rep->ttl = is_expired
		?SERVE_EXPIRED_REPLY_TTL
		:r->ttl - now;
	if(r->prefetch_ttl > now)
		msg->rep->prefetch_ttl = r->prefetch_ttl - now;
	else
		msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
	msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
	msg->rep->security = r->security;
	msg->rep->an_numrrsets = r->an_numrrsets;
	msg->rep->ns_numrrsets = r->ns_numrrsets;
	msg->rep->ar_numrrsets = r->ar_numrrsets;
	msg->rep->rrset_count = r->rrset_count;
	msg->rep->authoritative = r->authoritative;
	msg->rep->reason_bogus = r->reason_bogus;
	if(!rrset_array_lock(r->ref, r->rrset_count, now_control)) {
		return NULL;
	}
	if(r->an_numrrsets > 0 && (r->rrsets[0]->rk.type == htons(
		LDNS_RR_TYPE_CNAME) || r->rrsets[0]->rk.type == htons(
		LDNS_RR_TYPE_DNAME)) && !reply_check_cname_chain(q, r)) {
		/* cname chain is now invalid, reconstruct msg */
		rrset_array_unlock(r->ref, r->rrset_count);
		return NULL;
	}
	if(r->security == sec_status_secure && !reply_all_rrsets_secure(r)) {
		/* message rrsets have changed status, revalidate */
		rrset_array_unlock(r->ref, r->rrset_count);
		return NULL;
	}
	for(i=0; i<msg->rep->rrset_count; i++) {
		msg->rep->rrsets[i] = packed_rrset_copy_region(r->rrsets[i],
			region, now);
		if(!msg->rep->rrsets[i]) {
			rrset_array_unlock(r->ref, r->rrset_count);
			return NULL;
		}
	}
	if(env)
		rrset_array_unlock_touch(env->rrset_cache, scratch, r->ref, 
		r->rrset_count);
	else
		rrset_array_unlock(r->ref, r->rrset_count);
	return msg;
}
tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
	struct regional* region, time_t now, int allow_expired,
	struct regional* scratch)
{
	struct dns_msg* msg;
	size_t i;
	int is_expired = 0;
	time_t now_control = now;
	if(now > r->ttl) {
		 
		if(allow_expired) {
			if(env->cfg->serve_expired_ttl &&
				r->serve_expired_ttl < now) {
				return NULL;
			}
		} else {
			return NULL;
		}
		 
		now_control = r->ttl - env->cfg->serve_expired_reply_ttl;
		is_expired = 1;
	}

	msg = gen_dns_msg(region, q, r->rrset_count);
	if(!msg) return NULL;
	msg->rep->flags = r->flags;
	msg->rep->qdcount = r->qdcount;
	msg->rep->ttl = is_expired
		?SERVE_EXPIRED_REPLY_TTL
		:r->ttl - now;
	if(r->prefetch_ttl > now)
		msg->rep->prefetch_ttl = r->prefetch_ttl - now;
	else
		msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
	msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
	msg->rep->security = r->security;
	msg->rep->an_numrrsets = r->an_numrrsets;
	msg->rep->ns_numrrsets = r->ns_numrrsets;
	msg->rep->ar_numrrsets = r->ar_numrrsets;
	msg->rep->rrset_count = r->rrset_count;
	msg->rep->authoritative = r->authoritative;
	msg->rep->reason_bogus = r->reason_bogus;
	if(!rrset_array_lock(r->ref, r->rrset_count, now_control)) {
		return NULL;
	}
	if(r->an_numrrsets > 0 && (r->rrsets[0]->rk.type == htons(
		LDNS_RR_TYPE_CNAME) || r->rrsets[0]->rk.type == htons(
		LDNS_RR_TYPE_DNAME)) && !reply_check_cname_chain(q, r)) {
		 
		rrset_array_unlock(r->ref, r->rrset_count);
		return NULL;
	}
	if(r->security == sec_status_secure && !reply_all_rrsets_secure(r)) {
		 
		rrset_array_unlock(r->ref, r->rrset_count);
		return NULL;
	}
	for(i=0; i<msg->rep->rrset_count; i++) {
		msg->rep->rrsets[i] = packed_rrset_copy_region(r->rrsets[i],
			region, now);
		if(!msg->rep->rrsets[i]) {
			rrset_array_unlock(r->ref, r->rrset_count);
			return NULL;
		}
	}
	if(env)
		rrset_array_unlock_touch(env->rrset_cache, scratch, r->ref, 
		r->rrset_count);
	else
		rrset_array_unlock(r->ref, r->rrset_count);
	return msg;
}