2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1996,1999 by Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static const char rcsid
[] = "$Id: gen_ho.c,v 1.1.2.2 2004/03/17 01:54:19 marka Exp $";
20 #endif /* LIBC_SCCS and not lint */
24 #include "port_before.h"
26 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <arpa/nameser.h>
38 #include <isc/memcluster.h>
41 #include "port_after.h"
49 struct irs_rule
* rules
;
50 struct irs_rule
* rule
;
52 struct __res_state
* res
;
53 void (*free_res
)(void *);
58 static void ho_close(struct irs_ho
*this);
59 static struct hostent
* ho_byname(struct irs_ho
*this, const char *name
);
60 static struct hostent
* ho_byname2(struct irs_ho
*this, const char *name
,
62 static struct hostent
* ho_byaddr(struct irs_ho
*this, const void *addr
,
64 static struct hostent
* ho_next(struct irs_ho
*this);
65 static void ho_rewind(struct irs_ho
*this);
66 static void ho_minimize(struct irs_ho
*this);
67 static struct __res_state
* ho_res_get(struct irs_ho
*this);
68 static void ho_res_set(struct irs_ho
*this,
69 struct __res_state
*res
,
70 void (*free_res
)(void *));
71 static struct addrinfo
* ho_addrinfo(struct irs_ho
*this, const char *name
,
72 const struct addrinfo
*pai
);
74 static int init(struct irs_ho
*this);
79 irs_gen_ho(struct irs_acc
*this) {
80 struct gen_p
*accpvt
= (struct gen_p
*)this->private;
84 if (!(pvt
= memget(sizeof *pvt
))) {
88 memset(pvt
, 0, sizeof *pvt
);
89 if (!(ho
= memget(sizeof *ho
))) {
90 memput(pvt
, sizeof *pvt
);
94 memset(ho
, 0x5e, sizeof *ho
);
95 pvt
->rules
= accpvt
->map_rules
[irs_ho
];
96 pvt
->rule
= pvt
->rules
;
99 ho
->byname
= ho_byname
;
100 ho
->byname2
= ho_byname2
;
101 ho
->byaddr
= ho_byaddr
;
103 ho
->rewind
= ho_rewind
;
104 ho
->minimize
= ho_minimize
;
105 ho
->res_get
= ho_res_get
;
106 ho
->res_set
= ho_res_set
;
107 ho
->addrinfo
= ho_addrinfo
;
114 ho_close(struct irs_ho
*this) {
115 struct pvt
*pvt
= (struct pvt
*)this->private;
118 if (pvt
->res
&& pvt
->free_res
)
119 (*pvt
->free_res
)(pvt
->res
);
120 memput(pvt
, sizeof *pvt
);
121 memput(this, sizeof *this);
124 static struct hostent
*
125 ho_byname(struct irs_ho
*this, const char *name
) {
126 struct pvt
*pvt
= (struct pvt
*)this->private;
127 struct irs_rule
*rule
;
128 struct hostent
*rval
;
130 int therrno
= NETDB_INTERNAL
;
133 if (init(this) == -1)
136 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
138 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
140 rval
= (*ho
->byname
)(ho
, name
);
143 if (softerror
== 0 &&
144 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
145 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
147 therrno
= pvt
->res
->res_h_errno
;
149 if (rule
->flags
& IRS_CONTINUE
)
152 * The value TRY_AGAIN can mean that the service
153 * is not available, or just that this particular name
154 * cannot be resolved now. We use the errno ECONNREFUSED
155 * to distinguish. If a lookup sets that errno when
156 * H_ERRNO is TRY_AGAIN, we continue to try other lookup
157 * functions, otherwise we return the TRY_AGAIN error.
159 if (pvt
->res
->res_h_errno
!= TRY_AGAIN
|| errno
!= ECONNREFUSED
)
162 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
163 RES_SET_H_ERRNO(pvt
->res
, therrno
);
167 static struct hostent
*
168 ho_byname2(struct irs_ho
*this, const char *name
, int af
) {
169 struct pvt
*pvt
= (struct pvt
*)this->private;
170 struct irs_rule
*rule
;
171 struct hostent
*rval
;
173 int therrno
= NETDB_INTERNAL
;
176 if (init(this) == -1)
179 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
181 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
183 rval
= (*ho
->byname2
)(ho
, name
, af
);
186 if (softerror
== 0 &&
187 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
188 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
190 therrno
= pvt
->res
->res_h_errno
;
192 if (rule
->flags
& IRS_CONTINUE
)
195 * See the comments in ho_byname() explaining
196 * the interpretation of TRY_AGAIN and ECONNREFUSED.
198 if (pvt
->res
->res_h_errno
!= TRY_AGAIN
|| errno
!= ECONNREFUSED
)
201 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
202 RES_SET_H_ERRNO(pvt
->res
, therrno
);
206 static struct hostent
*
207 ho_byaddr(struct irs_ho
*this, const void *addr
, int len
, int af
) {
208 struct pvt
*pvt
= (struct pvt
*)this->private;
209 struct irs_rule
*rule
;
210 struct hostent
*rval
;
212 int therrno
= NETDB_INTERNAL
;
216 if (init(this) == -1)
219 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
221 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
223 rval
= (*ho
->byaddr
)(ho
, addr
, len
, af
);
226 if (softerror
== 0 &&
227 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
228 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
230 therrno
= pvt
->res
->res_h_errno
;
233 if (rule
->flags
& IRS_CONTINUE
)
236 * See the comments in ho_byname() explaining
237 * the interpretation of TRY_AGAIN and ECONNREFUSED.
239 if (pvt
->res
->res_h_errno
!= TRY_AGAIN
|| errno
!= ECONNREFUSED
)
242 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
243 RES_SET_H_ERRNO(pvt
->res
, therrno
);
247 static struct hostent
*
248 ho_next(struct irs_ho
*this) {
249 struct pvt
*pvt
= (struct pvt
*)this->private;
250 struct hostent
*rval
;
254 ho
= pvt
->rule
->inst
->ho
;
255 rval
= (*ho
->next
)(ho
);
258 if (!(pvt
->rule
->flags
& IRS_CONTINUE
))
260 pvt
->rule
= pvt
->rule
->next
;
262 ho
= pvt
->rule
->inst
->ho
;
270 ho_rewind(struct irs_ho
*this) {
271 struct pvt
*pvt
= (struct pvt
*)this->private;
274 pvt
->rule
= pvt
->rules
;
276 ho
= pvt
->rule
->inst
->ho
;
282 ho_minimize(struct irs_ho
*this) {
283 struct pvt
*pvt
= (struct pvt
*)this->private;
284 struct irs_rule
*rule
;
287 res_nclose(pvt
->res
);
288 for (rule
= pvt
->rules
; rule
!= NULL
; rule
= rule
->next
) {
289 struct irs_ho
*ho
= rule
->inst
->ho
;
295 static struct __res_state
*
296 ho_res_get(struct irs_ho
*this) {
297 struct pvt
*pvt
= (struct pvt
*)this->private;
300 struct __res_state
*res
;
301 res
= (struct __res_state
*)malloc(sizeof *res
);
306 memset(res
, 0, sizeof *res
);
307 ho_res_set(this, res
, free
);
314 ho_res_set(struct irs_ho
*this, struct __res_state
*res
,
315 void (*free_res
)(void *)) {
316 struct pvt
*pvt
= (struct pvt
*)this->private;
317 struct irs_rule
*rule
;
319 if (pvt
->res
&& pvt
->free_res
) {
320 res_nclose(pvt
->res
);
321 (*pvt
->free_res
)(pvt
->res
);
325 pvt
->free_res
= free_res
;
327 for (rule
= pvt
->rules
; rule
!= NULL
; rule
= rule
->next
) {
328 struct irs_ho
*ho
= rule
->inst
->ho
;
330 (*ho
->res_set
)(ho
, pvt
->res
, NULL
);
334 static struct addrinfo
*
335 ho_addrinfo(struct irs_ho
*this, const char *name
, const struct addrinfo
*pai
)
337 struct pvt
*pvt
= (struct pvt
*)this->private;
338 struct irs_rule
*rule
;
339 struct addrinfo
*rval
= NULL
;
341 int therrno
= NETDB_INTERNAL
;
344 if (init(this) == -1)
347 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
349 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
351 if (ho
->addrinfo
== NULL
) /* for safety */
353 rval
= (*ho
->addrinfo
)(ho
, name
, pai
);
356 if (softerror
== 0 &&
357 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
358 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
360 therrno
= pvt
->res
->res_h_errno
;
362 if (rule
->flags
& IRS_CONTINUE
)
365 * See the comments in ho_byname() explaining
366 * the interpretation of TRY_AGAIN and ECONNREFUSED.
368 if (pvt
->res
->res_h_errno
!= TRY_AGAIN
||
369 errno
!= ECONNREFUSED
)
372 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
373 RES_SET_H_ERRNO(pvt
->res
, therrno
);
380 init(struct irs_ho
*this) {
381 struct pvt
*pvt
= (struct pvt
*)this->private;
383 if (!pvt
->res
&& !ho_res_get(this))
386 if (((pvt
->res
->options
& RES_INIT
) == 0U) &&
387 (res_ninit(pvt
->res
) == -1))