/[resiprocate]/main/contrib/ares/ares_search.c
ViewVC logotype

Contents of /main/contrib/ares/ares_search.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5295 - (show annotations) (download)
Mon Aug 22 00:30:05 2005 UTC (14 years, 2 months ago) by jason
File MIME type: text/plain
File size: 7163 byte(s)
merged 5270:HEAD from b-directory-reorg
1 /* Copyright 1998 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose. It is provided "as is"
13 * without express or implied warranty.
14 */
15
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include "ares.h"
22 #include "ares_private.h"
23
24 struct search_query {
25 /* Arguments passed to ares_search */
26 ares_channel channel;
27 char *name; /* copied into an allocated buffer */
28 int dnsclass;
29 int type;
30 ares_callback callback;
31 void *arg;
32
33 int status_as_is; /* error status from trying as-is */
34 int next_domain; /* next search domain to try */
35 int trying_as_is; /* current query is for name as-is */
36 };
37
38 static void search_callback(void *arg, int status, unsigned char *abuf,
39 int alen);
40 static void end_squery(struct search_query *squery, int status,
41 unsigned char *abuf, int alen);
42 static int cat_domain(const char *name, const char *domain, char **s);
43 static int single_domain(ares_channel channel, const char *name, char **s);
44
45 void ares_search(ares_channel channel, const char *name, int dnsclass,
46 int type, ares_callback callback, void *arg)
47 {
48 struct search_query *squery;
49 char *s;
50 const char *p;
51 int status, ndots;
52
53 /* If name only yields one domain to search, then we don't have
54 * to keep extra state, so just do an ares_query().
55 */
56 status = single_domain(channel, name, &s);
57 if (status != ARES_SUCCESS)
58 {
59 callback(arg, status, NULL, 0);
60 return;
61 }
62 if (s)
63 {
64 ares_query(channel, s, dnsclass, type, callback, arg);
65 free(s);
66 return;
67 }
68
69 /* Allocate a search_query structure to hold the state necessary for
70 * doing multiple lookups.
71 */
72 squery = malloc(sizeof(struct search_query));
73 if (!squery)
74 {
75 callback(arg, ARES_ENOMEM, NULL, 0);
76 return;
77 }
78 squery->channel = channel;
79 squery->name = strdup(name);
80 if (!squery->name)
81 {
82 free(squery);
83 callback(arg, ARES_ENOMEM, NULL, 0);
84 return;
85 }
86 squery->dnsclass = dnsclass;
87 squery->type = type;
88 squery->status_as_is = -1;
89 squery->callback = callback;
90 squery->arg = arg;
91
92 /* Count the number of dots in name. */
93 ndots = 0;
94 for (p = name; *p; p++)
95 {
96 if (*p == '.')
97 ndots++;
98 }
99
100 /* If ndots is at least the channel ndots threshold (usually 1),
101 * then we try the name as-is first. Otherwise, we try the name
102 * as-is last.
103 */
104 if (ndots >= channel->ndots)
105 {
106 /* Try the name as-is first. */
107 squery->next_domain = 0;
108 squery->trying_as_is = 1;
109 ares_query(channel, name, dnsclass, type, search_callback, squery);
110 }
111 else
112 {
113 /* Try the name as-is last; start with the first search domain. */
114 squery->next_domain = 1;
115 squery->trying_as_is = 0;
116 status = cat_domain(name, channel->domains[0], &s);
117 if (status == ARES_SUCCESS)
118 {
119 ares_query(channel, s, dnsclass, type, search_callback, squery);
120 free(s);
121 }
122 else
123 callback(arg, status, NULL, 0);
124 }
125 }
126
127 static void search_callback(void *arg, int status, unsigned char *abuf,
128 int alen)
129 {
130 struct search_query *squery = (struct search_query *) arg;
131 ares_channel channel = squery->channel;
132 char *s;
133
134 /* Stop searching unless we got a non-fatal error. */
135 if (status != ARES_ENODATA && status != ARES_ESERVFAIL
136 && status != ARES_ENOTFOUND)
137 end_squery(squery, status, abuf, alen);
138 else
139 {
140 /* Save the status if we were trying as-is. */
141 if (squery->trying_as_is)
142 squery->status_as_is = status;
143 if (squery->next_domain < channel->ndomains)
144 {
145 /* Try the next domain. */
146 status = cat_domain(squery->name,
147 channel->domains[squery->next_domain], &s);
148 if (status != ARES_SUCCESS)
149 end_squery(squery, status, NULL, 0);
150 else
151 {
152 squery->trying_as_is = 0;
153 squery->next_domain++;
154 ares_query(channel, s, squery->dnsclass, squery->type,
155 search_callback, squery);
156 free(s);
157 }
158 }
159 else if (squery->status_as_is == -1)
160 {
161 /* Try the name as-is at the end. */
162 squery->trying_as_is = 1;
163 ares_query(channel, squery->name, squery->dnsclass, squery->type,
164 search_callback, squery);
165 }
166 else
167 end_squery(squery, squery->status_as_is, NULL, 0);
168 }
169 }
170
171 static void end_squery(struct search_query *squery, int status,
172 unsigned char *abuf, int alen)
173 {
174 squery->callback(squery->arg, status, abuf, alen);
175 free(squery->name);
176 free(squery);
177 }
178
179 /* Concatenate two domains. */
180 static int cat_domain(const char *name, const char *domain, char **s)
181 {
182 int nlen = strlen(name), dlen = strlen(domain);
183
184 *s = malloc(nlen + 1 + dlen + 1);
185 if (!*s)
186 return ARES_ENOMEM;
187 memcpy(*s, name, nlen);
188 (*s)[nlen] = '.';
189 memcpy(*s + nlen + 1, domain, dlen);
190 (*s)[nlen + 1 + dlen] = 0;
191 return ARES_SUCCESS;
192 }
193
194 /* Determine if this name only yields one query. If it does, set *s to
195 * the string we should query, in an allocated buffer. If not, set *s
196 * to NULL.
197 */
198 static int single_domain(ares_channel channel, const char *name, char **s)
199 {
200 int len = strlen(name);
201 const char *hostaliases;
202 FILE *fp;
203 char *line = NULL;
204 int linesize, status;
205 const char *p, *q;
206
207 /* If the name contains a trailing dot, then the single query is the name
208 * sans the trailing dot.
209 */
210 if (name[len - 1] == '.')
211 {
212 *s = strdup(name);
213 return (*s) ? ARES_SUCCESS : ARES_ENOMEM;
214 }
215
216 if (!(channel->flags & ARES_FLAG_NOALIASES) && !strchr(name, '.'))
217 {
218 /* The name might be a host alias. */
219 hostaliases = getenv("HOSTALIASES");
220 if (hostaliases)
221 {
222 fp = fopen(hostaliases, "r");
223 if (fp)
224 {
225 while ((status = ares__read_line(fp, &line, &linesize))
226 == ARES_SUCCESS)
227 {
228 if (strncasecmp(line, name, len) != 0 ||
229 !isspace((unsigned char)line[len]))
230 continue;
231 p = line + len;
232 while (isspace((unsigned char)*p))
233 p++;
234 if (*p)
235 {
236 q = p + 1;
237 while (*q && !isspace((unsigned char)*q))
238 q++;
239 *s = malloc(q - p + 1);
240 if (*s)
241 {
242 memcpy(*s, p, q - p);
243 (*s)[q - p] = 0;
244 }
245 free(line);
246 fclose(fp);
247 return (*s) ? ARES_SUCCESS : ARES_ENOMEM;
248 }
249 }
250 free(line);
251 fclose(fp);
252 if (status != ARES_SUCCESS)
253 return status;
254 }
255 }
256 }
257
258 if (channel->flags & ARES_FLAG_NOSEARCH || channel->ndomains == 0)
259 {
260 /* No domain search to do; just try the name as-is. */
261 *s = strdup(name);
262 return (*s) ? ARES_SUCCESS : ARES_ENOMEM;
263 }
264
265 *s = NULL;
266 return ARES_SUCCESS;
267 }

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27