Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenquery.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
1.7.6.1
|