Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / libbind / dist / irs / gen_ho.c
blob22ba6d84b1ea00eb6783cedc1ec377a3cf4beda8
1 /* $NetBSD$ */
3 /*
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996,1999 by Internet Software Consortium.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #if defined(LIBC_SCCS) && !defined(lint)
21 static const char rcsid[] = "Id: gen_ho.c,v 1.5 2006/03/09 23:57:56 marka Exp";
22 #endif /* LIBC_SCCS and not lint */
24 /* Imports */
26 #include "port_before.h"
28 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <arpa/nameser.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <netdb.h>
36 #include <resolv.h>
37 #include <stdio.h>
38 #include <string.h>
40 #include <isc/memcluster.h>
41 #include <irs.h>
43 #include "port_after.h"
45 #include "irs_p.h"
46 #include "gen_p.h"
48 /* Definitions */
50 struct pvt {
51 struct irs_rule * rules;
52 struct irs_rule * rule;
53 struct irs_ho * ho;
54 struct __res_state * res;
55 void (*free_res)(void *);
58 /* Forwards */
60 static void ho_close(struct irs_ho *this);
61 static struct hostent * ho_byname(struct irs_ho *this, const char *name);
62 static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
63 int af);
64 static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
65 int len, int af);
66 static struct hostent * ho_next(struct irs_ho *this);
67 static void ho_rewind(struct irs_ho *this);
68 static void ho_minimize(struct irs_ho *this);
69 static struct __res_state * ho_res_get(struct irs_ho *this);
70 static void ho_res_set(struct irs_ho *this,
71 struct __res_state *res,
72 void (*free_res)(void *));
73 static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
74 const struct addrinfo *pai);
76 static int init(struct irs_ho *this);
78 /* Exports */
80 struct irs_ho *
81 irs_gen_ho(struct irs_acc *this) {
82 struct gen_p *accpvt = (struct gen_p *)this->private;
83 struct irs_ho *ho;
84 struct pvt *pvt;
86 if (!(pvt = memget(sizeof *pvt))) {
87 errno = ENOMEM;
88 return (NULL);
90 memset(pvt, 0, sizeof *pvt);
91 if (!(ho = memget(sizeof *ho))) {
92 memput(pvt, sizeof *pvt);
93 errno = ENOMEM;
94 return (NULL);
96 memset(ho, 0x5e, sizeof *ho);
97 pvt->rules = accpvt->map_rules[irs_ho];
98 pvt->rule = pvt->rules;
99 ho->private = pvt;
100 ho->close = ho_close;
101 ho->byname = ho_byname;
102 ho->byname2 = ho_byname2;
103 ho->byaddr = ho_byaddr;
104 ho->next = ho_next;
105 ho->rewind = ho_rewind;
106 ho->minimize = ho_minimize;
107 ho->res_get = ho_res_get;
108 ho->res_set = ho_res_set;
109 ho->addrinfo = ho_addrinfo;
110 return (ho);
113 /* Methods. */
115 static void
116 ho_close(struct irs_ho *this) {
117 struct pvt *pvt = (struct pvt *)this->private;
119 ho_minimize(this);
120 if (pvt->res && pvt->free_res)
121 (*pvt->free_res)(pvt->res);
122 memput(pvt, sizeof *pvt);
123 memput(this, sizeof *this);
126 static struct hostent *
127 ho_byname(struct irs_ho *this, const char *name) {
128 struct pvt *pvt = (struct pvt *)this->private;
129 struct irs_rule *rule;
130 struct hostent *rval;
131 struct irs_ho *ho;
132 int therrno = NETDB_INTERNAL;
133 int softerror = 0;
135 if (init(this) == -1)
136 return (NULL);
138 for (rule = pvt->rules; rule; rule = rule->next) {
139 ho = rule->inst->ho;
140 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
141 errno = 0;
142 rval = (*ho->byname)(ho, name);
143 if (rval != NULL)
144 return (rval);
145 if (softerror == 0 &&
146 pvt->res->res_h_errno != HOST_NOT_FOUND &&
147 pvt->res->res_h_errno != NETDB_INTERNAL) {
148 softerror = 1;
149 therrno = pvt->res->res_h_errno;
151 if (rule->flags & IRS_CONTINUE)
152 continue;
154 * The value TRY_AGAIN can mean that the service
155 * is not available, or just that this particular name
156 * cannot be resolved now. We use the errno ECONNREFUSED
157 * to distinguish. If a lookup sets that errno when
158 * H_ERRNO is TRY_AGAIN, we continue to try other lookup
159 * functions, otherwise we return the TRY_AGAIN error.
161 if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
162 break;
164 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
165 RES_SET_H_ERRNO(pvt->res, therrno);
166 return (NULL);
169 static struct hostent *
170 ho_byname2(struct irs_ho *this, const char *name, int af) {
171 struct pvt *pvt = (struct pvt *)this->private;
172 struct irs_rule *rule;
173 struct hostent *rval;
174 struct irs_ho *ho;
175 int therrno = NETDB_INTERNAL;
176 int softerror = 0;
178 if (init(this) == -1)
179 return (NULL);
181 for (rule = pvt->rules; rule; rule = rule->next) {
182 ho = rule->inst->ho;
183 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
184 errno = 0;
185 rval = (*ho->byname2)(ho, name, af);
186 if (rval != NULL)
187 return (rval);
188 if (softerror == 0 &&
189 pvt->res->res_h_errno != HOST_NOT_FOUND &&
190 pvt->res->res_h_errno != NETDB_INTERNAL) {
191 softerror = 1;
192 therrno = pvt->res->res_h_errno;
194 if (rule->flags & IRS_CONTINUE)
195 continue;
197 * See the comments in ho_byname() explaining
198 * the interpretation of TRY_AGAIN and ECONNREFUSED.
200 if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
201 break;
203 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
204 RES_SET_H_ERRNO(pvt->res, therrno);
205 return (NULL);
208 static struct hostent *
209 ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
210 struct pvt *pvt = (struct pvt *)this->private;
211 struct irs_rule *rule;
212 struct hostent *rval;
213 struct irs_ho *ho;
214 int therrno = NETDB_INTERNAL;
215 int softerror = 0;
218 if (init(this) == -1)
219 return (NULL);
221 for (rule = pvt->rules; rule; rule = rule->next) {
222 ho = rule->inst->ho;
223 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
224 errno = 0;
225 rval = (*ho->byaddr)(ho, addr, len, af);
226 if (rval != NULL)
227 return (rval);
228 if (softerror == 0 &&
229 pvt->res->res_h_errno != HOST_NOT_FOUND &&
230 pvt->res->res_h_errno != NETDB_INTERNAL) {
231 softerror = 1;
232 therrno = pvt->res->res_h_errno;
235 if (rule->flags & IRS_CONTINUE)
236 continue;
238 * See the comments in ho_byname() explaining
239 * the interpretation of TRY_AGAIN and ECONNREFUSED.
241 if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
242 break;
244 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
245 RES_SET_H_ERRNO(pvt->res, therrno);
246 return (NULL);
249 static struct hostent *
250 ho_next(struct irs_ho *this) {
251 struct pvt *pvt = (struct pvt *)this->private;
252 struct hostent *rval;
253 struct irs_ho *ho;
255 while (pvt->rule) {
256 ho = pvt->rule->inst->ho;
257 rval = (*ho->next)(ho);
258 if (rval)
259 return (rval);
260 if (!(pvt->rule->flags & IRS_CONTINUE))
261 break;
262 pvt->rule = pvt->rule->next;
263 if (pvt->rule) {
264 ho = pvt->rule->inst->ho;
265 (*ho->rewind)(ho);
268 return (NULL);
271 static void
272 ho_rewind(struct irs_ho *this) {
273 struct pvt *pvt = (struct pvt *)this->private;
274 struct irs_ho *ho;
276 pvt->rule = pvt->rules;
277 if (pvt->rule) {
278 ho = pvt->rule->inst->ho;
279 (*ho->rewind)(ho);
283 static void
284 ho_minimize(struct irs_ho *this) {
285 struct pvt *pvt = (struct pvt *)this->private;
286 struct irs_rule *rule;
288 if (pvt->res)
289 res_nclose(pvt->res);
290 for (rule = pvt->rules; rule != NULL; rule = rule->next) {
291 struct irs_ho *ho = rule->inst->ho;
293 (*ho->minimize)(ho);
297 static struct __res_state *
298 ho_res_get(struct irs_ho *this) {
299 struct pvt *pvt = (struct pvt *)this->private;
301 if (!pvt->res) {
302 struct __res_state *res;
303 res = (struct __res_state *)malloc(sizeof *res);
304 if (!res) {
305 errno = ENOMEM;
306 return (NULL);
308 memset(res, 0, sizeof *res);
309 ho_res_set(this, res, free);
312 return (pvt->res);
315 static void
316 ho_res_set(struct irs_ho *this, struct __res_state *res,
317 void (*free_res)(void *)) {
318 struct pvt *pvt = (struct pvt *)this->private;
319 struct irs_rule *rule;
321 if (pvt->res && pvt->free_res) {
322 res_nclose(pvt->res);
323 (*pvt->free_res)(pvt->res);
326 pvt->res = res;
327 pvt->free_res = free_res;
329 for (rule = pvt->rules; rule != NULL; rule = rule->next) {
330 struct irs_ho *ho = rule->inst->ho;
332 (*ho->res_set)(ho, pvt->res, NULL);
336 static struct addrinfo *
337 ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
339 struct pvt *pvt = (struct pvt *)this->private;
340 struct irs_rule *rule;
341 struct addrinfo *rval = NULL;
342 struct irs_ho *ho;
343 int therrno = NETDB_INTERNAL;
344 int softerror = 0;
346 if (init(this) == -1)
347 return (NULL);
349 for (rule = pvt->rules; rule; rule = rule->next) {
350 ho = rule->inst->ho;
351 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
352 errno = 0;
353 if (ho->addrinfo == NULL) /*%< for safety */
354 continue;
355 rval = (*ho->addrinfo)(ho, name, pai);
356 if (rval != NULL)
357 return (rval);
358 if (softerror == 0 &&
359 pvt->res->res_h_errno != HOST_NOT_FOUND &&
360 pvt->res->res_h_errno != NETDB_INTERNAL) {
361 softerror = 1;
362 therrno = pvt->res->res_h_errno;
364 if (rule->flags & IRS_CONTINUE)
365 continue;
367 * See the comments in ho_byname() explaining
368 * the interpretation of TRY_AGAIN and ECONNREFUSED.
370 if (pvt->res->res_h_errno != TRY_AGAIN ||
371 errno != ECONNREFUSED)
372 break;
374 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
375 RES_SET_H_ERRNO(pvt->res, therrno);
376 return (NULL);
379 static int
380 init(struct irs_ho *this) {
381 struct pvt *pvt = (struct pvt *)this->private;
383 if (!pvt->res && !ho_res_get(this))
384 return (-1);
386 if (((pvt->res->options & RES_INIT) == 0U) &&
387 (res_ninit(pvt->res) == -1))
388 return (-1);
390 return (0);
393 /*! \file */