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 */
26 #include "port_before.h"
28 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <arpa/nameser.h>
40 #include <isc/memcluster.h>
43 #include "port_after.h"
51 struct irs_rule
* rules
;
52 struct irs_rule
* rule
;
54 struct __res_state
* res
;
55 void (*free_res
)(void *);
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
,
64 static struct hostent
* ho_byaddr(struct irs_ho
*this, const void *addr
,
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);
81 irs_gen_ho(struct irs_acc
*this) {
82 struct gen_p
*accpvt
= (struct gen_p
*)this->private;
86 if (!(pvt
= memget(sizeof *pvt
))) {
90 memset(pvt
, 0, sizeof *pvt
);
91 if (!(ho
= memget(sizeof *ho
))) {
92 memput(pvt
, sizeof *pvt
);
96 memset(ho
, 0x5e, sizeof *ho
);
97 pvt
->rules
= accpvt
->map_rules
[irs_ho
];
98 pvt
->rule
= pvt
->rules
;
100 ho
->close
= ho_close
;
101 ho
->byname
= ho_byname
;
102 ho
->byname2
= ho_byname2
;
103 ho
->byaddr
= ho_byaddr
;
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
;
116 ho_close(struct irs_ho
*this) {
117 struct pvt
*pvt
= (struct pvt
*)this->private;
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
;
132 int therrno
= NETDB_INTERNAL
;
135 if (init(this) == -1)
138 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
140 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
142 rval
= (*ho
->byname
)(ho
, name
);
145 if (softerror
== 0 &&
146 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
147 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
149 therrno
= pvt
->res
->res_h_errno
;
151 if (rule
->flags
& IRS_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
)
164 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
165 RES_SET_H_ERRNO(pvt
->res
, therrno
);
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
;
175 int therrno
= NETDB_INTERNAL
;
178 if (init(this) == -1)
181 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
183 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
185 rval
= (*ho
->byname2
)(ho
, name
, af
);
188 if (softerror
== 0 &&
189 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
190 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
192 therrno
= pvt
->res
->res_h_errno
;
194 if (rule
->flags
& IRS_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
)
203 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
204 RES_SET_H_ERRNO(pvt
->res
, therrno
);
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
;
214 int therrno
= NETDB_INTERNAL
;
218 if (init(this) == -1)
221 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
223 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
225 rval
= (*ho
->byaddr
)(ho
, addr
, len
, af
);
228 if (softerror
== 0 &&
229 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
230 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
232 therrno
= pvt
->res
->res_h_errno
;
235 if (rule
->flags
& IRS_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
)
244 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
245 RES_SET_H_ERRNO(pvt
->res
, therrno
);
249 static struct hostent
*
250 ho_next(struct irs_ho
*this) {
251 struct pvt
*pvt
= (struct pvt
*)this->private;
252 struct hostent
*rval
;
256 ho
= pvt
->rule
->inst
->ho
;
257 rval
= (*ho
->next
)(ho
);
260 if (!(pvt
->rule
->flags
& IRS_CONTINUE
))
262 pvt
->rule
= pvt
->rule
->next
;
264 ho
= pvt
->rule
->inst
->ho
;
272 ho_rewind(struct irs_ho
*this) {
273 struct pvt
*pvt
= (struct pvt
*)this->private;
276 pvt
->rule
= pvt
->rules
;
278 ho
= pvt
->rule
->inst
->ho
;
284 ho_minimize(struct irs_ho
*this) {
285 struct pvt
*pvt
= (struct pvt
*)this->private;
286 struct irs_rule
*rule
;
289 res_nclose(pvt
->res
);
290 for (rule
= pvt
->rules
; rule
!= NULL
; rule
= rule
->next
) {
291 struct irs_ho
*ho
= rule
->inst
->ho
;
297 static struct __res_state
*
298 ho_res_get(struct irs_ho
*this) {
299 struct pvt
*pvt
= (struct pvt
*)this->private;
302 struct __res_state
*res
;
303 res
= (struct __res_state
*)malloc(sizeof *res
);
308 memset(res
, 0, sizeof *res
);
309 ho_res_set(this, res
, free
);
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
);
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
;
343 int therrno
= NETDB_INTERNAL
;
346 if (init(this) == -1)
349 for (rule
= pvt
->rules
; rule
; rule
= rule
->next
) {
351 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
353 if (ho
->addrinfo
== NULL
) /*%< for safety */
355 rval
= (*ho
->addrinfo
)(ho
, name
, pai
);
358 if (softerror
== 0 &&
359 pvt
->res
->res_h_errno
!= HOST_NOT_FOUND
&&
360 pvt
->res
->res_h_errno
!= NETDB_INTERNAL
) {
362 therrno
= pvt
->res
->res_h_errno
;
364 if (rule
->flags
& IRS_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
)
374 if (softerror
!= 0 && pvt
->res
->res_h_errno
== HOST_NOT_FOUND
)
375 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))