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 search_query {
00026
00027 ares_channel channel;
00028 char *name;
00029 int dnsclass;
00030 int type;
00031 ares_callback callback;
00032 void *arg;
00033
00034 int status_as_is;
00035 int next_domain;
00036 int trying_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
00055
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
00071
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
00094 ndots = 0;
00095 for (p = name; *p; p++)
00096 {
00097 if (*p == '.')
00098 ndots++;
00099 }
00100
00101
00102
00103
00104
00105 if (ndots >= channel->ndots)
00106 {
00107
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
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
00136 if (status != ARES_ENODATA && status != ARES_ESERVFAIL
00137 && status != ARES_ENOTFOUND)
00138 end_squery(squery, status, abuf, alen);
00139 else
00140 {
00141
00142 if (squery->trying_as_is)
00143 squery->status_as_is = status;
00144 if (squery->next_domain < channel->ndomains)
00145 {
00146
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
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
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
00196
00197
00198
00199 static int single_domain(ares_channel channel, const char *name, char **s)
00200 {
00201 int len = strlen(name);
00202
00203
00204
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
00215 *s = strdup(name);
00216 return (*s) ? ARES_SUCCESS : ARES_ENOMEM;
00217 }
00218
00219 *s = NULL;
00220 return ARES_SUCCESS;
00221 }