Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

ares_search.c

Go to the documentation of this file.
00001 /* Copyright 1998 by the Massachusetts Institute of Technology.
00002  *
00003  * Permission to use, copy, modify, and distribute this
00004  * software and its documentation for any purpose and without
00005  * fee is hereby granted, provided that the above copyright
00006  * notice appear in all copies and that both that copyright
00007  * notice and this permission notice appear in supporting
00008  * documentation, and that the name of M.I.T. not be used in
00009  * advertising or publicity pertaining to distribution of the
00010  * software without specific, written prior permission.
00011  * M.I.T. makes no representations about the suitability of
00012  * this software for any purpose.  It is provided "as is"
00013  * without express or implied warranty.
00014  *
00015  * CHANGELOG: this file has been modified by Sergio Perez Alcañiz <serpeal@disca.upv.es> 
00016  *            Departamento de Informática de Sistemas y Computadores          
00017  *            Universidad Politécnica de Valencia                             
00018  *            Valencia (Spain)    
00019  *            Date: April 2003                                          
00020  *
00021  */
00022 
00023 #include "ares_private.h"
00024 
00025 struct search_query {
00026   /* Arguments passed to ares_search */
00027   ares_channel channel;
00028   char *name;                   /* copied into an allocated buffer */
00029   int dnsclass;
00030   int type;
00031   ares_callback callback;
00032   void *arg;
00033 
00034   int status_as_is;             /* error status from trying as-is */
00035   int next_domain;              /* next search domain to try */
00036   int trying_as_is;             /* current query is for name as-is */
00037 };
00038 
00039 static void search_callback(void *arg, int status, unsigned char *abuf,
00040                             int alen);
00041 static void end_squery(struct search_query *squery, int status,
00042                        unsigned char *abuf, int alen);
00043 static int cat_domain(const char *name, const char *domain, char **s);
00044 static int single_domain(ares_channel channel, const char *name, char **s);
00045 
00046 void ares_search(ares_channel channel, const char *name, int dnsclass,
00047                  int type, ares_callback callback, void *arg)
00048 {
00049   struct search_query *squery;
00050   char *s;
00051   const char *p;
00052   int status, ndots;
00053   
00054   /* If name only yields one domain to search, then we don't have
00055    * to keep extra state, so just do an ares_query().
00056    */
00057   status = single_domain(channel, name, &s);
00058   if (status != ARES_SUCCESS)
00059     {
00060       callback(arg, status, NULL, 0);
00061       return;
00062     }
00063   if (s)
00064     {
00065       ares_query(channel, s, dnsclass, type, callback, arg);
00066       free(s);
00067       return;
00068     }
00069   
00070   /* Allocate a search_query structure to hold the state necessary for
00071    * doing multiple lookups.
00072    */
00073   squery = malloc(sizeof(struct search_query));
00074   if (!squery)
00075     {
00076       callback(arg, ARES_ENOMEM, NULL, 0);
00077       return;
00078     }
00079   squery->channel = channel;
00080   squery->name = strdup(name);
00081   if(!squery->name)
00082     {
00083       free(squery);
00084       callback(arg, ARES_ENOMEM, NULL, 0);
00085       return;
00086     }
00087   squery->dnsclass = dnsclass;
00088   squery->type = type;
00089   squery->status_as_is = -1;
00090   squery->callback = callback;
00091   squery->arg = arg;
00092   
00093   /* Count the number of dots in name. */
00094   ndots = 0;
00095   for (p = name; *p; p++)
00096     {
00097       if (*p == '.')
00098         ndots++;
00099     }
00100   
00101   /* If ndots is at least the channel ndots threshold (usually 1),
00102    * then we try the name as-is first.  Otherwise, we try the name
00103    * as-is last.
00104    */
00105   if (ndots >= channel->ndots)
00106     {
00107       /* Try the name as-is first. */
00108       squery->next_domain = 0;
00109       squery->trying_as_is = 1;
00110       ares_query(channel, name, dnsclass, type, search_callback, squery);
00111     }
00112   else
00113     {
00114       /* Try the name as-is last; start with the first search domain. */
00115       squery->next_domain = 1;
00116       squery->trying_as_is = 0;
00117       status = cat_domain(name, channel->domains[0], &s);
00118       if (status == ARES_SUCCESS)
00119         {
00120           ares_query(channel, s, dnsclass, type, search_callback, squery);
00121           free(s);
00122         }
00123       else
00124         callback(arg, status, NULL, 0);
00125     }
00126 }
00127 
00128 static void search_callback(void *arg, int status, unsigned char *abuf,
00129                             int alen)
00130 {
00131   struct search_query *squery = (struct search_query *) arg;
00132   ares_channel channel = squery->channel;
00133   char *s;
00134   
00135   /* Stop searching unless we got a non-fatal error. */
00136   if (status != ARES_ENODATA && status != ARES_ESERVFAIL
00137       && status != ARES_ENOTFOUND)
00138     end_squery(squery, status, abuf, alen);
00139   else
00140     {
00141       /* Save the status if we were trying as-is. */
00142       if (squery->trying_as_is)
00143         squery->status_as_is = status;
00144       if (squery->next_domain < channel->ndomains)
00145         {
00146           /* Try the next domain. */
00147           status = cat_domain(squery->name,
00148                               channel->domains[squery->next_domain], &s);
00149           if (status != ARES_SUCCESS)
00150             end_squery(squery, status, NULL, 0);
00151           else
00152             {
00153               squery->trying_as_is = 0;
00154               squery->next_domain++;
00155               ares_query(channel, s, squery->dnsclass, squery->type,
00156                          search_callback, squery);
00157               free(s);
00158             }
00159         }
00160       else if (squery->status_as_is == -1)
00161         {
00162           /* Try the name as-is at the end. */
00163           squery->trying_as_is = 1;
00164           ares_query(channel, squery->name, squery->dnsclass, squery->type,
00165                      search_callback, squery);
00166         }
00167       else
00168         end_squery(squery, squery->status_as_is, NULL, 0);
00169     }
00170 }
00171 
00172 static void end_squery(struct search_query *squery, int status,
00173                        unsigned char *abuf, int alen)
00174 {
00175   squery->callback(squery->arg, status, abuf, alen);
00176   free(squery->name);
00177   free(squery);
00178 }
00179 
00180 /* Concatenate two domains. */
00181 static int cat_domain(const char *name, const char *domain, char **s)
00182 {
00183   int nlen = strlen(name), dlen = strlen(domain);
00184   
00185   *s = malloc(nlen + 1 + dlen + 1);
00186   if (!*s)
00187     return ARES_ENOMEM;
00188   memcpy(*s, name, nlen);
00189   (*s)[nlen] = '.';
00190   memcpy(*s + nlen + 1, domain, dlen);
00191   (*s)[nlen + 1 + dlen] = 0;
00192   return ARES_SUCCESS;
00193 }
00194 
00195 /* Determine if this name only yields one query.  If it does, set *s to
00196  * the string we should query, in an allocated buffer.  If not, set *s
00197  * to NULL.
00198  */
00199 static int single_domain(ares_channel channel, const char *name, char **s)
00200 {
00201   int len = strlen(name);
00202   
00203   /* If the name contains a trailing dot, then the single query is the name
00204    * sans the trailing dot.
00205    */
00206   if (name[len - 1] == '.')
00207     {
00208       *s = strdup(name);
00209       return (*s) ? ARES_SUCCESS : ARES_ENOMEM;
00210     }
00211   
00212   if (channel->flags & ARES_FLAG_NOSEARCH || channel->ndomains == 0)
00213     {
00214       /* No domain search to do; just try the name as-is. */
00215       *s = strdup(name);
00216       return (*s) ? ARES_SUCCESS : ARES_ENOMEM;
00217     }
00218   
00219   *s = NULL;
00220   return ARES_SUCCESS;
00221 }

Generated on Wed Jan 14 12:58:56 2004 for RTL-lwIP-0.4 by doxygen 1.3.4