00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "ares_private.h"
00024
00025 struct host_query {
00026
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
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
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
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
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
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
00140
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
00152 for (p = name; *p; p++)
00153 {
00154 if (!isdigit((unsigned char)*p) && *p != '.')
00155 return 0;
00156 }
00157
00158
00159
00160
00161 if (p == name || *(p - 1) == '.')
00162 return 0;
00163
00164
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
00173 hostent.h_name = strdup(name);
00174 if (!hostent.h_name)
00175 {
00176 callback(arg, ARES_ENOMEM, NULL);
00177 return 1;
00178 }
00179
00180
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
00200
00201
00202
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
00221
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 }