From 8e5b0abb4e5416f4bd244500d9ba8dd45788093e Mon Sep 17 00:00:00 2001 From: ian Date: Sun, 8 Nov 1998 00:58:51 +0000 Subject: [PATCH] New memory management arrangements pretty much finished, but probably still will not compile. --- src/adns.h | 4 +- src/event.c | 2 +- src/internal.h | 119 ++++++++++++++++++++++++++++++++++++++----------- src/query.c | 47 +++++++++++-------- src/reply.c | 30 +++++-------- src/submit.c | 119 +++++++++++++++++++++++++++++++++---------------- 6 files changed, 217 insertions(+), 104 deletions(-) diff --git a/src/adns.h b/src/adns.h index f71230a..ea4c680 100644 --- a/src/adns.h +++ b/src/adns.h @@ -146,8 +146,10 @@ typedef struct { adns_status status; char *cname; /* always NULL if query was for CNAME records */ adns_rrtype type; - int nrrs; + int nrrs, rrsz; union { + void *untyped; + unsigned char *bytes; char *(*str); /* ns_raw, cname, ptr, ptr_raw, txt, _mf */ struct in_addr *inaddr; /* a */ adns_rr_dmaddr *dmaddr; /* ns */ diff --git a/src/event.c b/src/event.c index 453567d..cd76707 100644 --- a/src/event.c +++ b/src/event.c @@ -346,7 +346,7 @@ static int internal_check(adns_state ads, if (qu->id>=0) return EWOULDBLOCK; } LIST_UNLINK(ads->output,qu); -#error copy answer *answer= (adns_answer*)qu->ans.buf; + *answer= qu->answer; if (context_r) *context_r= qu->context.ext; free(qu); return 0; diff --git a/src/internal.h b/src/internal.h index 1eecc60..b121c9f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -61,7 +61,8 @@ typedef union { typedef struct { adns_rrtype type; int rrsz; - adns_status (*parse)(adns_state ads, adns_query qu, int serv, vbuf *vb, + + adns_status (*parse)(adns_state ads, adns_query qu, int serv, const byte *dgram, int dglen, int cbyte, int max, void *store_r); /* Parse one RR, in dgram of length dglen, starting at cbyte and @@ -71,27 +72,54 @@ typedef struct { * * If there is an overrun which might indicate truncation, it should set * *rdstart to -1; otherwise it may set it to anything else positive. - * - * This function may use vb (which has been initialised) however it likes. + */ + + void (*makefinal)(adns_state ads, adns_query qu, void *data); + /* Change memory management of *data. + * Previously, used alloc_interim, now use alloc_final. */ } typeinfo; +typedef struct allocnode { + struct allocnode *next; +} allocnode; + +union maxalign { + byte d[1]; + struct in_addr ia; + long l; + void *p; + void (*fp)(void); + union maxalign *up; +} data; + struct adns__query { - /* FIXME: make sure this is all init'd properly */ enum { query_udp, query_tcpwait, query_tcpsent, query_child, query_done } state; adns_query back, next, parent; struct { adns_query head, tail; } children; struct { adns_query back, next; } siblings; + struct allocnode *allocations; + int interim_alloced, final_used; const typeinfo *typei; + char *query_dgram; + int query_dglen; -#error make sure all this is init'd properly -#error make sure all this is freed properly - byte *querymsg; - int querylen; + vbuf vb; + /* General-purpose messing-about buffer. + * Wherever a `big' interface is crossed, this may be corrupted/changed + * unless otherwise specified. + */ + + adns_answer *answer; + /* This is allocated when a query is submitted, to avoid being unable + * to relate errors to queries if we run out of memory. During + * query processing status, rrs is 0. cname is set if + * we found a cname (this corresponds to cname_dgram in the query + * structure). type is set from the word go. nrrs and rrs + * are set together, when we find how many rrs there are. + */ - vbuf ansbuf; /* Used for answer RRs */ - char *cname_str; byte *cname_dgram; int cname_dglen, cname_begin; @@ -100,22 +128,20 @@ struct adns__query { unsigned long udpsent, tcpfailed; /* bitmap indexed by server */ struct timeval timeout; qcontext context; - char owner[1]; - /* After the owner name and nul comes the query message, pointed to by querymsg */ /* Possible states: * - * state Queue child id ansbuf nextudpserver sentudp failedtcp - * - * udp NONE null >=0 null 0 zero zero - * udp timew null >=0 null any nonzero zero - * udp NONE null >=0 null any nonzero zero - * - * tcpwait timew null >=0 null irrelevant zero any - * tcpsent timew null >=0 null irrelevant zero any - * - * child childw set >=0 partial irrelevant irrelevant irrelevant - * done output null -1 set/null irrelevant irrelevant irrelevant + * state Queue child id nextudpserver sentudp failedtcp + * + * udp NONE null >=0 0 zero zero + * udp timew null >=0 any nonzero zero + * udp NONE null >=0 any nonzero zero + * + * tcpwait timew null >=0 irrelevant zero any + * tcpsent timew null >=0 irrelevant zero any + * + * child childw set >=0 irrelevant irrelevant irrelevant + * done output null -1 irrelevant irrelevant irrelevant * * +------------------------+ * START -----> | udp/NONE | @@ -161,7 +187,7 @@ struct adns__state { FILE *diagfile; struct { adns_query head, tail; } timew, childw, output; int nextid, udpsocket, tcpsocket; - vbuf rqbuf, tcpsend, tcprecv; + vbuf tcpsend, tcprecv; int nservers, tcpserver; enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate; struct timeval tcptimeout; @@ -188,14 +214,46 @@ int adns__vbuf_append(vbuf *vb, const byte *data, int len); /* 1=>success, 0=>realloc failed */ void adns__vbuf_appendq(vbuf *vb, const byte *data, int len); void adns__vbuf_init(vbuf *vb); +void adns__vbuf_free(vbuf *vb); int adns__setnonblock(adns_state ads, int fd); /* => errno value */ /* From submit.c: */ -void adns__query_nomem(adns_state ads, adns_query qu); -void adns__query_finish(adns_state ads, adns_query qu, adns_status stat); -void adns__query_fail(adns_state ads, adns_query qu, adns_status stat); +int adns__internal_submit(adns_state ads, adns_query *query_r, + adns_rrtype type, char *query_dgram, int query_len, + adns_queryflags flags, struct timeval now, + adns_status failstat, const qcontext *ctx); +/* Submits a query (for internal use, called during external submits). + * + * The new query is returned in *query_r, or we return adns_s_nomemory. + * + * The query datagram should already have been assembled; memory for it + * is taken over by this routine whether it succeeds or fails. + * + * If failstat is nonzero then if we are successful in creating the query + * it is immediately failed with code failstat (but _submit still succeds). + * + * ctx is copied byte-for-byte into the query. + */ + +void *adns__alloc_interim(adns_query qu, size_t sz); +/* Allocates some memory, and records which query it came from + * and how much there was. + * + * If an error occurs in the query, all its memory is simply freed. + * + * If the query succeeds, one large buffer will be made which is + * big enough for all these allocations, and then adns__alloc_final + * will get memory from this buffer. + * + * _alloc_interim can fail, in which case it will fail the query too, + * so nothing more need be done with it. + */ + +void *adns__alloc_final(adns_query qu, size_t sz); +/* Cannot fail. + */ /* From query.c: */ @@ -204,6 +262,9 @@ void adns__query_tcp(adns_state ads, adns_query qu, struct timeval now); adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id, const typeinfo *typei, adns_queryflags flags); +void adns__query_ok(adns_state ads, adns_query qu); +void adns__query_fail(adns_state ads, adns_query qu, adns_status stat); + /* From reply.c: */ void adns__procdgram(adns_state ads, const byte *dgram, int len, @@ -326,6 +387,10 @@ static inline int ctype_alpha(int c) { /* Useful macros */ +#define MEM_ROUND(sz) \ + (( ((sz)+sizeof(union maxalign)-1) / sizeof(union maxalign) ) \ + * sizeof(union maxalign) ) + #define LIST_INIT(list) ((list).head= (list).tail= 0) #define LIST_UNLINK_PART(list,node,part) \ diff --git a/src/query.c b/src/query.c index d3139dd..ddd5064 100644 --- a/src/query.c +++ b/src/query.c @@ -177,28 +177,39 @@ void adns__query_udp(adns_state ads, adns_query qu, struct timeval now) { LIST_LINK_TAIL(ads->timew,qu); } -void adns__query_finish(adns_state ads, adns_query qu, adns_status stat) { +static void adns__query_done(adns_state ads, adns_query qu) { adns_answer *ans; - byte *newbuf; - - newbuf= realloc(qu->ans.buf,qu->ans.used); - if (newbuf) qu->ans.buf= newbuf; - ans= (adns_answer*)qu->ans.buf; - ans->status= stat; - ans->cname= qu->cnameoff<0 ? 0 : qu->ans.buf + qu->cnameoff; - ans->rrs.str= qu->rrsoff<0 ? 0 : (char **)(qu->ans.buf + qu->rrsoff); + allocnode *an, *ann; + + qu->answer= ans= realloc(qu->answer, + MEM_ROUND(MEM_ROUND(sizeof(*ans)) + + qu->interim_allocd)); + qu->final_used= MEM_ROUND(sizeof(*ans)); + + adns__makefinal_str(qu,&ans->cname); + if (ans->nrrs) { + adns__makefinal_block(qu,&ans->rrs.untyped,ans->rrsz*ans->nrrs); + for (i=0; inrrs; i++) + qu->typei->makefinal(ads,qu,ans->rrs.bytes+ans->rrsz*i); + } + + for (an= qu->allocations; an; an= ann) { ann= an->next; free(an); } + + adns__vbuf_free(&qu->vb); + qu->id= -1; LIST_LINK_TAIL(ads->output,qu); } -void adns__query_fail(adns_state ads, adns_query qu, adns_status stat) { - adns_answer *ans; - - qu->ans.used= sizeof(adns_answer); - qu->cnameoff= -1; - qu->rrsoff= -1; - ans= (adns_answer*)qu->ans.buf; - ans->nrrs= 0; +void adns__reset_cnameonly(adns_state ads, adns_query qu) { + qu->answer->nrrs= 0; + qu->answer->rrs= 0; + qu->permalloclen= qu->answer->cname ? MEM_ROUND(strlen(qu->answer->cname)+1) : 0; +} - adns__query_finish(ads,qu,stat); +void adns__query_fail(adns_state ads, adns_query qu, adns_status stat) { + adns__reset_cnameonly(ads,qu); + qu->answer->status= stat; + qu->answer->type= qu->type; + adns__query_done(ads,qu,stat); } diff --git a/src/reply.c b/src/reply.c index 0bcc3fa..198218e 100644 --- a/src/reply.c +++ b/src/reply.c @@ -16,8 +16,6 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, adns_query qu, nqu; dns_rcode rcode; adns_status st; - vbuf vb; -#error init and free vb properly if (dgleniflags & adns_if_debug) { adns__debug(ads,serv,qu,"ignoring RR with an unexpected owner %s", - adns__diag_domain(ads,serv,&vb,qu->flags, + adns__diag_domain(ads,serv,&qu->vb,qu->flags, dgram,dglen,rrstart,dglen)); } continue; @@ -135,11 +133,12 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, qu->cname_begin= rdstart; qu->cname_dgram= dgram; qu->cname_dglen= dglen; - st= adns__parse_domain(ads,serv,&vb,qu->flags, + st= adns__parse_domain(ads,serv,&qu->vb,qu->flags, dgram,dglen, &rdstart,rdstart+rdlength); if (!vb.used) goto x_truncated; if (st) { adns__query_fail(ads,qu,st); return; } - qu->cname_str= adns__vbuf_extractstring(&vb); + qu->answer->cname= adns__savestring(qu); + if (!qu->answer->cname) return; /* If we find the answer section truncated after this point we restart * the query at the CNAME; if beforehand then we obviously have to use * TCP. If there is no truncation we can use the whole answer if @@ -147,7 +146,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, */ } else { adns__debug(ads,serv,qu,"ignoring duplicate CNAME (%s, as well as %s)", - adns__diag_domain(ads,serv,&vb,qu->flags, + adns__diag_domain(ads,serv,&qu->vb,qu->flags, dgram,dglen, rdstart,rdstart+rdlength), qu->cname_str); } @@ -217,15 +216,11 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, /* Now, we have some RRs which we wanted. */ - if (!adns__vbuf_ensure(&qu->ansbuf,qu->typei->rrsz*wantedrrs)) { - adns__query_fail(ads,qu,adns_s_nolocalmem); - return; - } + qu->ans->rrs= adns__alloc_interim(qu,qu->typei->rrsz*wantedrrs); + if (!qu->ans->rrs) return; cbyte= anstart; - currentrrs= 0; arstart= -1; - qu->ansbuf.used= 0; for (rri=0; rricname_dgram >= 0) { st= adns__findrr(ads,serv, dgram,dglen,&cbyte, @@ -241,11 +236,10 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, rrtype != (qu->typei->type & adns__rrt_typemask) || !ownermatched) continue; - assert(currentrrsansbuf.used += quj->typei->rrsz; - st= qu->typei->parse(ads,qu,serv,&vb, + assert(qu->ans->nrrstypei->parse(ads,qu,serv, dgram,dglen, &rdstart,rdstart+rdlength, - (void*)(qu->ansbuf.buf+qu->ansbuf.used)); + qu->ans->rrs.bytes+qu->ans->nrrs*quj->typei->rrsz); if (st) { adns__query_fail(ads,qu,st); return; } if (rdstart==-1) goto x_truncated; } @@ -267,9 +261,7 @@ x_truncated: return; } if (qu->cname_dgram) { cname_recurse(ads,qu,adns_qf_usevc); return; } - ans= (adns_answer*)qu->ans.buf; - ans->nrrs= 0; - qu->ans.used= sizeof(adns_answer); + adns__reset_cnameonly(ads,qu); qu->flags |= adns_qf_usevc; adns__query_udp(ads,qu,now); } diff --git a/src/submit.c b/src/submit.c index bd214b1..ee73b37 100644 --- a/src/submit.c +++ b/src/submit.c @@ -8,21 +8,50 @@ #include "internal.h" -static adns_query allocquery(adns_state ads, const char *owner, int ol, - int id, const typeinfo *typei, - adns_queryflags flags, const qcontext *ctx) { - /* Query message used is the one assembled in ads->rqbuf */ +int adns__internal_submit(adns_state ads, adns_query *query_r, + adns_rrtype type, char *query_dgram, int query_len, + adns_queryflags flags, struct timeval now, + adns_status failstat, const qcontext *ctx) { + /* Submits a query (for internal use, called during external submits). + * + * The new query is returned in *query_r, or we return adns_s_nomemory. + * + * The query datagram should already have been assembled; memory for it + * is taken over by this routine whether it succeeds or fails. + * + * If failstat is nonzero then if we are successful in creating the query + * it is immediately failed with code failstat (but _submit still succeds). + * + * ctx is copied byte-for-byte into the query. + */ + adns_query qu; + adns_status stat; + int ol, id, r; + struct timeval now; + const typeinfo *typei; adns_query qu; - adns_answer *ans; - qu= malloc(sizeof(*qu)+ol+1+ads->rqbuf.used); if (!qu) return 0; - adns__vbuf_init(&qu->ansbuf); - qu->cname= 0; + id= ads->nextid++; + + qu= malloc(sizeof(*qu)); if (!qu) goto x_nomemory; + qu->answer= malloc(sizeof(*qu->answer)); if (!qu->answer) goto x_freequ_nomemory; + qu->state= query_udp; - qu->next= qu->back= qu->parent= 0; + qu->back= qu->next= qu->parent= 0; LIST_INIT(qu->children); qu->siblings.next= qu->siblings.back= 0; - qu->typei= typei; + qu->allocations= 0; + qu->interim_allocd= 0; + qu->perm_used= 0; + + qu->typei= adns__findtype(type); + qu->query_dgram= query_dgram; + qu->query_dglen= query_dglen; + adns__vbuf_init(&qu->vb); + + qu->cname_dgram= 0; + qu->cname_dglen= qu->cname_begin= 0; + qu->id= id; qu->flags= flags; qu->udpretries= 0; @@ -31,22 +60,36 @@ static adns_query allocquery(adns_state ads, const char *owner, int ol, timerclear(&qu->timeout); memcpy(&qu->context,ctx,sizeof(qu->context)); memcpy(qu->owner,owner,ol); qu->owner[ol]= 0; - qu->querymsg= qu->owner+ol+1; - memcpy(qu->owner+ol+1,ads->rqbuf.buf,ads->rqbuf.used); - qu->querylen= ads->rqbuf.used; - - return qu; -} -static int failsubmit(adns_state ads, const qcontext *ctx, adns_query *query_r, - adns_queryflags flags, int id, adns_status stat) { - adns_query qu; + qu->answer->status= adns_s_ok; + qu->answer->cname= 0; + qu->answer->type= type; + qu->answer->nrrs= 0; + qu->answer->rrs= 0; - ads->rqbuf.used= 0; - qu= allocquery(ads,0,0,id,0,flags,ctx); if (!qu) return errno; - adns__query_fail(ads,qu,stat); *query_r= qu; + + if (qu->typei) { + qu->answer->rrsz= qu->rrsz; + } else { + qu->answer->rrsz= -1; + failstat= adns_s_notimplemented; + } + if (failstat) { + adns__query_fail(ads,qu,failstat); + return; + } + + adns__query_udp(ads,qu,now); + adns__autosys(ads,now); + return 0; + + x_freequ_nomemory: + free(qu); + x_nomemory: + free(query_dgram); + return adns_s_nomemory; } int adns_submit(adns_state ads, @@ -55,21 +98,11 @@ int adns_submit(adns_state ads, adns_queryflags flags, void *context, adns_query *query_r) { - adns_query qu; - adns_status stat; - int ol, id, r; qcontext ctx; - struct timeval now; - const typeinfo *typei; ctx.ext= context; - id= ads->nextid++; - r= gettimeofday(&now,0); if (r) return errno; - typei= adns__findtype(type); - if (!typei) return failsubmit(ads,context,query_r,flags,id,adns_s_notimplemented); - ol= strlen(owner); if (ol<=1 || ol>DNS_MAXDOMAIN+1) return failsubmit(ads,context,query_r,flags,id,adns_s_invaliddomain); @@ -78,12 +111,7 @@ int adns_submit(adns_state ads, stat= adns__mkquery(ads,owner,ol,id,typei,flags); if (stat) return failsubmit(ads,context,query_r,flags,id,stat); - qu= allocquery(ads,owner,ol,id,typei,flags,&ctx); if (!qu) return errno; - adns__query_udp(ads,qu,now); - adns__autosys(ads,now); - - *query_r= qu; - return 0; + adns__internal_submit(ads,type,flags,now,query_r } int adns_synchronous(adns_state ads, @@ -107,3 +135,18 @@ int adns_synchronous(adns_state ads, void adns_cancel(adns_state ads, adns_query query) { abort(); /* fixme */ } + +void *adns__alloc_interim(adns_state ads, adns_query qu, size_t sz) { + allocnode *an; + + sz= MEM_ROUND(sz); + an= malloc(MEM_ROUND(MEM_ROUND(sizeof(*an)) + sz)); + if (!an) { + adns__query_fail(ads,qu,adns_s_nolocalmem); + return 0; + } + qu->permalloclen += sz; + an->next= qu->allocations; + qu->allocations= an; + return (byte*)an + MEM_ROUND(sizeof(*an)); +} -- 2.30.2