struct sockaddr sa;
struct sockaddr_in inet;
} addr;
-} adns_addr;
+} adns_rr_addr;
typedef struct {
char *host;
adns_status astatus;
int naddrs; /* temp fail => -1, perm fail => 0, s_ok => >0 */
- adns_addr *addrs;
+ adns_rr_addr *addrs;
} adns_rr_hostaddr;
typedef struct {
unsigned char *bytes;
char *(*str); /* ns_raw, cname, ptr, ptr_raw */
adns_rr_intstr *(*manyistr); /* txt (list of strings ends with i=-1, str=0) */
- adns_addr *addr; /* addr */
+ adns_rr_addr *addr; /* addr */
struct in_addr *inaddr; /* a */
adns_rr_hostaddr *hostaddr; /* ns */
adns_rr_strpair *strpair; /* hinfo ??fixme, rp, rp_raw */
typedef union {
void *ext;
- adns_rr_hostaddr *hostaddr;
+ struct {
+ void (*callback)(adns_query parent, adns_query child);
+ union {
+ adns_rr_hostaddr *hostaddr;
+ } info;
+ } intern;
} qcontext;
typedef struct {
} typeinfo;
typedef struct allocnode {
- struct allocnode *next;
+ struct allocnode *next, *back;
} allocnode;
union maxalign {
adns_query back, next, parent;
struct { adns_query head, tail; } children;
struct { adns_query back, next; } siblings;
- struct allocnode *allocations;
+ struct { allocnode *head, *tail; } allocations;
int interim_allocd;
void *final_allocspace;
* but it will not necessarily return a distinct pointer each time.
*/
+void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t sz);
+/* Transfers an interim allocation from one query to another, so that
+ * the `to' query will have room for the data when we get to makefinal
+ * and so that the free will happen when the `to' query is freed
+ * rather than the `from' query.
+ *
+ * It is legal to call adns__transfer_interim with a null pointer; this
+ * has no effect.
+ */
+
void *adns__alloc_mine(adns_query qu, size_t sz);
/* Like _interim, but does not record the length for later
* copying into the answer. This just ensures that the memory
#define LIST_UNLINK_PART(list,node,part) \
do { \
- if ((node)->back) (node)->back->part next= (node)->part next; \
- else (list).head= (node)->part next; \
- if ((node)->next) (node)->next->part back= (node)->part back; \
- else (list).tail= (node)->part back; \
+ if ((node)->part back) (node)->part back->part next= (node)->part next; \
+ else (list).head= (node)->part next; \
+ if ((node)->part next) (node)->part next->part back= (node)->part back; \
+ else (list).tail= (node)->part back; \
} while(0)
#define LIST_LINK_TAIL_PART(list,node,part) \
qu->back= qu->next= qu->parent= 0;
LIST_INIT(qu->children);
qu->siblings.next= qu->siblings.back= 0;
- qu->allocations= 0;
+ LIST_INIT(qu->allocations);
qu->interim_allocd= 0;
qu->final_allocspace= 0;
assert(!qu->final_allocspace);
an= malloc(MEM_ROUND(MEM_ROUND(sizeof(*an)) + sz));
if (!an) return 0;
- an->next= qu->allocations;
- qu->allocations= an;
+ LIST_LINK_TAIL(qu->allocations,an);
return (byte*)an + MEM_ROUND(sizeof(*an));
}
return alloc_common(qu,MEM_ROUND(sz));
}
+void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t sz) {
+ allocnode *an;
+
+ if (!block) return;
+ an= (void*)((byte*)block - MEM_ROUND(sizeof(*an)));
+
+ assert(!to->final_allocspace);
+ assert(!from->final_allocspace);
+
+ LIST_UNLINK(from->allocations,an);
+ LIST_LINK_TAIL(to->allocations,an);
+
+ from->interim_allocd -= sz;
+ to->interim_allocd += sz;
+}
+
void *adns__alloc_final(adns_query qu, size_t sz) {
/* When we're in the _final stage, we _subtract_ from interim_alloc'd
* each allocation, and use final_allocspace to point to the next free
ncqu= cqu->siblings.next;
adns_cancel(cqu);
}
- for (an= qu->allocations; an; an= ann) { ann= an->next; free(an); }
+ for (an= qu->allocations.head; an; an= ann) { ann= an->next; free(an); }
adns__vbuf_free(&qu->vb);
}
free(qu->answer);
free(qu);
}
-
-void adns__query_done(adns_query qu) {
+
+static void makefinal_query(adns_query qu) {
adns_answer *ans;
int rrn;
ans= qu->answer;
-
+
if (qu->interim_allocd) {
- if (qu->answer->nrrs && qu->typei->diff_needswap) {
- if (!adns__vbuf_ensure(&qu->vb,qu->typei->rrsz)) {
- adns__query_fail(qu,adns_s_nolocalmem);
- return;
- }
- }
ans= realloc(qu->answer, MEM_ROUND(MEM_ROUND(sizeof(*ans)) + qu->interim_allocd));
- if (!ans) {
- qu->answer->cname= 0;
- adns__query_fail(qu, adns_s_nolocalmem);
- return;
- }
+ if (!ans) goto x_nomem;
qu->answer= ans;
}
for (rrn=0; rrn<ans->nrrs; rrn++)
qu->typei->makefinal(qu, ans->rrs.bytes + rrn*ans->rrsz);
-
- if (qu->typei->diff_needswap)
- adns__isort(ans->rrs.bytes, ans->nrrs, ans->rrsz,
- qu->vb.buf, qu->typei->diff_needswap);
}
-
+
free_query_allocs(qu);
+ return;
+ x_nomem:
+ qu->answer->status= adns_s_nolocalmem;
+ qu->answer->cname= 0;
+ adns__reset_cnameonly(qu);
+ free_query_allocs(qu);
+}
+
+void adns__query_done(adns_query qu) {
+ adns_answer *ans;
+ adns_query parent;
+
qu->id= -1;
- LIST_LINK_TAIL(qu->ads->output,qu);
+ ans= qu->answer;
+
+ if (ans->nrrs && qu->typei->diff_needswap) {
+ if (!adns__vbuf_ensure(&qu->vb,qu->typei->rrsz)) {
+ adns__query_fail(qu,adns_s_nolocalmem);
+ return;
+ }
+ adns__isort(ans->rrs.bytes, ans->nrrs, ans->rrsz,
+ qu->vb.buf, qu->typei->diff_needswap);
+ }
- assert(!qu->parent);
- /* fixme: do something with the answers to internally-generated queries. */
+ parent= qu->parent;
+ if (parent) {
+ LIST_UNLINK_PART(parent->children,qu,siblings.);
+ qu->context.intern.callback(parent,qu);
+ free_query_allocs(qu);
+ free(qu);
+ if (!parent->children.head) adns__query_done(parent);
+ } else {
+ makefinal_query(qu);
+ LIST_LINK_TAIL(qu->ads->output,qu);
+ }
}
void adns__query_fail(adns_query qu, adns_status stat) {
*/
static adns_status pa_addr(const parseinfo *pai, int cbyte, int max, void *datap) {
- adns_addr *storeto= datap;
+ adns_rr_addr *storeto= datap;
const byte *dgram= pai->dgram;
if (max-cbyte != 4) return adns_s_invaliddata;
}
static int di_addr(const void *datap_a, const void *datap_b) {
- const adns_addr *ap= datap_a, *bp= datap_b;
+ const adns_rr_addr *ap= datap_a, *bp= datap_b;
assert(ap->addr.sa.sa_family == AF_INET);
return dip_inaddr(ap->addr.inet.sin_addr,bp->addr.inet.sin_addr);
}
-static adns_status csp_addr(vbuf *vb, const adns_addr *rrp) {
+static adns_status csp_addr(vbuf *vb, const adns_rr_addr *rrp) {
const char *ia;
static char buf[30];
}
static adns_status cs_addr(vbuf *vb, const void *datap) {
- const adns_addr *rrp= datap;
+ const adns_rr_addr *rrp= datap;
return csp_addr(vb,rrp);
}
}
/*
- * _hostaddr (pap,pa,dip,di,mfp,mf,csp,cs +pap_findaddrs)
+ * _hostaddr (pap,pa,dip,di,mfp,mf,csp,cs +icb_hostaddr, pap_findaddrs)
*/
static adns_status pap_findaddrs(const parseinfo *pai, adns_rr_hostaddr *ha,
if (naddrs == -1) {
naddrs= 0;
}
- if (!adns__vbuf_ensure(&pai->qu->vb, (naddrs+1)*sizeof(adns_addr))) R_NOMEM;
- st= pa_addr(pai, rdstart,rdstart+rdlen, pai->qu->vb.buf + naddrs*sizeof(adns_addr));
+ if (!adns__vbuf_ensure(&pai->qu->vb, (naddrs+1)*sizeof(adns_rr_addr))) R_NOMEM;
+ st= pa_addr(pai, rdstart,rdstart+rdlen,
+ pai->qu->vb.buf + naddrs*sizeof(adns_rr_addr));
if (st) return st;
naddrs++;
}
if (naddrs >= 0) {
- ha->addrs= adns__alloc_interim(pai->qu, naddrs*sizeof(adns_addr));
+ ha->addrs= adns__alloc_interim(pai->qu, naddrs*sizeof(adns_rr_addr));
if (!ha->addrs) R_NOMEM;
- memcpy(ha->addrs, pai->qu->vb.buf, naddrs*sizeof(adns_addr));
+ memcpy(ha->addrs, pai->qu->vb.buf, naddrs*sizeof(adns_rr_addr));
ha->naddrs= naddrs;
ha->astatus= adns_s_ok;
- adns__isort(ha->addrs, naddrs, sizeof(adns_addr), pai->qu->vb.buf, di_addr);
+ adns__isort(ha->addrs, naddrs, sizeof(adns_rr_addr), pai->qu->vb.buf, di_addr);
}
return adns_s_ok;
}
+static void icb_hostaddr(adns_query parent, adns_query child) {
+ adns_rr_hostaddr *rrp= child->context.intern.info.hostaddr;
+ adns_answer *cans= child->answer;
+
+ rrp->astatus= cans->status;
+ rrp->naddrs= cans->nrrs;
+ rrp->addrs= cans->rrs.addr;
+ adns__transfer_interim(child, parent, rrp->addrs, rrp->naddrs*sizeof(adns_rr_addr));
+}
+
static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
int max, adns_rr_hostaddr *rrp) {
adns_status st;
pai->dgram, pai->dglen, dmstart,
adns_r_addr, adns_qf_quoteok_query);
if (st) return st;
-
- ctx.hostaddr= rrp;
+
+ ctx.intern.callback= icb_hostaddr;
+ ctx.intern.info.hostaddr= rrp;
st= adns__internal_submit(pai->ads, &nqu, adns__findtype(adns_r_addr),
&pai->qu->vb, id,
adns_qf_quoteok_query, pai->now, 0, &ctx);