no more iov per rr.

git-svn-id: file:///svn/unbound/trunk@266 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-04-27 12:42:03 +00:00
parent 87bff3dc63
commit 1bffcab1f3
5 changed files with 92 additions and 161 deletions

View file

@ -1,3 +1,6 @@
27 April 2007: Wouter
- removed iov usage, it is not good for dns message encoding.
26 April 2007: Wouter
- floating point exception fix in lock-verify.
- lint uses make dependency

View file

@ -12,5 +12,7 @@ o possible optimization, so that precious id number resource is not depleted
special id numbers, and if you release the next_id number for the thread
it reuses that id number.
o use rbtree to compress domain names in messages, sorted AXFRs of 16Kb
and so on. This may be faster for that case.
and so on. For current packets, even worstcase, list, is ok. Only if we
start to send out compressed AXFRs then it becomes a problem.
We can cap AXFR packets on 256 or 1024 domain names, for example.
o speed up pkt domain name decompression loop detection using counter perhaps.

View file

@ -253,8 +253,6 @@ testpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
uint16_t flags;
uint32_t timenow = 0;
region_type *region = region_create(malloc, free);
struct iovec iov[1024];
size_t maxiov = 1024;
hex_to_buf(pkt, hex);
memmove(&id, ldns_buffer_begin(pkt), sizeof(id));
@ -268,11 +266,11 @@ testpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
checkformerr(pkt);
unit_assert(ret != LDNS_RCODE_SERVFAIL);
} else {
sz = reply_info_iov_regen(&qi, rep, id, flags, iov, maxiov,
timenow, region);
sz = reply_info_encode(&qi, rep, id, flags, out, timenow,
region);
unit_assert(sz != 0); /* udp packets should fit in 1024 iov */
write_iov_buffer(out, iov, sz);
if(vbmp) printf("iov len outlen %u %u\n", (unsigned)sz,
if(vbmp) printf("inlen %u outlen %u\n",
(unsigned)ldns_buffer_limit(pkt),
(unsigned)ldns_buffer_limit(out));
test_buffers(pkt, out);
}

View file

@ -676,149 +676,86 @@ compress_tree_store(struct compress_tree_node** tree, uint8_t* dname,
return 1;
}
/** bake a new type-class-ttl value, or 0 on malloc error */
static uint32_t*
bake_tcttl(int do_sig, region_type* region,
struct packed_rrset_key* rk, uint32_t ttl, uint32_t timenow,
uint32_t* prevttl, uint32_t* prevtcttl)
{
/* type, class, ttl,
type-class-ttl used for rrsigs.
ttl used for data itself. */
uint32_t* t;
if(prevttl && *prevttl == ttl)
return prevtcttl;
if(do_sig) {
t = (uint32_t*)region_alloc(region, 2*sizeof(uint32_t));
if(!t) return 0;
((uint16_t*)t)[0] = htons(LDNS_RR_TYPE_RRSIG);
memcpy( &(((uint16_t*)t)[1]), &(rk->dname[rk->dname_len+2]),
sizeof(uint16_t));
t[1] = htonl(ttl - timenow);
} else {
t = (uint32_t*)region_alloc(region, sizeof(uint32_t));
if(!t) return 0;
t[0] = htonl(ttl - timenow);
}
return t;
}
/** bake dname iov */
/** bake dname compression */
static int
bakedname(int dosig, struct compress_tree_node** tree, size_t* offset,
region_type* region, struct iovec* iov, struct packed_rrset_key* rk)
bakedname(struct compress_tree_node** tree, region_type* region,
ldns_buffer* pkt, struct packed_rrset_key* rk)
{
/* see if this name can be compressed */
size_t pos = ldns_buffer_position(pkt);
struct compress_tree_node* p;
int labs = dname_count_labels(rk->dname);
p = compress_tree_lookup(*tree, rk->dname, labs);
if(p && p->offset <= PTR_MAX_OFFSET) {
/* compress it */
int labcopy = labs - p->labs;
size_t len = 0;
uint8_t lablen;
uint8_t* from = rk->dname;
uint16_t ptr;
uint8_t* dat = (uint8_t*)region_alloc(region,
(dosig?0:sizeof(uint16_t)*2) + rk->dname_len);
/* note: oversized memory allocation. */
if(!dat) return 0;
iov->iov_base = dat;
/* copy the first couple of labels */
while(labcopy--) {
lablen = *from++;
*dat++ = lablen;
memmove(dat, from, lablen);
len += lablen+1;
dat += lablen;
ldns_buffer_write_u8(pkt, lablen);
ldns_buffer_write(pkt, from, lablen);
from += lablen;
}
/* insert compression ptr */
ptr = (uint16_t)(0xc000 | p->offset);
ptr = htons(ptr);
memmove(dat, &ptr, sizeof(ptr));
len += sizeof(ptr);
dat += sizeof(ptr);
if(!dosig) {
/* add type and class */
memmove(dat, &rk->dname[rk->dname_len], 4);
dat += 4;
len += 4;
}
log_assert(len <= (dosig?0:sizeof(uint16_t)*2) + rk->dname_len);
iov->iov_len = len;
ldns_buffer_write_u16(pkt, ptr);
} else {
/* uncompressed */
iov->iov_base = rk->dname;
if(dosig)
iov->iov_len = rk->dname_len;
else iov->iov_len = rk->dname_len + 4;
ldns_buffer_write(pkt, rk->dname, rk->dname_len);
}
/* store this name for future compression */
if(!compress_tree_store(tree, rk->dname, labs, *offset, region, p))
if(!compress_tree_store(tree, rk->dname, labs, pos, region, p))
return 0;
return 1;
}
/** store rrset in iov vector */
static int
packed_rrset_iov(struct ub_packed_rrset_key* key, struct iovec* iov,
size_t max, uint16_t* num_rrs, uint32_t timenow, region_type* region,
size_t* used, int do_data, int do_sig,
struct compress_tree_node** tree, size_t* offset)
packed_rrset_iov(struct ub_packed_rrset_key* key, ldns_buffer* pkt,
uint16_t* num_rrs, uint32_t timenow, region_type* region,
int do_data, int do_sig, struct compress_tree_node** tree)
{
size_t i;
uint32_t* tcttl = 0;
struct packed_rrset_data* data = (struct packed_rrset_data*)
key->entry.data;
if(do_data) {
*num_rrs += data->count;
for(i=0; i<data->count; i++) {
if(max - *used < 3) return 0;
if(!(tcttl = bake_tcttl(0, region, &key->rk,
data->rr_ttl[i], timenow,
i>0?&data->rr_ttl[i-1]:0, tcttl)))
return 0;
/* no compression of dnames yet */
if(1) {
if(!bakedname(0, tree, offset, region, &iov[*used],
&key->rk))
return 0;
if(1) { /* compression */
if(!bakedname(tree, region, pkt, &key->rk))
return 0;
ldns_buffer_write(pkt,
&key->rk.dname[key->rk.dname_len], 4);
} else {
/* no compression */
iov[*used].iov_base = (void*)key->rk.dname;
iov[*used].iov_len = key->rk.dname_len + 4;
ldns_buffer_write(pkt, key->rk.dname,
key->rk.dname_len + 4);
}
iov[*used+1].iov_base = (void*)tcttl;
iov[*used+1].iov_len = sizeof(uint32_t);
iov[*used+2].iov_base = (void*)data->rr_data[i];
iov[*used+2].iov_len = data->rr_len[i];
*offset += iov[*used].iov_len + sizeof(uint32_t) +
data->rr_len[i];
*used += 3;
ldns_buffer_write_u32(pkt, data->rr_ttl[i]-timenow);
ldns_buffer_write(pkt, data->rr_data[i],
data->rr_len[i]);
}
}
/* insert rrsigs */
if(do_sig) {
size_t total = data->count+data->rrsig_count;
*num_rrs += data->rrsig_count;
for(i=0; i<data->rrsig_count; i++) {
if(max - *used < 3) return 0;
if(!(tcttl = bake_tcttl(1, region, &key->rk,
data->rr_ttl[data->count+i], timenow,
i>0?&data->rr_ttl[i-1]:0, tcttl)))
return 0;
for(i=data->count; i<total; i++) {
/* no compression of dnames yet */
iov[*used].iov_base = (void*)key->rk.dname;
iov[*used].iov_len = key->rk.dname_len;
iov[*used+1].iov_base = (void*)tcttl;
iov[*used+1].iov_len = sizeof(uint32_t)*2;
iov[*used+2].iov_base = (void*)data->rr_data[data->count+i];
iov[*used+2].iov_len = data->rr_len[data->count+i];
*offset += iov[*used].iov_len + sizeof(uint32_t)*2 +
data->rr_len[data->count+i];
*used += 3;
ldns_buffer_write(pkt, key->rk.dname,
key->rk.dname_len);
ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG);
ldns_buffer_write(pkt, &(key->rk.dname[
key->rk.dname_len+2]), sizeof(uint16_t));
ldns_buffer_write_u32(pkt, data->rr_ttl[i]-timenow);
ldns_buffer_write(pkt, data->rr_data[i],
data->rr_len[i]);
}
}
@ -828,90 +765,81 @@ packed_rrset_iov(struct ub_packed_rrset_key* key, struct iovec* iov,
/** store msg section in iov vector */
static int
insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
struct iovec* iov, size_t max, size_t rrsets_before,
uint32_t timenow, region_type* region, size_t* used, int addit,
struct compress_tree_node** tree, size_t* offset)
ldns_buffer* pkt, size_t rrsets_before, uint32_t timenow,
region_type* region, int addit, struct compress_tree_node** tree)
{
size_t i;
*num_rrs = 0;
if(!addit) {
for(i=0; i<num_rrsets; i++)
if(!packed_rrset_iov(rep->rrsets[rrsets_before+i], iov,
max, num_rrs, timenow, region, used, 1, 1,
tree, offset))
if(!packed_rrset_iov(rep->rrsets[rrsets_before+i], pkt,
num_rrs, timenow, region, 1, 1, tree))
return 0;
} else {
for(i=0; i<num_rrsets; i++)
if(!packed_rrset_iov(rep->rrsets[rrsets_before+i], iov,
max, num_rrs, timenow, region, used, 1, 0,
tree, offset))
if(!packed_rrset_iov(rep->rrsets[rrsets_before+i], pkt,
num_rrs, timenow, region, 1, 0, tree))
return 0;
for(i=0; i<num_rrsets; i++)
if(!packed_rrset_iov(rep->rrsets[rrsets_before+i], iov,
max, num_rrs, timenow, region, used, 0, 1,
tree, offset))
if(!packed_rrset_iov(rep->rrsets[rrsets_before+i], pkt,
num_rrs, timenow, region, 0, 1, tree))
return 0;
}
*num_rrs = htons(*num_rrs);
return 1;
}
size_t reply_info_iov_regen(struct query_info* qinfo, struct reply_info* rep,
uint16_t id, uint16_t flags, struct iovec* iov, size_t max,
uint32_t timenow, region_type* region)
int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow,
region_type* region)
{
size_t used;
uint16_t* hdr = (uint16_t*)region_alloc(region, sizeof(uint16_t)*6);
size_t offset = 0;
uint16_t ancount=0, nscount=0, arcount=0;
struct compress_tree_node* tree = 0;
if(!hdr) return 0;
if(max<1) return 0;
hdr[0] = id;
hdr[1] = htons(flags);
iov[0].iov_base = (void*)&hdr[0];
iov[0].iov_len = sizeof(uint16_t)*6;
hdr[2] = htons(rep->qdcount);
offset = sizeof(uint16_t)*6;
used=1;
ldns_buffer_clear(buffer);
if(ldns_buffer_capacity(buffer) < LDNS_HEADER_SIZE)
return 0;
ldns_buffer_write(buffer, &id, sizeof(uint16_t));
ldns_buffer_write_u16(buffer, flags);
ldns_buffer_write_u16(buffer, rep->qdcount);
/* skip an, ns, ar counts */
ldns_buffer_set_position(buffer, LDNS_HEADER_SIZE);
/* insert query section */
if(rep->qdcount) {
uint16_t* qt = (uint16_t*)region_alloc(region,sizeof(uint16_t));
uint16_t* qc = (uint16_t*)region_alloc(region,sizeof(uint16_t));
if(!qt || !qc) return 0;
if(max-used < 3) return 0;
iov[used].iov_base = (void*)qinfo->qname;
iov[used].iov_len = qinfo->qnamesize;
if(ldns_buffer_remaining(buffer) <
qinfo->qnamesize+sizeof(uint16_t)*2)
return 0; /* buffer too small */
if(!compress_tree_store(&tree, qinfo->qname,
dname_count_labels(qinfo->qname), offset, region, NULL))
dname_count_labels(qinfo->qname),
ldns_buffer_position(buffer), region, NULL))
return 0;
*qt = htons(qinfo->qtype);
*qc = htons(qinfo->qclass);
iov[used+1].iov_base = (void*)qt;
iov[used+1].iov_len = sizeof(uint16_t);
iov[used+2].iov_base = (void*)qc;
iov[used+2].iov_len = sizeof(uint16_t);
offset += qinfo->qnamesize + sizeof(uint16_t)*2;
used += 3;
ldns_buffer_write(buffer, qinfo->qname, qinfo->qnamesize);
ldns_buffer_write_u16(buffer, qinfo->qtype);
ldns_buffer_write_u16(buffer, qinfo->qclass);
}
/* insert answer section */
if(!insert_section(rep, rep->an_numrrsets, &hdr[3], iov, max,
0, timenow, region, &used, 0, &tree, &offset))
if(!insert_section(rep, rep->an_numrrsets, &ancount, buffer,
0, timenow, region, 0, &tree))
return 0;
ldns_buffer_write_u16_at(buffer, 6, ancount);
/* insert auth section */
if(!insert_section(rep, rep->ns_numrrsets, &hdr[4], iov, max,
rep->an_numrrsets, timenow, region, &used, 0, &tree, &offset))
if(!insert_section(rep, rep->ns_numrrsets, &nscount, buffer,
rep->an_numrrsets, timenow, region, 0, &tree))
return 0;
ldns_buffer_write_u16_at(buffer, 8, nscount);
/* insert add section */
if(!insert_section(rep, rep->ar_numrrsets, &hdr[5], iov, max,
if(!insert_section(rep, rep->ar_numrrsets, &arcount, buffer,
rep->an_numrrsets + rep->ns_numrrsets, timenow, region,
&used, 1, &tree, &offset))
1, &tree))
return 0;
ldns_buffer_write_u16_at(buffer, 10, arcount);
ldns_buffer_flip(buffer);
return used;
return 1;
}
void

View file

@ -251,20 +251,20 @@ void reply_info_answer(struct reply_info* rep, uint16_t qflags,
ldns_buffer* buf);
/**
* Regenerate the wireformat from the parsed msg.
* Regenerate the wireformat from the stored msg reply.
* @param qinfo: query info to store.
* @param rep: reply to store.
* @param id: id value to store, network order.
* @param flags: flags value to store, host order.
* @param iov: iov to store it into (start position to store).
* @param max: max that can be stored.
* @param buffer: buffer to store the packet into.
* @param timenow: time now, to adjust ttl values.
* @param region: to store temporary data in.
* @return: number of items stored, 0 on error.
* @return: nonzero is success, or
* 0 on error: malloc failure or buffer too small.
*/
size_t reply_info_iov_regen(struct query_info* qinfo, struct reply_info* rep,
uint16_t id, uint16_t flags, struct iovec* iov, size_t max,
uint32_t timenow, struct region* region);
int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow,
struct region* region);
/**
* Generate and send out answer from reply_info.