diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c index afe76e16dd..b8a66af3b2 100644 --- a/lib/dns/rdataset.c +++ b/lib/dns/rdataset.c @@ -306,6 +306,14 @@ towire_compare(const void *av, const void *bv) { return (a->key - b->key); } +static inline void +swap_rdata(dns_rdata_t *in, unsigned int a, unsigned int b) { + dns_rdata_t rdata = DNS_RDATA_INIT; + rdata = in[a]; + in[a] = in[b]; + in[b] = rdata; +} + static isc_result_t towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, dns_compress_t *cctx, isc_buffer_t *target, @@ -313,10 +321,9 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, isc_boolean_t partial, unsigned int options, unsigned int *countp, void **state) { - dns_rdata_t rdata = DNS_RDATA_INIT; isc_region_t r; isc_result_t result; - unsigned int i, count = 0, added, choice; + unsigned int i, count = 0, added; isc_buffer_t savedbuffer, rdlen, rrbuffer; unsigned int headlen; isc_boolean_t question = ISC_FALSE; @@ -380,14 +387,17 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, } } - if ((shuffle || sort) && count > MAX_SHUFFLE) { - in = isc_mem_get(cctx->mctx, count * sizeof(*in)); - out = isc_mem_get(cctx->mctx, count * sizeof(*out)); - if (in == NULL || out == NULL) - shuffle = sort = ISC_FALSE; + if ((shuffle || sort)) { + if (count > MAX_SHUFFLE) { + in = isc_mem_get(cctx->mctx, count * sizeof(*in)); + out = isc_mem_get(cctx->mctx, count * sizeof(*out)); + if (in == NULL || out == NULL) { + shuffle = sort = ISC_FALSE; + } + } } - if (shuffle || sort) { + if ((shuffle || sort)) { /* * First we get handles to all of the rdata. */ @@ -399,68 +409,42 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, i++; result = dns_rdataset_next(rdataset); } while (result == ISC_R_SUCCESS); - if (result != ISC_R_NOMORE) + if (result != ISC_R_NOMORE) { goto cleanup; + } INSIST(i == count); - } - if (shuffle) { - if (want_random) { - /* - * 'Random' order. - */ - isc_uint32_t val = isc_random32(); - for (i = 0; i < count; i++) { - choice = i + val % (count - i); - rdata = in[i]; - in[i] = in[choice]; - in[choice] = rdata; - if (order != NULL) - out[i].key = (*order)(&in[i], - order_arg); - else - out[i].key = 0; /* Unused */ - out[i].rdata = &in[i]; - } - } else if (want_cyclic) { - /* - * 'Cyclic' order. - */ - isc_uint32_t val; - unsigned int j; - - val = rdataset->count; - if (val == ISC_UINT32_MAX) { - val = isc_random32(); - } - j = val % count; - for (i = 0; i < count; i++) { - if (order != NULL) - out[i].key = (*order)(&in[j], - order_arg); - else - out[i].key = 0; /* Unused */ - out[i].rdata = &in[j]; - j++; - if (j == count) - j = 0; /* Wrap around. */ - } + unsigned int j, seed; + if (ISC_LIKELY(want_random)) { + seed = isc_random32(); + j = 0; } - } else if (sort) { + + if (ISC_UNLIKELY(want_cyclic) && (rdataset->count < ISC_UINT32_MAX)) { + j = rdataset->count % count; + } else { /* Otherwise, just start from beginning */ + j = 0; + } + for (i = 0; i < count; i++) { - if (order != NULL) - out[i].key = (*order)(&in[i], order_arg); - else - out[i].key = 0; /* Unused */ - out[i].rdata = &in[i]; - } - } + if (ISC_LIKELY(want_random)) { + swap_rdata(in, j, j + seed % (count - j)); + } - /* - * Sortlist order. - */ - if (sort) { - qsort(out, count, sizeof(out[0]), towire_compare); + out[i].key = (sort) ? + (*order)(&in[j], order_arg) : + 0; + out[i].rdata = &in[j]; + if (++j == count) { + j = 0; + } + } + /* + * Sortlist order. + */ + if (sort) { + qsort(out, count, sizeof(out[0]), towire_compare); + } } savedbuffer = *target; @@ -497,6 +481,8 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, isc_buffer_putuint16(target, rdataset->type); isc_buffer_putuint16(target, rdataset->rdclass); if (!question) { + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_buffer_putuint32(target, rdataset->ttl); /*