- if (qu->nextudpserver != -1) {
- if (qu->udpretries >= UDPMAXRETRIES) {
- DLIST_UNLINK(ads->tosend,qu);
- query_fail(ads,qu,adns_s_notresponding);
- return;
- }
- serv= qu->nextudpserver;
- memset(&servaddr,0,sizeof(servaddr));
- servaddr.sin_family= AF_INET;
- servaddr.sin_addr= ads->servers[serv].addr;
- servaddr.sin_port= htons(53);
- r= sendto(ads->udpsocket,qu->querymsg,qu->querylen,0,&servaddr,sizeof(servaddr));
- if (r<0 && errno == EMSGSIZE) {
- qu->nextudpserver= -1;
- } else {
- if (r<0) {
- diag("sendto %s failed: %s",inet_ntoa(servaddr.sin_addr),strerror(errno));
- }
- DLIST_UNLINK(ads->tosend,qu);
- timevaladd(&now,UDPRETRYMS);
- qu->timeout= now;
- qu->sentudp |= (1<<serv);
- qu->nextudpserver= (serv+1)%ads->nservers;
- qu->udpretries++;
- DLIST_LINKTAIL(ads->timew,qu);
- return;
- }
+ typei= adns__findtype(type);
+ if (!typei) return adns_s_notimplemented;
+
+ ctx.ext= context;
+ r= gettimeofday(&now,0); if (r) return errno;
+ id= 0;
+
+ adns__vbuf_init(&vb);
+
+ ol= strlen(owner);
+ if (ol<=1 || ol>DNS_MAXDOMAIN+1) { stat= adns_s_domaintoolong; goto xit; }
+
+ if (owner[ol-1]=='.' && owner[ol-2]!='\\') { flags &= ~adns_qf_search; ol--; }
+
+ stat= adns__mkquery(ads,&vb,&id, owner,ol, typei,flags);
+
+ xit:
+ return adns__internal_submit(ads,query_r, typei,&vb,id, flags,now, stat,&ctx);
+}
+
+int adns_synchronous(adns_state ads,
+ const char *owner,
+ adns_rrtype type,
+ adns_queryflags flags,
+ adns_answer **answer_r) {
+ adns_query qu;
+ int r;
+
+ r= adns_submit(ads,owner,type,flags,0,&qu);
+ if (r) return r;
+
+ r= adns_wait(ads,&qu,answer_r,0);
+ if (r) adns_cancel(qu);
+
+ return r;
+}
+
+static void *alloc_common(adns_query qu, size_t sz) {
+ allocnode *an;
+
+ if (!sz) return qu; /* Any old pointer will do */
+ assert(!qu->final_allocspace);
+ an= malloc(MEM_ROUND(MEM_ROUND(sizeof(*an)) + sz));
+ if (!an) return 0;
+ an->next= qu->allocations;
+ qu->allocations= an;
+ return (byte*)an + MEM_ROUND(sizeof(*an));
+}
+
+void *adns__alloc_interim(adns_query qu, size_t sz) {
+ sz= MEM_ROUND(sz);
+ qu->interim_allocd += sz;
+ return alloc_common(qu,sz);
+}
+
+void *adns__alloc_mine(adns_query qu, size_t sz) {
+ return alloc_common(qu,MEM_ROUND(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
+ * bit.
+ */
+ void *rp;
+
+ sz= MEM_ROUND(sz);
+ rp= qu->final_allocspace;
+ assert(rp);
+ qu->interim_allocd -= sz;
+ assert(qu->interim_allocd>=0);
+ qu->final_allocspace= (byte*)rp + sz;
+ return rp;
+}
+
+void adns__reset_cnameonly(adns_query qu) {
+ /* fixme: cancel children */
+ assert(!qu->final_allocspace);
+ qu->answer->nrrs= 0;
+ qu->answer->rrs= 0;
+ qu->interim_allocd= qu->answer->cname ? MEM_ROUND(strlen(qu->answer->cname)+1) : 0;
+}
+
+static void free_query_allocs(adns_query qu) {
+ allocnode *an, *ann;
+ adns_query cqu, ncqu;
+
+ for (cqu= qu->children.head; cqu; cqu= ncqu) {
+ ncqu= cqu->siblings.next;
+ adns_cancel(cqu);