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

ares_gethostbyname.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 host_query {
00026   /* Arguments passed to ares_gethostbyname() */
00027   ares_channel channel;
00028   char *name;
00029   ares_host_callback callback;
00030   void *arg;
00031 
00032   const char *remaining_lookups;
00033 };
00034 
00035 static void next_lookup(struct host_query *hquery);
00036 static void host_callback(void *arg, int status, unsigned char *abuf,
00037                           int alen);
00038 static void end_hquery(struct host_query *hquery, int status,
00039                        struct hostent *host);
00040 static int fake_hostent(const char *name, ares_host_callback callback,
00041                         void *arg);
00042 static void sort_addresses(struct hostent *host, struct apattern *sortlist,
00043                            int nsort);
00044 static int get_address_index(struct in_addr *addr, struct apattern *sortlist,
00045                              int nsort);
00046 
00047 void ares_gethostbyname(ares_channel channel, const char *name, int family,
00048                         ares_host_callback callback, void *arg)
00049 {
00050   struct host_query *hquery;
00051 
00052   /* Right now we only know how to look up Internet addresses. */
00053   if (family != AF_INET)
00054     {
00055       callback(arg, ARES_ENOTIMP, NULL);
00056       return;
00057     }
00058 
00059   if (fake_hostent(name, callback, arg))
00060     return;
00061 
00062   /* Allocate and fill in the host query structure. */
00063   hquery = malloc(sizeof(struct host_query));
00064   if (!hquery)
00065     {
00066       callback(arg, ARES_ENOMEM, NULL);
00067       return;
00068     }
00069 
00070   hquery->channel = channel;
00071   hquery->name = strdup(name);
00072   if (!hquery->name)
00073     {
00074       free(hquery);
00075       callback(arg, ARES_ENOMEM, NULL);
00076       return;
00077     }
00078 
00079   hquery->callback = callback;
00080   hquery->arg = arg;
00081   hquery->remaining_lookups = channel->lookups;
00082 
00083   /* Start performing lookups according to channel->lookups. */
00084   next_lookup(hquery);
00085 }
00086 
00087 static void next_lookup(struct host_query *hquery)
00088 {
00089   const char *p;
00090 
00091   for (p = hquery->remaining_lookups; *p; p++)
00092     {
00093       switch (*p)
00094         {
00095         case 'b':
00096           /* DNS lookup */
00097           hquery->remaining_lookups = p + 1;
00098           ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback,
00099                       hquery);
00100           return;
00101 
00102         case 'f':
00103           /* Host file lookup */
00104           break;
00105         }
00106     }
00107   end_hquery(hquery, ARES_ENOTFOUND, NULL);
00108 }
00109 
00110 static void host_callback(void *arg, int status, unsigned char *abuf, int alen)
00111 {
00112   struct host_query *hquery = (struct host_query *) arg;
00113   ares_channel channel = hquery->channel;
00114   struct hostent *host;
00115 
00116   if (status == ARES_SUCCESS)
00117     {
00118       status = ares_parse_a_reply(abuf, alen, &host);
00119       if (host && channel->nsort)
00120         sort_addresses(host, channel->sortlist, channel->nsort);
00121       end_hquery(hquery, status, host);
00122     }
00123   else if (status == ARES_EDESTRUCTION)
00124     end_hquery(hquery, status, NULL);
00125   else
00126     next_lookup(hquery);
00127 }
00128 
00129 static void end_hquery(struct host_query *hquery, int status,
00130                        struct hostent *host)
00131 {
00132   hquery->callback(hquery->arg, status, host);
00133   if (host)
00134     ares_free_hostent(host);
00135   free(hquery->name);
00136   free(hquery);
00137 }
00138 
00139 /* If the name looks like an IP address, fake up a host entry, end the
00140  * query immediately, and return true.  Otherwise return false.
00141  */
00142 static int fake_hostent(const char *name, ares_host_callback callback,
00143                         void *arg)
00144 {
00145   struct in_addr addr;
00146   struct hostent hostent;
00147   const char *p;
00148   char *aliases[1] = { NULL };
00149   char *addrs[2];
00150 
00151   /* It only looks like an IP address if it's all numbers and dots. */
00152   for (p = name; *p; p++)
00153     {
00154       if (!isdigit((unsigned char)*p) && *p != '.')
00155         return 0;
00156     }
00157 
00158   /* It also only looks like an IP address if it's non-zero-length and
00159    * doesn't end with a dot.
00160    */
00161   if (p == name || *(p - 1) == '.')
00162     return 0;
00163 
00164   /* It looks like an IP address.  Figure out what IP address it is. */
00165   addr.s_addr = inet_addr(name);
00166   if (addr.s_addr == INADDR_NONE)
00167     {
00168       callback(arg, ARES_EBADNAME, NULL);
00169       return 1;
00170     }
00171 
00172   /* Duplicate the name, to avoid a constness violation. */
00173   hostent.h_name = strdup(name);
00174   if (!hostent.h_name)
00175     {
00176       callback(arg, ARES_ENOMEM, NULL);
00177       return 1;
00178     }
00179 
00180   /* Fill in the rest of the host structure and terminate the query. */
00181   addrs[0] = (char *) &addr;
00182   addrs[1] = NULL;
00183   hostent.h_aliases = aliases;
00184   hostent.h_addrtype = AF_INET;
00185   hostent.h_length = sizeof(struct in_addr);
00186   hostent.h_addr_list = addrs;
00187   callback(arg, ARES_SUCCESS, &hostent);
00188 
00189   free(hostent.h_name);
00190   return 1;
00191 }
00192 
00193 static void sort_addresses(struct hostent *host, struct apattern *sortlist,
00194                            int nsort)
00195 {
00196   struct in_addr a1, a2;
00197   int i1, i2, ind1, ind2;
00198 
00199   /* This is a simple insertion sort, not optimized at all.  i1 walks
00200    * through the address list, with the loop invariant that everything
00201    * to the left of i1 is sorted.  In the loop body, the value at i1 is moved
00202    * back through the list (via i2) until it is in sorted order.
00203    */
00204   for (i1 = 0; host->h_addr_list[i1]; i1++)
00205     {
00206       memcpy(&a1, host->h_addr_list[i1], sizeof(struct in_addr));
00207       ind1 = get_address_index(&a1, sortlist, nsort);
00208       for (i2 = i1 - 1; i2 >= 0; i2--)
00209         {
00210           memcpy(&a2, host->h_addr_list[i2], sizeof(struct in_addr));
00211           ind2 = get_address_index(&a2, sortlist, nsort);
00212           if (ind2 <= ind1)
00213             break;
00214           memcpy(host->h_addr_list[i2 + 1], &a2, sizeof(struct in_addr));
00215         }
00216       memcpy(host->h_addr_list[i2 + 1], &a1, sizeof(struct in_addr));
00217     }
00218 }
00219 
00220 /* Find the first entry in sortlist which matches addr.  Return nsort
00221  * if none of them match.
00222  */
00223 static int get_address_index(struct in_addr *addr, struct apattern *sortlist,
00224                              int nsort)
00225 {
00226   int i;
00227 
00228   for (i = 0; i < nsort; i++)
00229     {
00230       if ((addr->s_addr & sortlist[i].mask.s_addr) == sortlist[i].addr.s_addr)
00231         break;
00232     }
00233   return i;
00234 }

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