cdaabce
commit d7ef7b31e0dbb0a73b201649c3729508b270f43f
cdaabce
Author: wouter <wouter@be551aaa-1e26-0410-a405-d3ace91eadb9>
cdaabce
Date:   Mon Apr 26 14:59:44 2010 +0000
cdaabce
cdaabce
    Fix bug#307: 0x20 fallback outstanding query count, together with rec_lame,
cdaabce
    and canonical rrset comparison.
cdaabce
cdaabce
diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c
cdaabce
index 9082055..6124650 100644
cdaabce
--- a/iterator/iter_utils.c
cdaabce
+++ b/iterator/iter_utils.c
cdaabce
@@ -674,7 +674,7 @@ rrset_equal(struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2)
cdaabce
 }
cdaabce
 
cdaabce
 int 
cdaabce
-reply_equal(struct reply_info* p, struct reply_info* q)
cdaabce
+reply_equal(struct reply_info* p, struct reply_info* q, ldns_buffer* scratch)
cdaabce
 {
cdaabce
 	size_t i;
cdaabce
 	if(p->flags != q->flags ||
cdaabce
@@ -688,8 +688,29 @@ reply_equal(struct reply_info* p, struct reply_info* q)
cdaabce
 		p->rrset_count != q->rrset_count)
cdaabce
 		return 0;
cdaabce
 	for(i=0; i<p->rrset_count; i++) {
cdaabce
-		if(!rrset_equal(p->rrsets[i], q->rrsets[i]))
cdaabce
-			return 0;
cdaabce
+		if(!rrset_equal(p->rrsets[i], q->rrsets[i])) {
cdaabce
+			/* fallback procedure: try to sort and canonicalize */
cdaabce
+			ldns_rr_list* pl, *ql;
cdaabce
+			pl = packed_rrset_to_rr_list(p->rrsets[i], scratch);
cdaabce
+			ql = packed_rrset_to_rr_list(q->rrsets[i], scratch);
cdaabce
+			if(!pl || !ql) {
cdaabce
+				ldns_rr_list_deep_free(pl);
cdaabce
+				ldns_rr_list_deep_free(ql);
cdaabce
+				return 0;
cdaabce
+			}
cdaabce
+			ldns_rr_list2canonical(pl);
cdaabce
+			ldns_rr_list2canonical(ql);
cdaabce
+			ldns_rr_list_sort(pl);
cdaabce
+			ldns_rr_list_sort(ql);
cdaabce
+			if(ldns_rr_list_compare(pl, ql) != 0) {
cdaabce
+				ldns_rr_list_deep_free(pl);
cdaabce
+				ldns_rr_list_deep_free(ql);
cdaabce
+				return 0;
cdaabce
+			}
cdaabce
+			ldns_rr_list_deep_free(pl);
cdaabce
+			ldns_rr_list_deep_free(ql);
cdaabce
+			continue;
cdaabce
+		}
cdaabce
 	}
cdaabce
 	return 1;
cdaabce
 }
cdaabce
@@ -792,3 +813,18 @@ iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns, uint8_t* z)
cdaabce
 		i++;
cdaabce
 	}
cdaabce
 }
cdaabce
+
cdaabce
+void iter_dec_attempts(struct delegpt* dp, int d)
cdaabce
+{
cdaabce
+	struct delegpt_addr* a;
cdaabce
+	for(a=dp->target_list; a; a = a->next_target) {
cdaabce
+		if(a->attempts >= OUTBOUND_MSG_RETRY) {
cdaabce
+			/* add back to result list */
cdaabce
+			a->next_result = dp->result_list;
cdaabce
+			dp->result_list = a;
cdaabce
+		}
cdaabce
+		if(a->attempts > d)
cdaabce
+			a->attempts -= d;
cdaabce
+		else a->attempts = 0;
cdaabce
+	}
cdaabce
+}
cdaabce
diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h
cdaabce
index 9a1db5f..a9f4247 100644
cdaabce
--- a/iterator/iter_utils.h
cdaabce
+++ b/iterator/iter_utils.h
cdaabce
@@ -211,9 +211,10 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
cdaabce
  * @param p: reply one. The reply has rrset data pointers in region.
cdaabce
  * 	Does not check rrset-IDs
cdaabce
  * @param q: reply two
cdaabce
+ * @param buf: scratch buffer.
cdaabce
  * @return if one and two are equal.
cdaabce
  */
cdaabce
-int reply_equal(struct reply_info* p, struct reply_info* q);
cdaabce
+int reply_equal(struct reply_info* p, struct reply_info* q, ldns_buffer* buf);
cdaabce
 
cdaabce
 /**
cdaabce
  * Store in-zone glue in seperate rrset cache entries for later last-resort
cdaabce
@@ -257,4 +258,11 @@ int iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
cdaabce
 void iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns,
cdaabce
 	uint8_t* z);
cdaabce
 
cdaabce
+/**
cdaabce
+ * Remove query attempts from all available ips. For 0x20.
cdaabce
+ * @param dp: delegpt.
cdaabce
+ * @param d: decrease.
cdaabce
+ */
cdaabce
+void iter_dec_attempts(struct delegpt* dp, int d);
cdaabce
+
cdaabce
 #endif /* ITERATOR_ITER_UTILS_H */
cdaabce
diff --git a/iterator/iterator.c b/iterator/iterator.c
cdaabce
index c7cdbc8..b1a948d 100644
cdaabce
--- a/iterator/iterator.c
cdaabce
+++ b/iterator/iterator.c
cdaabce
@@ -1416,6 +1416,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
cdaabce
 				"match for %d wanted, done.", 
cdaabce
 				(int)iq->caps_server+1, (int)naddr*3);
cdaabce
 			iq->caps_fallback = 0;
cdaabce
+			iter_dec_attempts(iq->dp, 3); /* space for fallback */
cdaabce
+			iq->num_current_queries++; /* RespState decrements it*/
cdaabce
+			iq->referral_count++; /* make sure we don't loop */
cdaabce
 			iq->state = QUERY_RESP_STATE;
cdaabce
 			return 1;
cdaabce
 		}
cdaabce
@@ -2384,7 +2387,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
cdaabce
 			goto handle_it;
cdaabce
 		} else {
cdaabce
 			/* check if reply is the same, otherwise, fail */
cdaabce
-			if(!reply_equal(iq->response->rep, iq->caps_reply)) {
cdaabce
+			if(!reply_equal(iq->response->rep, iq->caps_reply,
cdaabce
+				qstate->env->scratch_buffer)) {
cdaabce
 				verbose(VERB_DETAIL, "Capsforid fallback: "
cdaabce
 					"getting different replies, failed");
cdaabce
 				outbound_list_remove(&iq->outlist, outbound);