/** allocate qinfo, return 0 on error. */
static int
parse_create_qinfo(ldns_buffer* pkt, struct msg_parse* msg,
- struct query_info* qinf)
+ struct query_info* qinf, struct region* region)
{
if(msg->qname) {
- qinf->qname = (uint8_t*)malloc(msg->qname_len);
+ if(region)
+ qinf->qname = (uint8_t*)region_alloc(region,
+ msg->qname_len);
+ else qinf->qname = (uint8_t*)malloc(msg->qname_len);
if(!qinf->qname) return 0;
dname_pkt_copy(pkt, qinf->qname, msg->qname);
} else qinf->qname = 0;
/** allocate replyinfo, return 0 on error. */
static int
-parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep)
+parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep,
+ struct region* region)
{
/* rrset_count-1 because the first ref is part of the struct. */
- *rep = (struct reply_info*)malloc(sizeof(struct reply_info) +
- sizeof(struct rrset_ref) * (msg->rrset_count-1) +
- sizeof(struct ub_packed_rrset_key*) * msg->rrset_count);
+ size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) +
+ sizeof(struct ub_packed_rrset_key*) * msg->rrset_count;
+ if(region)
+ *rep = (struct reply_info*)region_alloc(region, s);
+ else *rep = (struct reply_info*)malloc(s +
+ sizeof(struct rrset_ref) * (msg->rrset_count));
if(!*rep) return 0;
(*rep)->flags = msg->flags;
(*rep)->qdcount = msg->qdcount;
(*rep)->ar_numrrsets = msg->ar_rrsets;
(*rep)->rrset_count = msg->rrset_count;
/* array starts after the refs */
- (*rep)->rrsets = (struct ub_packed_rrset_key**)
- &((*rep)->ref[msg->rrset_count]);
+ if(region)
+ (*rep)->rrsets = (struct ub_packed_rrset_key**)
+ &((*rep)->ref[0]);
+ else (*rep)->rrsets = (struct ub_packed_rrset_key**)
+ &((*rep)->ref[msg->rrset_count]);
/* zero the arrays to assist cleanup in case of malloc failure */
memset( (*rep)->rrsets, 0,
sizeof(struct ub_packed_rrset_key*) * msg->rrset_count);
- memset( &(*rep)->ref[0], 0,
- sizeof(struct rrset_ref) * msg->rrset_count);
+ if(!region)
+ memset( &(*rep)->ref[0], 0,
+ sizeof(struct rrset_ref) * msg->rrset_count);
return 1;
}
/** allocate (special) rrset keys, return 0 on error. */
static int
parse_alloc_rrset_keys(struct msg_parse* msg, struct reply_info* rep,
- struct alloc_cache* alloc)
+ struct alloc_cache* alloc, struct region* region)
{
size_t i;
for(i=0; i<msg->rrset_count; i++) {
- rep->rrsets[i] = alloc_special_obtain(alloc);
+ if(region) {
+ rep->rrsets[i] = (struct ub_packed_rrset_key*)
+ region_alloc(region,
+ sizeof(struct ub_packed_rrset_key));
+ if(rep->rrsets[i]) {
+ memset(rep->rrsets[i], 0,
+ sizeof(struct ub_packed_rrset_key));
+ rep->rrsets[i]->entry.key = rep->rrsets[i];
+ }
+ }
+ else rep->rrsets[i] = alloc_special_obtain(alloc);
if(!rep->rrsets[i])
return 0;
rep->rrsets[i]->entry.data = NULL;
/** create rrset return 0 on failure */
static int
parse_create_rrset(ldns_buffer* pkt, struct rrset_parse* pset,
- struct packed_rrset_data** data)
+ struct packed_rrset_data** data, struct region* region)
{
/* allocate */
- *data = malloc(sizeof(struct packed_rrset_data) +
+ size_t s = sizeof(struct packed_rrset_data) +
(pset->rr_count + pset->rrsig_count) *
(sizeof(size_t)+sizeof(uint8_t*)+sizeof(uint32_t)) +
- pset->size);
+ pset->size;
+ if(region)
+ *data = region_alloc(region, s);
+ else *data = malloc(s);
if(!*data)
return 0;
/* copy & decompress */
*/
static int
parse_copy_decompress(ldns_buffer* pkt, struct msg_parse* msg,
- struct reply_info* rep)
+ struct reply_info* rep, struct region* region)
{
size_t i;
struct rrset_parse *pset = msg->rrset_first;
for(i=0; i<rep->rrset_count; i++) {
rep->rrsets[i]->rk.flags = pset->flags;
rep->rrsets[i]->rk.dname_len = pset->dname_len;
- rep->rrsets[i]->rk.dname = (uint8_t*)malloc(pset->dname_len);
+ if(region)
+ rep->rrsets[i]->rk.dname = (uint8_t*)region_alloc(
+ region, pset->dname_len);
+ else rep->rrsets[i]->rk.dname =
+ (uint8_t*)malloc(pset->dname_len);
if(!rep->rrsets[i]->rk.dname)
return 0;
/** copy & decompress dname */
rep->rrsets[i]->rk.type = htons(pset->type);
rep->rrsets[i]->rk.rrset_class = pset->rrset_class;
/** read data part. */
- if(!parse_create_rrset(pkt, pset, &data))
+ if(!parse_create_rrset(pkt, pset, &data, region))
return 0;
rep->rrsets[i]->entry.data = (void*)data;
rep->rrsets[i]->entry.key = (void*)rep->rrsets[i];
return 1;
}
-/** allocate and decompress message and rrsets, returns 0 if failed. */
-static int
+int
parse_create_msg(ldns_buffer* pkt, struct msg_parse* msg,
struct alloc_cache* alloc, struct query_info* qinf,
- struct reply_info** rep)
+ struct reply_info** rep, struct region* region)
{
log_assert(pkt && msg);
- if(!parse_create_qinfo(pkt, msg, qinf))
+ if(!parse_create_qinfo(pkt, msg, qinf, region))
return 0;
- if(!parse_create_repinfo(msg, rep))
+ if(!parse_create_repinfo(msg, rep, region))
return 0;
- if(!parse_alloc_rrset_keys(msg, *rep, alloc))
+ if(!parse_alloc_rrset_keys(msg, *rep, alloc, region))
return 0;
- if(!parse_copy_decompress(pkt, msg, *rep))
+ if(!parse_copy_decompress(pkt, msg, *rep, region))
return 0;
return 1;
}
/* parse OK, allocate return structures */
/* this also performs dname decompression */
- if(!parse_create_msg(pkt, msg, alloc, qinf, rep)) {
+ if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) {
query_info_clear(qinf);
reply_info_parsedelete(*rep, alloc);
*rep = NULL;
struct iovec;
struct region;
struct edns_data;
+struct msg_parse;
/**
* Structure to store query information that makes answers to queries
struct query_info* qinf, struct reply_info** rep,
struct region* region, struct edns_data* edns);
+/**
+ * Allocate and decompress parsed message and rrsets.
+ * @param pkt: for name decompression.
+ * @param msg: parsed message in scratch region.
+ * @param alloc: alloc cache for special rrset key structures.
+ * Not used if region!=NULL, it can be NULL in that case.
+ * @param qinf: where to store query info.
+ * qinf itself is allocated by the caller.
+ * @param rep: reply info is allocated and returned.
+ * @param region: if this parameter is NULL then malloc and the alloc is used.
+ * otherwise, everything is allocated in this region.
+ * In a region, no special rrset key structures are needed (not shared),
+ * and no rrset_ref array in the reply is built up.
+ * @return 0 if allocation failed.
+ */
+int parse_create_msg(ldns_buffer* pkt, struct msg_parse* msg,
+ struct alloc_cache* alloc, struct query_info* qinf,
+ struct reply_info** rep, struct region* region);
+
/**
* Sorts the ref array.
* @param rep: reply info. rrsets must be filled in.