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.
20 #include "port_before.h"
22 #include <sys/types.h>
24 #include <netinet/in.h>
25 #include <arpa/nameser.h>
34 #include <isc/memcluster.h>
37 #include "port_after.h"
45 struct irs_rule
* rules
;
46 struct irs_rule
* rule
;
48 struct __res_state
* res
;
49 void (*free_res
)(void *);
54 static void ho_close(struct irs_ho
*this);
55 static struct hostent
* ho_byname(struct irs_ho
*this, const char *name
);
56 static struct hostent
* ho_byname2(struct irs_ho
*this, const char *name
,
58 static struct hostent
* ho_byaddr(struct irs_ho
*this, const void *addr
,
60 static struct hostent
* ho_next(struct irs_ho
*this);
61 static void ho_rewind(struct irs_ho
*this);
62 static void ho_minimize(struct irs_ho
*this);
63 static struct __res_state
* ho_res_get(struct irs_ho
*this);
64 static void ho_res_set(struct irs_ho
*this,
65 struct __res_state
*res
,
66 void (*free_res
)(void *));
67 static struct addrinfo
* ho_addrinfo(struct irs_ho
*this, const char *name
,
68 const struct addrinfo
*pai
);
70 static int init(struct irs_ho
*this);
75 irs_gen_ho(struct irs_acc
*this) {
76 struct gen_p
*accpvt
= (struct gen_p
*)this->private;
80 if (!(pvt
= memget(sizeof *pvt
))) {
84 memset(pvt
, 0, sizeof *pvt
);
85 if (!(ho
= memget(sizeof *ho
))) {
86 memput(pvt
, sizeof *pvt
);
90 memset(ho
, 0x5e, sizeof *ho
);
91 pvt
->rules
= accpvt
->map_rules
[irs_ho
];
92 pvt
->rule
= pvt
->rules
;
95 ho
->byname
= ho_byname
;
96 ho
->byname2
= ho_byname2
;
97 ho
->byaddr
= ho_byaddr
;
99 ho
->rewind
= ho_rewind
;
100 ho
->minimize
= ho_minimize
;
101 ho
->res_get
= ho_res_get
;
102 ho
->res_set
= ho_res_set
;
103 ho
->addrinfo
= ho_addrinfo
;
110 ho_close(struct irs_ho
*this) {
111 struct pvt
*pvt
= (struct pvt
*)this->private;
114 if (pvt
->res
&& pvt
->free_res
)
115 (*pvt
->free_res
)(pvt
->res
);
116 memput(pvt
, sizeof *pvt
);
117 memput(this, sizeof *this);
120 static struct hostent
*
121 ho_byname(struct irs_ho
*this, const char *name
) {
122 struct pvt
*pvt
= (struct pvt
*)this->private;
123 struct irs_rule
*rule
;
124 struct hostent
*rval
;
126 int therrno
= NETDB_INTERNAL
;
129 if (init(this) == -1)
132 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
134 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
136 rval
= (*ho
->byname
)(ho
, name
);
139 if (softerror
== 0 &&
140 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
141 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
143 therrno
= pvt
->res
->res_h_errno
;
145 if (rule
->flags
& IRS_CONTINUE
)
148 * The value TRY_AGAIN can mean that the service
149 * is not available, or just that this particular name
150 * cannot be resolved now. We use the errno ECONNREFUSED
151 * to distinguish. If a lookup sets that errno when
152 * H_ERRNO is TRY_AGAIN, we continue to try other lookup
153 * functions, otherwise we return the TRY_AGAIN error.
155 if (pvt
->res
->res_h_errno
!= TRY_AGAIN
|| errno
!= ECONNREFUSED
)
158 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
159 RES_SET_H_ERRNO(pvt
->res
, therrno
);
163 static struct hostent
*
164 ho_byname2(struct irs_ho
*this, const char *name
, int af
) {
165 struct pvt
*pvt
= (struct pvt
*)this->private;
166 struct irs_rule
*rule
;
167 struct hostent
*rval
;
169 int therrno
= NETDB_INTERNAL
;
172 if (init(this) == -1)
175 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
177 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
179 rval
= (*ho
->byname2
)(ho
, name
, af
);
182 if (softerror
== 0 &&
183 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
184 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
186 therrno
= pvt
->res
->res_h_errno
;
188 if (rule
->flags
& IRS_CONTINUE
)
191 * See the comments in ho_byname() explaining
192 * the interpretation of TRY_AGAIN and ECONNREFUSED.
194 if (pvt
->res
->res_h_errno
!= TRY_AGAIN
|| errno
!= ECONNREFUSED
)
197 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
198 RES_SET_H_ERRNO(pvt
->res
, therrno
);
202 static struct hostent
*
203 ho_byaddr(struct irs_ho
*this, const void *addr
, int len
, int af
) {
204 struct pvt
*pvt
= (struct pvt
*)this->private;
205 struct irs_rule
*rule
;
206 struct hostent
*rval
;
208 int therrno
= NETDB_INTERNAL
;
212 if (init(this) == -1)
215 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
217 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
219 rval
= (*ho
->byaddr
)(ho
, addr
, len
, af
);
222 if (softerror
== 0 &&
223 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
224 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
226 therrno
= pvt
->res
->res_h_errno
;
229 if (rule
->flags
& IRS_CONTINUE
)
232 * See the comments in ho_byname() explaining
233 * the interpretation of TRY_AGAIN and ECONNREFUSED.
235 if (pvt
->res
->res_h_errno
!= TRY_AGAIN
|| errno
!= ECONNREFUSED
)
238 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
239 RES_SET_H_ERRNO(pvt
->res
, therrno
);
243 static struct hostent
*
244 ho_next(struct irs_ho
*this) {
245 struct pvt
*pvt
= (struct pvt
*)this->private;
246 struct hostent
*rval
;
250 ho
= pvt
->rule
->inst
->ho
;
251 rval
= (*ho
->next
)(ho
);
254 if (!(pvt
->rule
->flags
& IRS_CONTINUE
))
256 pvt
->rule
= pvt
->rule
->next
;
258 ho
= pvt
->rule
->inst
->ho
;
266 ho_rewind(struct irs_ho
*this) {
267 struct pvt
*pvt
= (struct pvt
*)this->private;
270 pvt
->rule
= pvt
->rules
;
272 ho
= pvt
->rule
->inst
->ho
;
278 ho_minimize(struct irs_ho
*this) {
279 struct pvt
*pvt
= (struct pvt
*)this->private;
280 struct irs_rule
*rule
;
283 res_nclose(pvt
->res
);
284 for (rule
= pvt
->rules
; rule
!= NULL
; rule
= rule
->next
) {
285 struct irs_ho
*ho
= rule
->inst
->ho
;
291 static struct __res_state
*
292 ho_res_get(struct irs_ho
*this) {
293 struct pvt
*pvt
= (struct pvt
*)this->private;
296 struct __res_state
*res
;
297 res
= (struct __res_state
*)malloc(sizeof *res
);
302 memset(res
, 0, sizeof *res
);
303 ho_res_set(this, res
, free
);
310 ho_res_set(struct irs_ho
*this, struct __res_state
*res
,
311 void (*free_res
)(void *)) {
312 struct pvt
*pvt
= (struct pvt
*)this->private;
313 struct irs_rule
*rule
;
315 if (pvt
->res
&& pvt
->free_res
) {
316 res_nclose(pvt
->res
);
317 (*pvt
->free_res
)(pvt
->res
);
321 pvt
->free_res
= free_res
;
323 for (rule
= pvt
->rules
; rule
!= NULL
; rule
= rule
->next
) {
324 struct irs_ho
*ho
= rule
->inst
->ho
;
326 (*ho
->res_set
)(ho
, pvt
->res
, NULL
);
330 static struct addrinfo
*
331 ho_addrinfo(struct irs_ho
*this, const char *name
, const struct addrinfo
*pai
)
333 struct pvt
*pvt
= (struct pvt
*)this->private;
334 struct irs_rule
*rule
;
335 struct addrinfo
*rval
= NULL
;
337 int therrno
= NETDB_INTERNAL
;
340 if (init(this) == -1)
343 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
345 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
347 if (ho
->addrinfo
== NULL
) /*%< for safety */
349 rval
= (*ho
->addrinfo
)(ho
, name
, pai
);
352 if (softerror
== 0 &&
353 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
354 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
356 therrno
= pvt
->res
->res_h_errno
;
358 if (rule
->flags
& IRS_CONTINUE
)
361 * See the comments in ho_byname() explaining
362 * the interpretation of TRY_AGAIN and ECONNREFUSED.
364 if (pvt
->res
->res_h_errno
!= TRY_AGAIN
||
365 errno
!= ECONNREFUSED
)
368 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
369 RES_SET_H_ERRNO(pvt
->res
, therrno
);
374 init(struct irs_ho
*this) {
375 struct pvt
*pvt
= (struct pvt
*)this->private;
377 if (!pvt
->res
&& !ho_res_get(this))
380 if (((pvt
->res
->options
& RES_INIT
) == 0U) &&
381 (res_ninit(pvt
->res
) == -1))