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

tree.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 doxygen 1.7.6.1

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