reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region)
{
	size_t i;
	struct ub_packed_rrset_key** sorted_p, **sorted_q;
	if(p->flags != q->flags ||
		p->qdcount != q->qdcount ||
		/* do not check TTL, this may differ */
		/*
		p->ttl != q->ttl ||
		p->prefetch_ttl != q->prefetch_ttl ||
		*/
		p->security != q->security ||
		p->an_numrrsets != q->an_numrrsets ||
		p->ns_numrrsets != q->ns_numrrsets ||
		p->ar_numrrsets != q->ar_numrrsets ||
		p->rrset_count != q->rrset_count)
		return 0;
	/* sort the rrsets in the authority and additional sections before
	 * compare, the query and answer sections are ordered in the sequence
	 * they should have (eg. one after the other for aliases). */
	sorted_p = (struct ub_packed_rrset_key**)regional_alloc_init(
		region, p->rrsets, sizeof(*sorted_p)*p->rrset_count);
	if(!sorted_p) return 0;
	log_assert(p->an_numrrsets + p->ns_numrrsets + p->ar_numrrsets <=
		p->rrset_count);
	qsort(sorted_p + p->an_numrrsets, p->ns_numrrsets,
		sizeof(*sorted_p), rrset_canonical_sort_cmp);
	qsort(sorted_p + p->an_numrrsets + p->ns_numrrsets, p->ar_numrrsets,
		sizeof(*sorted_p), rrset_canonical_sort_cmp);

	sorted_q = (struct ub_packed_rrset_key**)regional_alloc_init(
		region, q->rrsets, sizeof(*sorted_q)*q->rrset_count);
	if(!sorted_q) {
		regional_free_all(region);
		return 0;
	}
	log_assert(q->an_numrrsets + q->ns_numrrsets + q->ar_numrrsets <=
		q->rrset_count);
	qsort(sorted_q + q->an_numrrsets, q->ns_numrrsets,
		sizeof(*sorted_q), rrset_canonical_sort_cmp);
	qsort(sorted_q + q->an_numrrsets + q->ns_numrrsets, q->ar_numrrsets,
		sizeof(*sorted_q), rrset_canonical_sort_cmp);

	/* compare the rrsets */
	for(i=0; i<p->rrset_count; i++) {
		if(!rrset_equal(sorted_p[i], sorted_q[i])) {
			if(!rrset_canonical_equal(region, sorted_p[i],
				sorted_q[i])) {
				regional_free_all(region);
				return 0;
			}
		}
	}
	regional_free_all(region);
	return 1;
}
reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region)
{
	size_t i;
	struct ub_packed_rrset_key** sorted_p, **sorted_q;
	if(p->flags != q->flags ||
		p->qdcount != q->qdcount ||
		 
		 
		p->security != q->security ||
		p->an_numrrsets != q->an_numrrsets ||
		p->ns_numrrsets != q->ns_numrrsets ||
		p->ar_numrrsets != q->ar_numrrsets ||
		p->rrset_count != q->rrset_count)
		return 0;
	 
	sorted_p = (struct ub_packed_rrset_key**)regional_alloc_init(
		region, p->rrsets, sizeof(*sorted_p)*p->rrset_count);
	if(!sorted_p) return 0;
	log_assert(p->an_numrrsets + p->ns_numrrsets + p->ar_numrrsets <=
		p->rrset_count);
	qsort(sorted_p + p->an_numrrsets, p->ns_numrrsets,
		sizeof(*sorted_p), rrset_canonical_sort_cmp);
	qsort(sorted_p + p->an_numrrsets + p->ns_numrrsets, p->ar_numrrsets,
		sizeof(*sorted_p), rrset_canonical_sort_cmp);

	sorted_q = (struct ub_packed_rrset_key**)regional_alloc_init(
		region, q->rrsets, sizeof(*sorted_q)*q->rrset_count);
	if(!sorted_q) {
		regional_free_all(region);
		return 0;
	}
	log_assert(q->an_numrrsets + q->ns_numrrsets + q->ar_numrrsets <=
		q->rrset_count);
	qsort(sorted_q + q->an_numrrsets, q->ns_numrrsets,
		sizeof(*sorted_q), rrset_canonical_sort_cmp);
	qsort(sorted_q + q->an_numrrsets + q->ns_numrrsets, q->ar_numrrsets,
		sizeof(*sorted_q), rrset_canonical_sort_cmp);

	 
	for(i=0; i<p->rrset_count; i++) {
		if(!rrset_equal(sorted_p[i], sorted_q[i])) {
			if(!rrset_canonical_equal(region, sorted_p[i],
				sorted_q[i])) {
				regional_free_all(region);
				return 0;
			}
		}
	}
	regional_free_all(region);
	return 1;
}