Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentree.c
Go to the documentation of this file.
00001 /* tree.c 00002 00003 Routines for manipulating parse trees... */ 00004 00005 /* 00006 * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. 00007 * All rights reserved. 00008 * 00009 * Redistribution and use in source and binary forms, with or without 00010 * modification, are permitted provided that the following conditions 00011 * are met: 00012 * 00013 * 1. Redistributions of source code must retain the above copyright 00014 * notice, this list of conditions and the following disclaimer. 00015 * 2. Redistributions in binary form must reproduce the above copyright 00016 * notice, this list of conditions and the following disclaimer in the 00017 * documentation and/or other materials provided with the distribution. 00018 * 3. Neither the name of The Internet Software Consortium nor the names 00019 * of its contributors may be used to endorse or promote products derived 00020 * from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 00023 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 00024 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00025 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00026 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 00027 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00028 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00029 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 00030 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00031 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00032 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00033 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00034 * SUCH DAMAGE. 00035 * 00036 * This software has been written for the Internet Software Consortium 00037 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 00038 * Enterprises. To learn more about the Internet Software Consortium, 00039 * see ``http://www.vix.com/isc''. To learn more about Vixie 00040 * Enterprises, see ``http://www.vix.com''. 00041 */ 00042 00043 #ifndef lint 00044 static char copyright[] = 00045 "$Id: tree.c,v 1.10 1997/05/09 08:14:57 mellon Exp $ Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. All rights reserved.\n"; 00046 #endif /* not lint */ 00047 00048 #include "rosdhcp.h" 00049 00050 static TIME tree_evaluate_recurse PROTO ((int *, unsigned char **, int *, 00051 struct tree *)); 00052 static TIME do_host_lookup PROTO ((int *, unsigned char **, int *, 00053 struct dns_host_entry *)); 00054 static void do_data_copy PROTO ((int *, unsigned char **, int *, 00055 unsigned char *, int)); 00056 00057 pair cons (car, cdr) 00058 caddr_t car; 00059 pair cdr; 00060 { 00061 pair foo = (pair)dmalloc (sizeof *foo, "cons"); 00062 if (!foo) 00063 error ("no memory for cons."); 00064 foo -> car = car; 00065 foo -> cdr = cdr; 00066 return foo; 00067 } 00068 00069 struct tree_cache *tree_cache (tree) 00070 struct tree *tree; 00071 { 00072 struct tree_cache *tc; 00073 00074 tc = new_tree_cache ("tree_cache"); 00075 if (!tc) 00076 return 0; 00077 tc -> value = (unsigned char *)0; 00078 tc -> len = tc -> buf_size = 0; 00079 tc -> timeout = 0; 00080 tc -> tree = tree; 00081 return tc; 00082 } 00083 00084 struct tree *tree_host_lookup (name) 00085 char *name; 00086 { 00087 struct tree *nt; 00088 nt = new_tree ("tree_host_lookup"); 00089 if (!nt) 00090 error ("No memory for host lookup tree node."); 00091 nt -> op = TREE_HOST_LOOKUP; 00092 nt -> data.host_lookup.host = enter_dns_host (name); 00093 return nt; 00094 } 00095 00096 struct dns_host_entry *enter_dns_host (name) 00097 char *name; 00098 { 00099 struct dns_host_entry *dh; 00100 00101 if (!(dh = (struct dns_host_entry *)dmalloc 00102 (sizeof (struct dns_host_entry), "enter_dns_host")) 00103 || !(dh -> hostname = dmalloc (strlen (name) + 1, 00104 "enter_dns_host"))) 00105 error ("Can't allocate space for new host."); 00106 strcpy (dh -> hostname, name); 00107 dh -> data = (unsigned char *)0; 00108 dh -> data_len = 0; 00109 dh -> buf_len = 0; 00110 dh -> timeout = 0; 00111 return dh; 00112 } 00113 00114 struct tree *tree_const (data, len) 00115 unsigned char *data; 00116 int len; 00117 { 00118 struct tree *nt; 00119 if (!(nt = new_tree ("tree_const")) 00120 || !(nt -> data.const_val.data = 00121 (unsigned char *)dmalloc (len, "tree_const"))) 00122 error ("No memory for constant data tree node."); 00123 nt -> op = TREE_CONST; 00124 memcpy (nt -> data.const_val.data, data, len); 00125 nt -> data.const_val.len = len; 00126 return nt; 00127 } 00128 00129 struct tree *tree_concat (left, right) 00130 struct tree *left, *right; 00131 { 00132 struct tree *nt; 00133 00134 /* If we're concatenating a null tree to a non-null tree, just 00135 return the non-null tree; if both trees are null, return 00136 a null tree. */ 00137 if (!left) 00138 return right; 00139 if (!right) 00140 return left; 00141 00142 /* If both trees are constant, combine them. */ 00143 if (left -> op == TREE_CONST && right -> op == TREE_CONST) { 00144 unsigned char *buf = dmalloc (left -> data.const_val.len 00145 + right -> data.const_val.len, 00146 "tree_concat"); 00147 if (!buf) 00148 error ("No memory to concatenate constants."); 00149 memcpy (buf, left -> data.const_val.data, 00150 left -> data.const_val.len); 00151 memcpy (buf + left -> data.const_val.len, 00152 right -> data.const_val.data, 00153 right -> data.const_val.len); 00154 dfree (left -> data.const_val.data, "tree_concat"); 00155 dfree (right -> data.const_val.data, "tree_concat"); 00156 left -> data.const_val.data = buf; 00157 left -> data.const_val.len += right -> data.const_val.len; 00158 free_tree (right, "tree_concat"); 00159 return left; 00160 } 00161 00162 /* Otherwise, allocate a new node to concatenate the two. */ 00163 if (!(nt = new_tree ("tree_concat"))) 00164 error ("No memory for data tree concatenation node."); 00165 nt -> op = TREE_CONCAT; 00166 nt -> data.concat.left = left; 00167 nt -> data.concat.right = right; 00168 return nt; 00169 } 00170 00171 struct tree *tree_limit (tree, limit) 00172 struct tree *tree; 00173 int limit; 00174 { 00175 struct tree *rv; 00176 00177 /* If the tree we're limiting is constant, limit it now. */ 00178 if (tree -> op == TREE_CONST) { 00179 if (tree -> data.const_val.len > limit) 00180 tree -> data.const_val.len = limit; 00181 return tree; 00182 } 00183 00184 /* Otherwise, put in a node which enforces the limit on evaluation. */ 00185 rv = new_tree ("tree_limit"); 00186 if (!rv) 00187 return (struct tree *)0; 00188 rv -> op = TREE_LIMIT; 00189 rv -> data.limit.tree = tree; 00190 rv -> data.limit.limit = limit; 00191 return rv; 00192 } 00193 00194 int tree_evaluate (tree_cache) 00195 struct tree_cache *tree_cache; 00196 { 00197 unsigned char *bp = tree_cache -> value; 00198 int bc = tree_cache -> buf_size; 00199 int bufix = 0; 00200 00201 /* If there's no tree associated with this cache, it evaluates 00202 to a constant and that was detected at startup. */ 00203 if (!tree_cache -> tree) 00204 return 1; 00205 00206 /* Try to evaluate the tree without allocating more memory... */ 00207 tree_cache -> timeout = tree_evaluate_recurse (&bufix, &bp, &bc, 00208 tree_cache -> tree); 00209 00210 /* No additional allocation needed? */ 00211 if (bufix <= bc) { 00212 tree_cache -> len = bufix; 00213 return 1; 00214 } 00215 00216 /* If we can't allocate more memory, return with what we 00217 have (maybe nothing). */ 00218 if (!(bp = (unsigned char *)dmalloc (bufix, "tree_evaluate"))) 00219 return 0; 00220 00221 /* Record the change in conditions... */ 00222 bc = bufix; 00223 bufix = 0; 00224 00225 /* Note that the size of the result shouldn't change on the 00226 second call to tree_evaluate_recurse, since we haven't 00227 changed the ``current'' time. */ 00228 tree_evaluate_recurse (&bufix, &bp, &bc, tree_cache -> tree); 00229 00230 /* Free the old buffer if needed, then store the new buffer 00231 location and size and return. */ 00232 if (tree_cache -> value) 00233 dfree (tree_cache -> value, "tree_evaluate"); 00234 tree_cache -> value = bp; 00235 tree_cache -> len = bufix; 00236 tree_cache -> buf_size = bc; 00237 return 1; 00238 } 00239 00240 static TIME tree_evaluate_recurse (bufix, bufp, bufcount, tree) 00241 int *bufix; 00242 unsigned char **bufp; 00243 int *bufcount; 00244 struct tree *tree; 00245 { 00246 int limit; 00247 TIME t1, t2; 00248 00249 switch (tree -> op) { 00250 case TREE_CONCAT: 00251 t1 = tree_evaluate_recurse (bufix, bufp, bufcount, 00252 tree -> data.concat.left); 00253 t2 = tree_evaluate_recurse (bufix, bufp, bufcount, 00254 tree -> data.concat.right); 00255 if (t1 > t2) 00256 return t2; 00257 return t1; 00258 00259 case TREE_HOST_LOOKUP: 00260 return do_host_lookup (bufix, bufp, bufcount, 00261 tree -> data.host_lookup.host); 00262 00263 case TREE_CONST: 00264 do_data_copy (bufix, bufp, bufcount, 00265 tree -> data.const_val.data, 00266 tree -> data.const_val.len); 00267 t1 = MAX_TIME; 00268 return t1; 00269 00270 case TREE_LIMIT: 00271 limit = *bufix + tree -> data.limit.limit; 00272 t1 = tree_evaluate_recurse (bufix, bufp, bufcount, 00273 tree -> data.limit.tree); 00274 *bufix = limit; 00275 return t1; 00276 00277 default: 00278 warn ("Bad node id in tree: %d."); 00279 t1 = MAX_TIME; 00280 return t1; 00281 } 00282 } 00283 00284 static TIME do_host_lookup (bufix, bufp, bufcount, dns) 00285 int *bufix; 00286 unsigned char **bufp; 00287 int *bufcount; 00288 struct dns_host_entry *dns; 00289 { 00290 struct hostent *h; 00291 int i; 00292 int new_len; 00293 00294 #ifdef DEBUG_EVAL 00295 debug ("time: now = %d dns = %d %d diff = %d", 00296 cur_time, dns -> timeout, cur_time - dns -> timeout); 00297 #endif 00298 00299 /* If the record hasn't timed out, just copy the data and return. */ 00300 if (cur_time <= dns -> timeout) { 00301 #ifdef DEBUG_EVAL 00302 debug ("easy copy: %x %d %x", 00303 dns -> data, dns -> data_len, 00304 dns -> data ? *(int *)(dns -> data) : 0); 00305 #endif 00306 do_data_copy (bufix, bufp, bufcount, 00307 dns -> data, dns -> data_len); 00308 return dns -> timeout; 00309 } 00310 #ifdef DEBUG_EVAL 00311 debug ("Looking up %s", dns -> hostname); 00312 #endif 00313 00314 /* Otherwise, look it up... */ 00315 h = gethostbyname (dns -> hostname); 00316 if (!h) { 00317 #ifndef NO_H_ERRNO 00318 switch (h_errno) { 00319 case HOST_NOT_FOUND: 00320 #endif 00321 warn ("%s: host unknown.", dns -> hostname); 00322 #ifndef NO_H_ERRNO 00323 break; 00324 case TRY_AGAIN: 00325 warn ("%s: temporary name server failure", 00326 dns -> hostname); 00327 break; 00328 case NO_RECOVERY: 00329 warn ("%s: name server failed", dns -> hostname); 00330 break; 00331 case NO_DATA: 00332 warn ("%s: no A record associated with address", 00333 dns -> hostname); 00334 } 00335 #endif /* !NO_H_ERRNO */ 00336 00337 /* Okay to try again after a minute. */ 00338 return cur_time + 60; 00339 } 00340 00341 #ifdef DEBUG_EVAL 00342 debug ("Lookup succeeded; first address is %x", 00343 h -> h_addr_list [0]); 00344 #endif 00345 00346 /* Count the number of addresses we got... */ 00347 for (i = 0; h -> h_addr_list [i]; i++) 00348 ; 00349 00350 /* Do we need to allocate more memory? */ 00351 new_len = i * h -> h_length; 00352 if (dns -> buf_len < i) { 00353 unsigned char *buf = 00354 (unsigned char *)dmalloc (new_len, "do_host_lookup"); 00355 /* If we didn't get more memory, use what we have. */ 00356 if (!buf) { 00357 new_len = dns -> buf_len; 00358 if (!dns -> buf_len) { 00359 dns -> timeout = cur_time + 60; 00360 return dns -> timeout; 00361 } 00362 } else { 00363 if (dns -> data) 00364 dfree (dns -> data, "do_host_lookup"); 00365 dns -> data = buf; 00366 dns -> buf_len = new_len; 00367 } 00368 } 00369 00370 /* Addresses are conveniently stored one to the buffer, so we 00371 have to copy them out one at a time... :'( */ 00372 for (i = 0; i < new_len / h -> h_length; i++) { 00373 memcpy (dns -> data + h -> h_length * i, 00374 h -> h_addr_list [i], h -> h_length); 00375 } 00376 #ifdef DEBUG_EVAL 00377 debug ("dns -> data: %x h -> h_addr_list [0]: %x", 00378 *(int *)(dns -> data), h -> h_addr_list [0]); 00379 #endif 00380 dns -> data_len = new_len; 00381 00382 /* Set the timeout for an hour from now. 00383 XXX This should really use the time on the DNS reply. */ 00384 dns -> timeout = cur_time + 3600; 00385 00386 #ifdef DEBUG_EVAL 00387 debug ("hard copy: %x %d %x", 00388 dns -> data, dns -> data_len, *(int *)(dns -> data)); 00389 #endif 00390 do_data_copy (bufix, bufp, bufcount, dns -> data, dns -> data_len); 00391 return dns -> timeout; 00392 } 00393 00394 static void do_data_copy (bufix, bufp, bufcount, data, len) 00395 int *bufix; 00396 unsigned char **bufp; 00397 int *bufcount; 00398 unsigned char *data; 00399 int len; 00400 { 00401 int space = *bufcount - *bufix; 00402 00403 /* If there's more space than we need, use only what we need. */ 00404 if (space > len) 00405 space = len; 00406 00407 /* Copy as much data as will fit, then increment the buffer index 00408 by the amount we actually had to copy, which could be more. */ 00409 if (space > 0) 00410 memcpy (*bufp + *bufix, data, space); 00411 *bufix += len; 00412 } Generated on Sat May 26 2012 04:22:03 for ReactOS by
1.7.6.1
|