From: Wouter Wijngaards Date: Thu, 3 May 2007 15:34:03 +0000 (+0000) Subject: Use packedrrset msgformat in service. X-Git-Tag: release-0.3~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8420d0b81922906326e980f540a46cdf556b7ebe;p=thirdparty%2Funbound.git Use packedrrset msgformat in service. git-svn-id: file:///svn/unbound/trunk@277 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/daemon.c b/daemon/daemon.c index 6457347fc..8c6742dd3 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -126,6 +126,15 @@ daemon_init() free(daemon); return NULL; } + daemon->rrset_cache = slabhash_create(HASH_DEFAULT_SLABS, + HASH_DEFAULT_STARTARRAY, HASH_DEFAULT_MAXMEM, + ub_rrset_sizefunc, ub_rrset_compare, + ub_rrset_key_delete, rrset_data_delete, &daemon->superalloc); + if(!daemon->rrset_cache) { + slabhash_delete(daemon->msg_cache); + free(daemon); + return NULL; + } alloc_init(&daemon->superalloc, NULL, 0); return daemon; } @@ -313,6 +322,7 @@ daemon_delete(struct daemon* daemon) return; listening_ports_free(daemon->ports); slabhash_delete(daemon->msg_cache); + slabhash_delete(daemon->rrset_cache); alloc_clear(&daemon->superalloc); free(daemon->cwd); free(daemon->pidfile); diff --git a/daemon/daemon.h b/daemon/daemon.h index 022623f87..8eee819b5 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -74,6 +74,8 @@ struct daemon { struct alloc_cache superalloc; /** the message cache, content is struct msgreply_entry* */ struct slabhash* msg_cache; + /** the rrset cache, content is struct struct ub_packed_rrset_key* */ + struct slabhash* rrset_cache; }; /** diff --git a/daemon/worker.c b/daemon/worker.c index 51c94a8b3..8a25742f8 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -92,18 +92,19 @@ req_release(struct work_query* w) w->worker->free_queries = w; } -/** reply to query with given error code */ -static void -replyerror(int r, struct work_query* w) +/** create error and fill into buffer */ +static void +replyerror_fillbuf(int r, struct comm_reply* repinfo, uint16_t id, + uint16_t qflags, struct query_info* qinfo) { - ldns_buffer* buf = w->query_reply.c->buffer; + ldns_buffer* buf = repinfo->c->buffer; uint16_t flags; verbose(VERB_DETAIL, "reply with error"); ldns_buffer_clear(buf); - ldns_buffer_write(buf, &w->query_id, sizeof(uint16_t)); + ldns_buffer_write(buf, &id, sizeof(uint16_t)); flags = (uint16_t)(BIT_QR | r); /* QR and retcode*/ - flags |= (w->query_flags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */ + flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */ ldns_buffer_write_u16(buf, flags); flags = 1; ldns_buffer_write_u16(buf, flags); @@ -111,23 +112,47 @@ replyerror(int r, struct work_query* w) ldns_buffer_write(buf, &flags, sizeof(uint16_t)); ldns_buffer_write(buf, &flags, sizeof(uint16_t)); ldns_buffer_write(buf, &flags, sizeof(uint16_t)); - ldns_buffer_write(buf, w->qinfo.qname, w->qinfo.qnamesize); - ldns_buffer_write_u16(buf, w->qinfo.qtype); - ldns_buffer_write_u16(buf, w->qinfo.qclass); + ldns_buffer_write(buf, qinfo->qname, qinfo->qnamesize); + ldns_buffer_write_u16(buf, qinfo->qtype); + ldns_buffer_write_u16(buf, qinfo->qclass); ldns_buffer_flip(buf); +} + +/** reply to query with given error code */ +static void +replyerror(int r, struct work_query* w) +{ + replyerror_fillbuf(r, &w->query_reply, w->query_id, w->query_flags, + &w->qinfo); comm_point_send_reply(&w->query_reply); req_release(w); query_info_clear(&w->qinfo); } +/** store rrsets in the rrset cache. */ +static void +worker_store_rrsets(struct worker* worker, struct reply_info* rep) +{ + size_t i; + for(i=0; irrset_count; i++) { + /* TODO: check if update really needed */ + slabhash_insert(worker->daemon->rrset_cache, + rep->rrsets[i]->entry.hash, &rep->rrsets[i]->entry, + rep->rrsets[i]->entry.data); + } +} + /** process incoming replies from the network */ static int worker_handle_reply(struct comm_point* c, void* arg, int error, struct comm_reply* ATTR_UNUSED(reply_info)) { struct work_query* w = (struct work_query*)arg; + struct query_info qinf; struct reply_info* rep; struct msgreply_entry* e; + int r; + verbose(VERB_DETAIL, "reply to query with stored ID %d", ntohs(w->query_id)); /* byteswapped so same as dig prints */ if(error != 0) { @@ -142,32 +167,36 @@ worker_handle_reply(struct comm_point* c, void* arg, int error, if(LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) return 0; /* too much in the query section */ /* woohoo a reply! */ - rep = (struct reply_info*)malloc(sizeof(struct reply_info)); - if(!rep) { - log_err("out of memory"); + if((r=reply_info_parse(c->buffer, &w->worker->alloc, &qinf, &rep))!=0) { + if(r == LDNS_RCODE_SERVFAIL) + log_err("reply_info_parse: out of memory"); + /* formerr on my parse gives servfail to my client */ replyerror(LDNS_RCODE_SERVFAIL, w); return 0; } - rep->flags = ldns_buffer_read_u16_at(c->buffer, 2); - rep->replysize = ldns_buffer_limit(c->buffer) - DNS_ID_AND_FLAGS; - log_info("got reply of size %u", (unsigned)rep->replysize); - rep->reply = (uint8_t*)malloc(rep->replysize); - if(!rep->reply) { - free(rep); - log_err("out of memory"); + if(!reply_info_answer_encode(&qinf, rep, w->query_id, w->query_flags, + w->query_reply.c->buffer, 0, 0)) { replyerror(LDNS_RCODE_SERVFAIL, w); + query_info_clear(&qinf); + reply_info_parsedelete(rep, &w->worker->alloc); return 0; } - memcpy(rep->reply, ldns_buffer_at(c->buffer, DNS_ID_AND_FLAGS), - rep->replysize); - reply_info_answer_iov(rep, w->query_id, w->query_flags, - &w->query_reply, 0); + comm_point_send_reply(&w->query_reply); req_release(w); - /* store or update reply in the cache */ - if(!(e = query_info_entrysetup(&w->qinfo, rep, w->query_hash))) { - free(rep->reply); - free(rep); - log_err("out of memory"); + query_info_clear(&w->qinfo); + if(rep->ttl == 0) { + log_info("TTL 0: dropped"); + query_info_clear(&qinf); + reply_info_parsedelete(rep, &w->worker->alloc); + return 0; + } + reply_info_set_ttls(rep, time(0)); + worker_store_rrsets(w->worker, rep); + reply_info_fillref(rep); + /* store msg in the cache */ + if(!(e = query_info_entrysetup(&qinf, rep, w->query_hash))) { + query_info_clear(&qinf); + reply_info_parsedelete(rep, &w->worker->alloc); return 0; } slabhash_insert(w->worker->daemon->msg_cache, w->query_hash, @@ -258,6 +287,46 @@ worker_handle_control_cmd(struct comm_point* c, void* arg, int error, return 0; } +/** answer query from the cache */ +static int +answer_from_cache(struct lruhash_entry* e, uint16_t id, + uint16_t flags, struct comm_reply* repinfo) +{ + struct msgreply_entry* mrentry = (struct msgreply_entry*)e->key; + struct reply_info* rep = (struct reply_info*)e->data; + uint32_t timenow = time(0); + size_t i; + /* see if it is possible */ + if(rep->ttl <= timenow) { + /* the rrsets may have been updated in the meantime */ + /* but this ignores it */ + return 0; + } + /* check rrsets */ + for(i=0; irrset_count; i++) { + lock_rw_rdlock(&rep->ref[i].key->entry.lock); + if(rep->ref[i].id != rep->ref[i].key->id || + rep->ttl <= timenow) { + /* failure! rollback our readlocks */ + size_t j; + for(j=0; j<=i; j++) + lock_rw_unlock(&rep->ref[j].key->entry.lock); + return 0; + } + } + /* locked and ids and ttls are OK. */ + if(!reply_info_answer_encode(&mrentry->key, rep, id, flags, + repinfo->c->buffer, timenow, 1)) { + replyerror_fillbuf(LDNS_RCODE_SERVFAIL, repinfo, id, + flags, &mrentry->key); + } + /* unlock */ + for(i=0; irrset_count; i++) + lock_rw_unlock(&rep->ref[i].key->entry.lock); + /* go and return this buffer to the client */ + return 1; +} + /** handles callbacks from listening event interface */ static int worker_handle_request(struct comm_point* c, void* arg, int error, @@ -295,13 +364,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error, h = query_info_hash(&qinfo); if((e=slabhash_lookup(worker->daemon->msg_cache, h, &qinfo, 0))) { /* answer from cache - we have acquired a readlock on it */ - uint16_t id; log_info("answer from the cache"); - memcpy(&id, ldns_buffer_begin(c->buffer), sizeof(uint16_t)); - reply_info_answer_iov((struct reply_info*)e->data, id, - ldns_buffer_read_u16_at(c->buffer, 2), repinfo, 1); + if(answer_from_cache(e, + *(uint16_t*)ldns_buffer_begin(c->buffer), + ldns_buffer_read_u16_at(c->buffer, 2), repinfo)) { + lock_rw_unlock(&e->lock); + return 1; + } + log_info("answer from the cache -- data has timed out"); lock_rw_unlock(&e->lock); - return 0; } ldns_buffer_rewind(c->buffer); server_stats_querymiss(&worker->stats, worker); diff --git a/doc/Changelog b/doc/Changelog index 1fb1ed2ba..48fdd30f5 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,8 @@ +3 May 2007: Wouter + - fill refs. Use new parse and encode to answer queries. + - stores rrsets in cache. + - uses new msgreply format in cache. + 2 May 2007: Wouter - dname unit tests in own file and spread out neatly in functions. - more dname unit tests. diff --git a/util/data/msgparse.h b/util/data/msgparse.h index 5b7715af3..0b2023a05 100644 --- a/util/data/msgparse.h +++ b/util/data/msgparse.h @@ -71,6 +71,8 @@ struct region; #define PARSE_TABLE_SIZE 1024 /** Maximum TTL that is allowed. */ #define MAX_TTL 3600*24*365*10 /* ten years */ +/** Negative cache time (for entries without any RRs.) */ +#define NORR_TTL 5 /* seconds */ /** * Data stored in scratch pad memory during parsing. diff --git a/util/data/msgreply.c b/util/data/msgreply.c index c35b05d5b..94f7f5960 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -71,6 +71,9 @@ parse_create_qinfo(ldns_buffer* pkt, struct msg_parse* msg, qinf->qnamesize = msg->qname_len; qinf->qtype = msg->qtype; qinf->qclass = msg->qclass; + qinf->has_cd = 0; + if(msg->flags & BIT_CD) + qinf->has_cd = 1; return 1; } @@ -83,8 +86,6 @@ parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep) sizeof(struct rrset_ref) * (msg->rrset_count-1) + sizeof(struct ub_packed_rrset_key*) * msg->rrset_count); if(!*rep) return 0; - (*rep)->reply = 0; /* unused */ - (*rep)->replysize = 0; /* unused */ (*rep)->flags = msg->flags; (*rep)->qdcount = msg->qdcount; (*rep)->ttl = 0; @@ -262,6 +263,9 @@ parse_copy_decompress(ldns_buffer* pkt, struct msg_parse* msg, struct rrset_parse *pset = msg->rrset_first; struct packed_rrset_data* data; log_assert(rep); + rep->ttl = MAX_TTL; + if(rep->rrset_count == 0) + rep->ttl = NORR_TTL; for(i=0; irrset_count; i++) { rep->rrsets[i]->rk.flags = pset->flags; @@ -282,7 +286,10 @@ parse_copy_decompress(ldns_buffer* pkt, struct msg_parse* msg, if((ret=parse_create_rrset(pkt, pset, &data)) != 0) return ret; rep->rrsets[i]->entry.data = (void*)data; + rep->rrsets[i]->entry.key = (void*)rep->rrsets[i]; rep->rrsets[i]->entry.hash = pset->hash; + if(data->ttl < rep->ttl) + rep->ttl = data->ttl; pset = pset->rrset_all_next; } @@ -349,6 +356,41 @@ int reply_info_parse(ldns_buffer* pkt, struct alloc_cache* alloc, return 0; } +/** helper compare function to sort in lock order */ +static int +reply_info_fillref_cmp(const void* a, const void* b) +{ + if(a < b) return -1; + if(a > b) return 1; + return 0; +} + +void +reply_info_fillref(struct reply_info* rep) +{ + size_t i; + for(i=0; irrset_count; i++) { + rep->ref[i].key = rep->rrsets[i]; + rep->ref[i].id = rep->rrsets[i]->id; + } + qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref), + reply_info_fillref_cmp); +} + +void +reply_info_set_ttls(struct reply_info* rep, uint32_t timenow) +{ + size_t i, j; + rep->ttl += timenow; + for(i=0; irrset_count; i++) { + struct packed_rrset_data* data = (struct packed_rrset_data*) + rep->rrsets[i]->entry.data; + data->ttl += timenow; + for(j=0; jcount + data->rrsig_count; j++) + data->rr_ttl[j] += timenow; + } +} + void reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc) { @@ -373,7 +415,7 @@ query_info_parse(struct query_info* m, ldns_buffer* query) log_assert(LDNS_OPCODE_WIRE(q) == LDNS_PACKET_QUERY); log_assert(LDNS_QDCOUNT(q) == 1); log_assert(ldns_buffer_position(query) == 0); - m->has_cd = (int)LDNS_CD_WIRE(q); + m->has_cd = LDNS_CD_WIRE(q)?1:0; ldns_buffer_skip(query, LDNS_HEADER_SIZE); m->qname = ldns_buffer_current(query); if((m->qnamesize = query_dname_len(query)) == 0) @@ -427,20 +469,17 @@ query_info_clear(struct query_info* m) m->qname = NULL; } -void -reply_info_clear(struct reply_info* m) -{ - free(m->reply); - m->reply = NULL; -} - size_t msgreply_sizefunc(void* k, void* d) { struct query_info* q = (struct query_info*)k; struct reply_info* r = (struct reply_info*)d; - return sizeof(struct msgreply_entry) + sizeof(struct reply_info) - + r->replysize + q->qnamesize; + size_t s = sizeof(struct msgreply_entry) + sizeof(struct reply_info) + + q->qnamesize; + if(r->rrset_count > 0) + s += r->rrset_count * (sizeof(struct ub_packed_rrset_key*) + + sizeof(struct rrset_ref)); + return s; } void @@ -456,7 +495,6 @@ void reply_info_delete(void* d, void* ATTR_UNUSED(arg)) { struct reply_info* r = (struct reply_info*)d; - reply_info_clear(r); free(r); } @@ -471,20 +509,6 @@ query_info_hash(struct query_info *q) return h; } -void -reply_info_answer(struct reply_info* rep, uint16_t qflags, - ldns_buffer* buffer) -{ - uint16_t flags; - ldns_buffer_clear(buffer); - ldns_buffer_skip(buffer, 2); /* ID */ - flags = rep->flags | (qflags & BIT_RD); /* copy RD bit */ - log_assert(flags & BIT_QR); /* QR bit must be on in our replies */ - ldns_buffer_write_u16(buffer, flags); - ldns_buffer_write(buffer, rep->reply, rep->replysize); - ldns_buffer_flip(buffer); -} - /** * Data structure to help domain name compression in outgoing messages. * A tree of dnames and their offsets in the packet is kept. @@ -851,19 +875,10 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt, if(do_data) { const ldns_rr_descriptor* c = type_rdata_compressable(key); for(i=0; icount; i++) { - if(1) { /* compression */ - if((r=compress_owner(key, pkt, region, tree, - owner_pos, &owner_ptr, owner_labs)) - != RETVAL_OK) - return r; - } else { - /* no compression */ - if(ldns_buffer_remaining(pkt) < - key->rk.dname_len + 4+4+2) - return RETVAL_TRUNC; - ldns_buffer_write(pkt, key->rk.dname, - key->rk.dname_len + 4); - } + if((r=compress_owner(key, pkt, region, tree, + owner_pos, &owner_ptr, owner_labs)) + != RETVAL_OK) + return r; ldns_buffer_write_u32(pkt, data->rr_ttl[i]-timenow); if(c) { if((r=compress_rdata(pkt, data->rr_data[i], @@ -882,28 +897,19 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt, if(do_sig) { size_t total = data->count+data->rrsig_count; for(i=data->count; irr_len[i]) - return RETVAL_TRUNC; - ldns_buffer_write(pkt, &owner_ptr, 2); - } else { - if((r=compress_any_dname(key->rk.dname, - pkt, owner_labs, region, tree)) - != RETVAL_OK) - return r; - if(ldns_buffer_remaining(pkt) < - 4+4+data->rr_len[i]) - return RETVAL_TRUNC; - } + if(owner_ptr) { + if(ldns_buffer_remaining(pkt) < + 2+4+4+data->rr_len[i]) + return RETVAL_TRUNC; + ldns_buffer_write(pkt, &owner_ptr, 2); } else { - /* no compression */ + if((r=compress_any_dname(key->rk.dname, + pkt, owner_labs, region, tree)) + != RETVAL_OK) + return r; if(ldns_buffer_remaining(pkt) < - key->rk.dname_len+4+4+data->rr_len[i]) + 4+4+data->rr_len[i]) return RETVAL_TRUNC; - 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[ @@ -1045,29 +1051,29 @@ int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, return 1; } -void -reply_info_answer_iov(struct reply_info* rep, uint16_t qid, - uint16_t qflags, struct comm_reply* comrep, int cached) +int +reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, + uint16_t id, uint16_t qflags, ldns_buffer* pkt, uint32_t timenow, + int cached) { - /* [0]=reserved for tcplen, [1]=id, [2]=flags, [3]=message */ - struct iovec iov[4]; + uint16_t flags; + region_type* region = region_create(malloc, free); - iov[1].iov_base = (void*)&qid; - iov[1].iov_len = sizeof(uint16_t); if(!cached) { /* original flags, copy RD bit from query. */ - qflags = rep->flags | (qflags & BIT_RD); + flags = rep->flags | (qflags & BIT_RD); } else { /* remove AA bit, copy RD and CD bits from query. */ - qflags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD)); + flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD)); } - log_assert(qflags & BIT_QR); /* QR bit must be on in our replies */ - qflags = htons(qflags); - iov[2].iov_base = (void*)&qflags; - iov[2].iov_len = sizeof(uint16_t); - iov[3].iov_base = (void*)rep->reply; - iov[3].iov_len = rep->replysize; - comm_point_send_reply_iov(comrep, iov, 4); + log_assert(flags & BIT_QR); /* QR bit must be on in our replies */ + + if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region)) { + log_err("reply encode: out of memory"); + return 0; + } + region_destroy(region); + return 1; } struct msgreply_entry* diff --git a/util/data/msgreply.h b/util/data/msgreply.h index 63990456c..a3e6b0d90 100644 --- a/util/data/msgreply.h +++ b/util/data/msgreply.h @@ -90,12 +90,6 @@ struct rrset_ref { * o packed_rrset_key* array. */ struct reply_info { - /** the reply packet, skips ID and flags, - * starts with opcode/rcode word */ - uint8_t* reply; - /** the reply size */ - size_t replysize; - /** the flags for the answer, host byte order. */ uint16_t flags; @@ -197,6 +191,19 @@ int query_info_parse(struct query_info* m, ldns_buffer* query); int reply_info_parse(ldns_buffer* pkt, struct alloc_cache* alloc, struct query_info* qinf, struct reply_info** rep); +/** + * Fills in the ref array based on the rest of the structure, the rrsets. + * @param rep: reply info. rrsets must be filled in. + */ +void reply_info_fillref(struct reply_info* rep); + +/** + * Set TTLs inside the replyinfo to absolute values. + * @param rep: reply info. rrsets must be filled in. + * @param timenow: the current time. + */ +void reply_info_set_ttls(struct reply_info* rep, uint32_t timenow); + /** * Delete reply_info and packed_rrsets (while they are not yet added to the * hashtables.). Returns rrsets to the alloc cache. @@ -224,9 +231,6 @@ int query_info_compare(void* m1, void* m2); /** clear out query info structure. */ void query_info_clear(struct query_info* m); -/** clear out reply info structure */ -void reply_info_clear(struct reply_info* m); - /** calculate size of struct query_info + reply_info */ size_t msgreply_sizefunc(void* k, void* d); @@ -241,14 +245,19 @@ hashvalue_t query_info_hash(struct query_info *q); /** * Generate answer from reply_info. + * @param qinf: query information that provides query section in packet. * @param rep: reply to fill in. + * @param id: id word from the query. * @param qflags: flags word from the query. - * @param buf: buffer to put reply into. Note that the query ID must - * be put in the buffer by caller. - * The buffer must be large enough. + * @param dest: buffer to put message into; will truncate if it does not fit. + * @param timenow: time to subtract. + * @param cached: set true if a cached reply (so no AA bit). + * set false for the first reply. + * @return: 0 on error (server failure). */ -void reply_info_answer(struct reply_info* rep, uint16_t qflags, - ldns_buffer* buf); +int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, + uint16_t id, uint16_t qflags, ldns_buffer* dest, uint32_t timenow, + int cached); /** * Regenerate the wireformat from the stored msg reply. @@ -269,18 +278,6 @@ 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. - * @param rep: reply to fill in. - * @param qid: query id, in network byte order. - * @param qflags: flags word from the query. - * @param comrep: communication reply point. - * @param cached: set true if a cached reply (so no AA bit). - * set false for the first reply. - */ -void reply_info_answer_iov(struct reply_info* rep, uint16_t qid, - uint16_t qflags, struct comm_reply* comrep, int cached); - /** * Setup query info entry * @param q: query info to copy. Emptied as if clear is called. diff --git a/util/data/packed_rrset.c b/util/data/packed_rrset.c index 2ecc109c9..41599bec5 100644 --- a/util/data/packed_rrset.c +++ b/util/data/packed_rrset.c @@ -60,3 +60,62 @@ ub_packed_rrset_parsedelete(struct ub_packed_rrset_key* pkey, alloc_special_release(alloc, pkey); } +size_t +ub_rrset_sizefunc(void* key, void* data) +{ + struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key; + struct packed_rrset_data* d = (struct packed_rrset_data*)data; + size_t s = sizeof(struct ub_packed_rrset_key) + k->rk.dname_len; + if(d->rrsig_count > 0) { + s += ((uint8_t*)d->rr_data[d->count+d->rrsig_count-1] - + (uint8_t*)d) + d->rr_len[d->count+d->rrsig_count-1]; + } else { + log_assert(d->count > 0); + s += ((uint8_t*)d->rr_data[d->count-1] - (uint8_t*)d) + + d->rr_len[d->count-1]; + } + return s; +} + +int +ub_rrset_compare(void* k1, void* k2) +{ + struct ub_packed_rrset_key* key1 = (struct ub_packed_rrset_key*)k1; + struct ub_packed_rrset_key* key2 = (struct ub_packed_rrset_key*)k2; + int c; + if(key1 == key2 || key1->id == key2->id) + return 0; + if(key1->rk.dname_len != key2->rk.dname_len) { + if(key1->rk.dname_len < key2->rk.dname_len) + return -1; + return 1; + } + if((c=memcmp(key1->rk.dname, key2->rk.dname, key1->rk.dname_len)) != 0) + return c; + if(key1->rk.flags != key2->rk.flags) { + if(key1->rk.flags < key2->rk.flags) + return -1; + return 1; + } + return 0; +} + +void +ub_rrset_key_delete(void* key, void* userdata) +{ + struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key; + struct alloc_cache* a = (struct alloc_cache*)userdata; + k->id = 0; + free(k->rk.dname); + k->rk.dname = NULL; + lock_quick_lock(&a->lock); + alloc_special_release(a, k); + lock_quick_unlock(&a->lock); +} + +void +rrset_data_delete(void* data, void* ATTR_UNUSED(userdata)) +{ + struct packed_rrset_data* d = (struct packed_rrset_data*)data; + free(d); +} diff --git a/util/data/packed_rrset.h b/util/data/packed_rrset.h index 41f2bf267..ce0ba8689 100644 --- a/util/data/packed_rrset.h +++ b/util/data/packed_rrset.h @@ -178,4 +178,34 @@ struct packed_rrset { void ub_packed_rrset_parsedelete(struct ub_packed_rrset_key* pkey, struct alloc_cache* alloc); +/** + * Calculate memory size of rrset entry. For hash table usage. + * @param key: struct ub_packed_rrset_key*. + * @param data: struct packed_rrset_data*. + * @return size in bytes. + */ +size_t ub_rrset_sizefunc(void* key, void* data); + +/** + * compares two rrset keys. + * @param k1: struct ub_packed_rrset_key*. + * @param k2: struct ub_packed_rrset_key*. + * @return 0 if equal. + */ +int ub_rrset_compare(void* k1, void* k2); + +/** + * Old key to be deleted. RRset keys are recycled via alloc. + * @param key: struct ub_packed_rrset_key*. + * @param userdata: alloc structure to use for recycling. + */ +void ub_rrset_key_delete(void* key, void* userdata); + +/** + * Old data to be deleted. + * @param data: what to delete. + * @param userdata: user data ptr. + */ +void rrset_data_delete(void* data, void* userdata); + #endif /* UTIL_DATA_PACKED_RRSET_H */