From: Mark Wooding Date: Sat, 31 May 2014 23:13:20 +0000 (+0100) Subject: src/: Lay the groundwork for variably-sized record structures. X-Git-Tag: make-bug.2014-07-26~35 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=commitdiff_plain;h=b5c41613ef9980fd9ce395dd85c2af10c21079be src/: Lay the groundwork for variably-sized record structures. All records in a particular answer are going to be the same size: that's not going to change. The case we're dealing with here is that we're going to want to include new information (e.g., new kinds of address families) which will make the structures larger -- and would break old binary clients. The plan is for new clients to encode a flag saying that they understand the extended structure in the type field (implicitly, through a header- file change). But all of this means that just dredging `typei->rrsz' out of the typeinfo structure isn't going to cut it any more, so we add a type hook to compute the right size, and make sure that we use it by renaming the slot containing the fixed value. Most places in the code can avoid having to call the hook by grabbing the record size from the answer structure. This involves adding an extra parameter to the postsort hook, which otherwise might not be able to determine the right size for itself. Signed-off-by: Mark Wooding --- diff --git a/src/general.c b/src/general.c index 4404b31..6ef2cb3 100644 --- a/src/general.c +++ b/src/general.c @@ -196,6 +196,9 @@ const char *adns__diag_domain(adns_state ads, int serv, adns_query qu, return vb->buf; } +int adns__getrrsz_default(const typeinfo *typei, adns_rrtype type) + { return typei->fixed_rrsz; } + adns_status adns_rr_info(adns_rrtype type, const char **rrtname_r, const char **fmtname_r, int *len_r, @@ -209,7 +212,7 @@ adns_status adns_rr_info(adns_rrtype type, if (rrtname_r) *rrtname_r= typei->rrtname; if (fmtname_r) *fmtname_r= typei->fmtname; - if (len_r) *len_r= typei->rrsz; + if (len_r) *len_r= typei->getrrsz(typei, type); if (!datap) return adns_s_ok; diff --git a/src/internal.h b/src/internal.h index 29f4dd2..7ad6daa 100644 --- a/src/internal.h +++ b/src/internal.h @@ -148,7 +148,7 @@ typedef struct typeinfo { adns_rrtype typekey; const char *rrtname; const char *fmtname; - int rrsz; + int fixed_rrsz; void (*makefinal)(adns_query qu, void *data); /* Change memory management of *data. @@ -166,7 +166,7 @@ typedef struct typeinfo { /* Parse one RR, in dgram of length dglen, starting at cbyte and * extending until at most max. * - * The RR should be stored at *store_r, of length qu->typei->rrsz. + * The RR should be stored at *store_r, of length qu->typei->getrrsz(). * * If there is an overrun which might indicate truncation, it should set * *rdstart to -1; otherwise it may set it to anything else positive. @@ -191,12 +191,17 @@ typedef struct typeinfo { * because lablen is zero. */ - void (*postsort)(adns_state ads, void *array, int nrrs, + void (*postsort)(adns_state ads, void *array, int nrrs,int rrsz, const struct typeinfo *typei); /* Called immediately after the RRs have been sorted, and may rearrange * them. (This is really for the benefit of SRV's bizarre weighting * stuff.) May be 0 to mean nothing needs to be done. */ + + int (*getrrsz)(const struct typeinfo *typei, adns_rrtype type); + /* Return the output resource-record element size; if this is null, then + * the rrsz member can be used. + */ } typeinfo; adns_status adns__ckl_hostname(adns_state ads, adns_queryflags flags, @@ -405,6 +410,11 @@ const char *adns__diag_domain(adns_state ads, int serv, adns_query qu, * vb before using the return value. */ +int adns__getrrsz_default(const typeinfo *typei, adns_rrtype type); +/* Default function for the `getrrsz' type hook; returns the `fixed_rrsz' + * value from the typeinfo entry. + */ + void adns__isort(void *array, int nobjs, int sz, void *tempbuf, int (*needswap)(void *context, const void *a, const void *b), void *context); diff --git a/src/query.c b/src/query.c index 541d8ac..717cac0 100644 --- a/src/query.c +++ b/src/query.c @@ -83,7 +83,7 @@ static adns_query query_alloc(adns_state ads, qu->answer->expires= -1; qu->answer->nrrs= 0; qu->answer->rrs.untyped= 0; - qu->answer->rrsz= typei->rrsz; + qu->answer->rrsz= typei->getrrsz(typei,type); return qu; } @@ -580,7 +580,7 @@ void adns__query_done(adns_query qu) { } if (ans->nrrs && qu->typei->diff_needswap) { - if (!adns__vbuf_ensure(&qu->vb,qu->typei->rrsz)) { + if (!adns__vbuf_ensure(&qu->vb,qu->answer->rrsz)) { adns__query_fail(qu,adns_s_nomemory); return; } @@ -591,7 +591,8 @@ void adns__query_done(adns_query qu) { qu->ads); } if (ans->nrrs && qu->typei->postsort) { - qu->typei->postsort(qu->ads, ans->rrs.bytes, ans->nrrs, qu->typei); + qu->typei->postsort(qu->ads, ans->rrs.bytes, + ans->nrrs,ans->rrsz, qu->typei); } ans->expires= qu->expires; diff --git a/src/reply.c b/src/reply.c index 62384ab..08d274f 100644 --- a/src/reply.c +++ b/src/reply.c @@ -311,7 +311,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, /* Now, we have some RRs which we wanted. */ - qu->answer->rrs.untyped= adns__alloc_interim(qu,qu->typei->rrsz*wantedrrs); + qu->answer->rrs.untyped= adns__alloc_interim(qu,qu->answer->rrsz*wantedrrs); if (!qu->answer->rrs.untyped) { adns__query_fail(qu,adns_s_nomemory); return; @@ -341,7 +341,8 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, !ownermatched) continue; adns__update_expires(qu,ttl,now); - st= typei->parse(&pai, rdstart,rdstart+rdlength, rrsdata+nrrs*typei->rrsz); + st= typei->parse(&pai, rdstart,rdstart+rdlength, + rrsdata+nrrs*qu->answer->rrsz); if (st) { adns__query_fail(qu,st); return; } if (rdstart==-1) goto x_truncated; nrrs++; diff --git a/src/types.c b/src/types.c index 90413a0..f4a2539 100644 --- a/src/types.c +++ b/src/types.c @@ -1100,12 +1100,12 @@ static adns_status cs_srvha(vbuf *vb, const void *datap) { return csp_hostaddr(vb,&rrp->ha); } -static void postsort_srv(adns_state ads, void *array, int nrrs, +static void postsort_srv(adns_state ads, void *array, int nrrs,int rrsz, const struct typeinfo *typei) { /* we treat everything in the array as if it were an adns_rr_srvha * even though the array might be of adns_rr_srvraw. That's OK * because they have the same prefix, which is all we access. - * We use typei->rrsz, too, rather than naive array indexing, of course. + * We use rrsz, too, rather than naive array indexing, of course. */ char *workbegin, *workend, *search, *arrayend; const adns_rr_srvha *rr; @@ -1113,14 +1113,15 @@ static void postsort_srv(adns_state ads, void *array, int nrrs, int cpriority, totalweight, runtotal; long randval; - for (workbegin= array, arrayend= workbegin + typei->rrsz * nrrs; + assert(rrsz <= sizeof(rrtmp)); + for (workbegin= array, arrayend= workbegin + rrsz * nrrs; workbegin < arrayend; workbegin= workend) { cpriority= (rr=(void*)workbegin)->priority; for (workend= workbegin, totalweight= 0; workend < arrayend && (rr=(void*)workend)->priority == cpriority; - workend += typei->rrsz) { + workend += rrsz) { totalweight += rr->weight; } @@ -1131,8 +1132,8 @@ static void postsort_srv(adns_state ads, void *array, int nrrs, * workbegin (swapping with the one that was there, and then * advance workbegin. */ for (; - workbegin + typei->rrsz < workend; /* don't bother if just one */ - workbegin += typei->rrsz) { + workbegin + rrsz < workend; /* don't bother if just one */ + workbegin += rrsz) { randval= nrand48(ads->rand48xsubi); randval %= (totalweight + 1); @@ -1144,13 +1145,13 @@ static void postsort_srv(adns_state ads, void *array, int nrrs, for (search=workbegin, runtotal=0; (runtotal += (rr=(void*)search)->weight) < randval; - search += typei->rrsz); + search += rrsz); assert(search < arrayend); totalweight -= rr->weight; if (search != workbegin) { - memcpy(&rrtmp, workbegin, typei->rrsz); - memcpy(workbegin, search, typei->rrsz); - memcpy(search, &rrtmp, typei->rrsz); + memcpy(&rrtmp, workbegin, rrsz); + memcpy(workbegin, search, rrsz); + memcpy(search, &rrtmp, rrsz); } } } @@ -1226,11 +1227,11 @@ static void mf_flat(adns_query qu, void *data) { } #define DEEP_TYPE(code,rrt,fmt,memb,parser,comparer,/*printer*/...) \ { adns_r_##code&adns_rrt_reprmask, rrt,fmt,TYPESZ_M(memb), mf_##memb, \ GLUE(cs_, CAR(__VA_ARGS__)),pa_##parser,di_##comparer, \ - adns__ckl_hostname, CDR(__VA_ARGS__) } + adns__ckl_hostname, 0, adns__getrrsz_default, CDR(__VA_ARGS__) } #define FLAT_TYPE(code,rrt,fmt,memb,parser,comparer,/*printer*/...) \ { adns_r_##code&adns_rrt_reprmask, rrt,fmt,TYPESZ_M(memb), mf_flat, \ GLUE(cs_, CAR(__VA_ARGS__)),pa_##parser,di_##comparer, \ - adns__ckl_hostname, CDR(__VA_ARGS__) } + adns__ckl_hostname, 0, adns__getrrsz_default, CDR(__VA_ARGS__) } #define di_0 0