ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

query.c
Go to the documentation of this file.
00001 /*
00002  * query.c
00003  * - overall query management (allocation, completion)
00004  * - per-query memory management
00005  * - query submission and cancellation (user-visible and internal)
00006  */
00007 /*
00008  *  This file is
00009  *    Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
00010  *
00011  *  It is part of adns, which is
00012  *    Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
00013  *    Copyright (C) 1999-2000 Tony Finch <dot@dotat.at>
00014  *
00015  *  This program is free software; you can redistribute it and/or modify
00016  *  it under the terms of the GNU General Public License as published by
00017  *  the Free Software Foundation; either version 2, or (at your option)
00018  *  any later version.
00019  *
00020  *  This program is distributed in the hope that it will be useful,
00021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  *  GNU General Public License for more details.
00024  *
00025  *  You should have received a copy of the GNU General Public License
00026  *  along with this program; if not, write to the Free Software Foundation,
00027  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00028  */
00029 
00030 #ifdef ADNS_JGAA_WIN32
00031 # include "adns_win32.h"
00032 #else
00033 # include <stdlib.h>
00034 # include <unistd.h>
00035 # include <errno.h>
00036 # include <sys/time.h>
00037 #endif
00038 
00039 #include "internal.h"
00040 
00041 static adns_query query_alloc(adns_state ads, const typeinfo *typei,
00042                   adns_queryflags flags, struct timeval now) {
00043   /* Allocate a virgin query and return it. */
00044   adns_query qu;
00045 
00046   qu= malloc(sizeof(*qu));  if (!qu) return 0;
00047   qu->answer= malloc(sizeof(*qu->answer));  if (!qu->answer) { free(qu); return 0; }
00048 
00049   qu->ads= ads;
00050   qu->state= query_tosend;
00051   qu->back= qu->next= qu->parent= 0;
00052   LIST_INIT(qu->children);
00053   LINK_INIT(qu->siblings);
00054   LIST_INIT(qu->allocations);
00055   qu->interim_allocd= 0;
00056   qu->preserved_allocd= 0;
00057   qu->final_allocspace= 0;
00058 
00059   qu->typei= typei;
00060   qu->query_dgram= 0;
00061   qu->query_dglen= 0;
00062   adns__vbuf_init(&qu->vb);
00063 
00064   qu->cname_dgram= 0;
00065   qu->cname_dglen= qu->cname_begin= 0;
00066 
00067   adns__vbuf_init(&qu->search_vb);
00068   qu->search_origlen= qu->search_pos= qu->search_doneabs= 0;
00069 
00070   qu->id= -2; /* will be overwritten with real id before we leave adns */
00071   qu->flags= flags;
00072   qu->retries= 0;
00073   qu->udpnextserver= 0;
00074   qu->udpsent= 0;
00075   timerclear(&qu->timeout);
00076   qu->expires= now.tv_sec + MAXTTLBELIEVE;
00077 
00078   memset(&qu->ctx,0,sizeof(qu->ctx));
00079 
00080   qu->answer->status= adns_s_ok;
00081   qu->answer->cname= qu->answer->owner= 0;
00082   qu->answer->type= typei->type;
00083   qu->answer->expires= -1;
00084   qu->answer->nrrs= 0;
00085   qu->answer->rrs.untyped= 0;
00086   qu->answer->rrsz= typei->rrsz;
00087 
00088   return qu;
00089 }
00090 
00091 static void query_submit(adns_state ads, adns_query qu,
00092              const typeinfo *typei, vbuf *qumsg_vb, int id,
00093              adns_queryflags flags, struct timeval now) {
00094   /* Fills in the query message in for a previously-allocated query,
00095    * and submits it.  Cannot fail.  Takes over the memory for qumsg_vb.
00096    */
00097 
00098   qu->vb= *qumsg_vb;
00099   adns__vbuf_init(qumsg_vb);
00100 
00101   qu->query_dgram= malloc( (size_t) qu->vb.used);
00102   if (!qu->query_dgram) { adns__query_fail(qu,adns_s_nomemory); return; }
00103 
00104   qu->id= id;
00105   qu->query_dglen= qu->vb.used;
00106   memcpy(qu->query_dgram,qu->vb.buf,(size_t) qu->vb.used);
00107 
00108   adns__query_send(qu,now);
00109 }
00110 
00111 adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
00112                   const typeinfo *typei, vbuf *qumsg_vb, int id,
00113                   adns_queryflags flags, struct timeval now,
00114                   const qcontext *ctx) {
00115   adns_query qu;
00116 
00117   qu= query_alloc(ads,typei,flags,now);
00118   if (!qu) { adns__vbuf_free(qumsg_vb); return adns_s_nomemory; }
00119   *query_r= qu;
00120 
00121   memcpy(&qu->ctx,ctx,(size_t) sizeof(qu->ctx));
00122   query_submit(ads,qu, typei,qumsg_vb,id,flags,now);
00123 
00124   return adns_s_ok;
00125 }
00126 
00127 static void query_simple(adns_state ads, adns_query qu,
00128              const char *owner, int ol,
00129              const typeinfo *typei, adns_queryflags flags,
00130              struct timeval now) {
00131   vbuf vb_new;
00132   int id;
00133   adns_status stat;
00134 
00135   stat= adns__mkquery(ads,&qu->vb,&id, owner,ol, typei,flags);
00136   if (stat) {
00137     if (stat == adns_s_querydomaintoolong && (flags & adns_qf_search)) {
00138       adns__search_next(ads,qu,now);
00139       return;
00140     } else {
00141       adns__query_fail(qu,stat);
00142       return;
00143     }
00144   }
00145 
00146   vb_new= qu->vb;
00147   adns__vbuf_init(&qu->vb);
00148   query_submit(ads,qu, typei,&vb_new,id, flags,now);
00149 }
00150 
00151 void adns__search_next(adns_state ads, adns_query qu, struct timeval now) {
00152   const char *nextentry;
00153   adns_status stat;
00154 
00155   if (qu->search_doneabs<0) {
00156     nextentry= 0;
00157     qu->search_doneabs= 1;
00158   } else {
00159     if (qu->search_pos >= ads->nsearchlist) {
00160       if (qu->search_doneabs) {
00161     stat= adns_s_nxdomain; goto x_fail;
00162     return;
00163       } else {
00164     nextentry= 0;
00165     qu->search_doneabs= 1;
00166       }
00167     } else {
00168       nextentry= ads->searchlist[qu->search_pos++];
00169     }
00170   }
00171 
00172   qu->search_vb.used= qu->search_origlen;
00173   if (nextentry) {
00174     if (!adns__vbuf_append(&qu->search_vb,(byte*)".",1) ||
00175     !adns__vbuf_appendstr(&qu->search_vb,nextentry)) {
00176       stat= adns_s_nomemory; goto x_fail;
00177     }
00178   }
00179 
00180   free(qu->query_dgram);
00181   qu->query_dgram= 0; qu->query_dglen= 0;
00182 
00183   query_simple(ads,qu, (char*)qu->search_vb.buf, qu->search_vb.used, qu->typei, qu->flags, now);
00184   return;
00185 
00186 x_fail:
00187   adns__query_fail(qu,stat);
00188 }
00189 
00190 static int save_owner(adns_query qu, const char *owner, int ol) {
00191   /* Returns 1 if OK, otherwise there was no memory. */
00192   adns_answer *ans;
00193 
00194   ans= qu->answer;
00195   assert(!ans->owner);
00196 
00197   ans->owner= adns__alloc_preserved(qu, (size_t) ol+1);  if (!ans->owner) return 0;
00198 
00199   memcpy(ans->owner,owner, (size_t) ol);
00200   ans->owner[ol]= 0;
00201   return 1;
00202 }
00203 
00204 int adns_submit(adns_state ads,
00205         const char *owner,
00206         adns_rrtype type,
00207         adns_queryflags flags,
00208         void *context,
00209         adns_query *query_r) {
00210   int r, ol, ndots;
00211   adns_status stat;
00212   const typeinfo *typei;
00213   struct timeval now;
00214   adns_query qu;
00215   const char *p;
00216 
00217   adns__consistency(ads,0,cc_entex);
00218 
00219   typei= adns__findtype(type);
00220   if (!typei) return ENOSYS;
00221 
00222   r= gettimeofday(&now,0); if (r) goto x_errno;
00223   qu= query_alloc(ads,typei,flags,now); if (!qu) goto x_errno;
00224 
00225   qu->ctx.ext= context;
00226   qu->ctx.callback= 0;
00227   memset(&qu->ctx.info,0,sizeof(qu->ctx.info));
00228 
00229   *query_r= qu;
00230 
00231   ol= strlen(owner);
00232   if (!ol) { stat= adns_s_querydomaininvalid; goto x_adnsfail; }
00233   if (ol>DNS_MAXDOMAIN+1) { stat= adns_s_querydomaintoolong; goto x_adnsfail; }
00234 
00235   if (ol>=1 && owner[ol-1]=='.' && (ol<2 || owner[ol-2]!='\\')) {
00236     flags &= ~adns_qf_search;
00237     qu->flags= flags;
00238     ol--;
00239   }
00240 
00241   if (flags & adns_qf_search) {
00242     r= adns__vbuf_append(&qu->search_vb,(byte*)owner,ol);
00243     if (!r) { stat= adns_s_nomemory; goto x_adnsfail; }
00244 
00245     for (ndots=0, p=owner; (p= strchr(p,'.')); p++, ndots++);
00246     qu->search_doneabs= (ndots >= ads->searchndots) ? -1 : 0;
00247     qu->search_origlen= ol;
00248     adns__search_next(ads,qu,now);
00249   } else {
00250     if (flags & adns_qf_owner) {
00251       if (!save_owner(qu,owner,ol)) { stat= adns_s_nomemory; goto x_adnsfail; }
00252     }
00253     query_simple(ads,qu, owner,ol, typei,flags, now);
00254   }
00255   adns__autosys(ads,now);
00256   adns__consistency(ads,qu,cc_entex);
00257   return 0;
00258 
00259  x_adnsfail:
00260   adns__query_fail(qu,stat);
00261   adns__consistency(ads,qu,cc_entex);
00262   return 0;
00263 
00264  x_errno:
00265   r= errno;
00266   assert(r);
00267   adns__consistency(ads,0,cc_entex);
00268   return r;
00269 }
00270 
00271 int adns_submit_reverse_any(adns_state ads,
00272                 const struct sockaddr *addr,
00273                 const char *zone,
00274                 adns_rrtype type,
00275                 adns_queryflags flags,
00276                 void *context,
00277                 adns_query *query_r) {
00278   const unsigned char *iaddr;
00279   char *buf, *buf_free;
00280   char shortbuf[100];
00281   int r, lreq;
00282 
00283   flags &= ~adns_qf_search;
00284 
00285   if (addr->sa_family != AF_INET) return ENOSYS;
00286   iaddr= (const unsigned char*) &(((const struct sockaddr_in*)addr) -> sin_addr);
00287 
00288   lreq= strlen(zone) + 4*4 + 1;
00289   if (lreq > (int)sizeof(shortbuf)) {
00290     buf= malloc( strlen(zone) + 4*4 + 1 );
00291     if (!buf) return errno;
00292     buf_free= buf;
00293   } else {
00294     buf= shortbuf;
00295     buf_free= 0;
00296   }
00297   sprintf(buf, "%d.%d.%d.%d.%s", iaddr[3], iaddr[2], iaddr[1], iaddr[0], zone);
00298 
00299   r= adns_submit(ads,buf,type,flags,context,query_r);
00300   free(buf_free);
00301   return r;
00302 }
00303 
00304 int adns_submit_reverse(adns_state ads,
00305             const struct sockaddr *addr,
00306             adns_rrtype type,
00307             adns_queryflags flags,
00308             void *context,
00309             adns_query *query_r) {
00310   if (type != adns_r_ptr && type != adns_r_ptr_raw) return EINVAL;
00311   return adns_submit_reverse_any(ads,addr,"in-addr.arpa",type,flags,context,query_r);
00312 }
00313 
00314 int adns_synchronous(adns_state ads,
00315              const char *owner,
00316              adns_rrtype type,
00317              adns_queryflags flags,
00318              adns_answer **answer_r) {
00319   adns_query qu;
00320   int r;
00321 
00322   r= adns_submit(ads,owner,type,flags,0,&qu);
00323   if (r) return r;
00324 
00325   r= adns_wait(ads,&qu,answer_r,0);
00326   if (r) adns_cancel(qu);
00327 
00328   return r;
00329 }
00330 
00331 static void *alloc_common(adns_query qu, size_t sz) {
00332   allocnode *an;
00333 
00334   if (!sz) return qu; /* Any old pointer will do */
00335   assert(!qu->final_allocspace);
00336   an= malloc(MEM_ROUND(MEM_ROUND(sizeof(*an)) + sz));
00337   if (!an) return 0;
00338   LIST_LINK_TAIL(qu->allocations,an);
00339   return (byte*)an + MEM_ROUND(sizeof(*an));
00340 }
00341 
00342 void *adns__alloc_interim(adns_query qu, size_t sz) {
00343   void *rv;
00344 
00345   sz= MEM_ROUND(sz);
00346   rv= alloc_common(qu,sz);
00347   if (!rv) return 0;
00348   qu->interim_allocd += sz;
00349   return rv;
00350 }
00351 
00352 void *adns__alloc_preserved(adns_query qu, size_t sz) {
00353   void *rv;
00354 
00355   sz= MEM_ROUND(sz);
00356   rv= adns__alloc_interim(qu,sz);
00357   if (!rv) return 0;
00358   qu->preserved_allocd += sz;
00359   return rv;
00360 }
00361 
00362 void *adns__alloc_mine(adns_query qu, size_t sz) {
00363   return alloc_common(qu,MEM_ROUND(sz));
00364 }
00365 
00366 void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t sz) {
00367   allocnode *an;
00368 
00369   if (!block) return;
00370   an= (void*)((byte*)block - MEM_ROUND(sizeof(*an)));
00371 
00372   assert(!to->final_allocspace);
00373   assert(!from->final_allocspace);
00374 
00375   LIST_UNLINK(from->allocations,an);
00376   LIST_LINK_TAIL(to->allocations,an);
00377 
00378   sz= MEM_ROUND(sz);
00379   from->interim_allocd -= sz;
00380   to->interim_allocd += sz;
00381 
00382   if (to->expires > from->expires) to->expires= from->expires;
00383 }
00384 
00385 void *adns__alloc_final(adns_query qu, size_t sz) {
00386   /* When we're in the _final stage, we _subtract_ from interim_alloc'd
00387    * each allocation, and use final_allocspace to point to the next free
00388    * bit.
00389    */
00390   void *rp;
00391 
00392   sz= MEM_ROUND(sz);
00393   rp= qu->final_allocspace;
00394   assert(rp);
00395   qu->interim_allocd -= sz;
00396   assert(qu->interim_allocd>=0);
00397   qu->final_allocspace= (byte*)rp + sz;
00398   return rp;
00399 }
00400 
00401 static void cancel_children(adns_query qu) {
00402   adns_query cqu, ncqu;
00403 
00404   for (cqu= qu->children.head; cqu; cqu= ncqu) {
00405     ncqu= cqu->siblings.next;
00406     adns_cancel(cqu);
00407   }
00408 }
00409 
00410 void adns__reset_preserved(adns_query qu) {
00411   assert(!qu->final_allocspace);
00412   cancel_children(qu);
00413   qu->answer->nrrs= 0;
00414   qu->answer->rrs.untyped= 0;
00415   qu->interim_allocd= qu->preserved_allocd;
00416 }
00417 
00418 static void free_query_allocs(adns_query qu) {
00419   allocnode *an, *ann;
00420 
00421   cancel_children(qu);
00422   for (an= qu->allocations.head; an; an= ann) { ann= an->next; free(an); }
00423   LIST_INIT(qu->allocations);
00424   adns__vbuf_free(&qu->vb);
00425   adns__vbuf_free(&qu->search_vb);
00426   free(qu->query_dgram);
00427   qu->query_dgram= 0;
00428 }
00429 
00430 void adns_cancel(adns_query qu) {
00431   adns_state ads;
00432 
00433   ads= qu->ads;
00434   adns__consistency(ads,qu,cc_entex);
00435   if (qu->parent) LIST_UNLINK_PART(qu->parent->children,qu,siblings.);
00436   switch (qu->state) {
00437   case query_tosend:
00438     LIST_UNLINK(ads->udpw,qu);
00439     break;
00440   case query_tcpw:
00441     LIST_UNLINK(ads->tcpw,qu);
00442     break;
00443   case query_childw:
00444     LIST_UNLINK(ads->childw,qu);
00445     break;
00446   case query_done:
00447     LIST_UNLINK(ads->output,qu);
00448     break;
00449   default:
00450     abort();
00451   }
00452   free_query_allocs(qu);
00453   free(qu->answer);
00454   free(qu);
00455   adns__consistency(ads,0,cc_entex);
00456 }
00457 
00458 void adns__update_expires(adns_query qu, unsigned long ttl, struct timeval now) {
00459   time_t max;
00460 
00461   assert(ttl <= MAXTTLBELIEVE);
00462   max= now.tv_sec + ttl;
00463   if (qu->expires < max) return;
00464   qu->expires= max;
00465 }
00466 
00467 static void makefinal_query(adns_query qu) {
00468   adns_answer *ans;
00469   int rrn;
00470 
00471   ans= qu->answer;
00472 
00473   if (qu->interim_allocd) {
00474     ans= realloc(qu->answer, MEM_ROUND(MEM_ROUND(sizeof(*ans)) + qu->interim_allocd));
00475     if (!ans) goto x_nomem;
00476     qu->answer= ans;
00477   }
00478 
00479   qu->final_allocspace= (byte*)ans + MEM_ROUND(sizeof(*ans));
00480   adns__makefinal_str(qu,&ans->cname);
00481   adns__makefinal_str(qu,&ans->owner);
00482 
00483   if (ans->nrrs) {
00484     adns__makefinal_block(qu, &ans->rrs.untyped, (size_t) ans->nrrs*ans->rrsz);
00485 
00486     for (rrn=0; rrn<ans->nrrs; rrn++)
00487       qu->typei->makefinal(qu, ans->rrs.bytes + rrn*ans->rrsz);
00488   }
00489 
00490   free_query_allocs(qu);
00491   return;
00492 
00493  x_nomem:
00494   qu->preserved_allocd= 0;
00495   qu->answer->cname= 0;
00496   qu->answer->owner= 0;
00497   adns__reset_preserved(qu); /* (but we just threw away the preserved stuff) */
00498 
00499   qu->answer->status= adns_s_nomemory;
00500   free_query_allocs(qu);
00501 }
00502 
00503 void adns__query_done(adns_query qu) {
00504   adns_answer *ans;
00505   adns_query parent;
00506 
00507   cancel_children(qu);
00508 
00509   qu->id= -1;
00510   ans= qu->answer;
00511 
00512   if (qu->flags & adns_qf_owner && qu->flags & adns_qf_search &&
00513       ans->status != adns_s_nomemory) {
00514     if (!save_owner(qu, (char*)qu->search_vb.buf, qu->search_vb.used)) {
00515       adns__query_fail(qu,adns_s_nomemory);
00516       return;
00517     }
00518   }
00519 
00520   if (ans->nrrs && qu->typei->diff_needswap) {
00521     if (!adns__vbuf_ensure(&qu->vb,qu->typei->rrsz)) {
00522       adns__query_fail(qu,adns_s_nomemory);
00523       return;
00524     }
00525     adns__isort(ans->rrs.bytes, ans->nrrs, ans->rrsz,
00526         qu->vb.buf,
00527         (int(*)(void*, const void*, const void*))qu->typei->diff_needswap,
00528         qu->ads);
00529   }
00530 
00531   ans->expires= qu->expires;
00532   parent= qu->parent;
00533   if (parent) {
00534     LIST_UNLINK_PART(parent->children,qu,siblings.);
00535     LIST_UNLINK(qu->ads->childw,parent);
00536     qu->ctx.callback(parent,qu);
00537     free_query_allocs(qu);
00538     free(qu->answer);
00539     free(qu);
00540   } else {
00541     makefinal_query(qu);
00542     LIST_LINK_TAIL(qu->ads->output,qu);
00543     qu->state= query_done;
00544   }
00545 }
00546 
00547 void adns__query_fail(adns_query qu, adns_status stat) {
00548   adns__reset_preserved(qu);
00549   qu->answer->status= stat;
00550   adns__query_done(qu);
00551 }
00552 
00553 void adns__makefinal_str(adns_query qu, char **strp) {
00554   int l;
00555   char *before, *after;
00556 
00557   before= *strp;
00558   if (!before) return;
00559   l= strlen(before)+1;
00560   after= adns__alloc_final(qu, (size_t) l);
00561   memcpy(after,before,(size_t) l);
00562   *strp= after;
00563 }
00564 
00565 void adns__makefinal_block(adns_query qu, void **blpp, size_t sz) {
00566   void *before, *after;
00567 
00568   before= *blpp;
00569   if (!before) return;
00570   after= adns__alloc_final(qu,sz);
00571   memcpy(after,before, (size_t) sz);
00572   *blpp= after;
00573 }

Generated on Sun May 27 2012 04:17:02 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.