1 /* 2 * Copyright 1997-2002 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1996,1999 by Internet Software Consortium. 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 14 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 16 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 17 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 * SOFTWARE. 21 */ 22 23 #pragma ident "%Z%%M% %I% %E% SMI" 24 25 #if defined(LIBC_SCCS) && !defined(lint) 26 static const char rcsid[] = "$Id: gen_ho.c,v 1.16 2001/05/29 05:48:36 marka Exp $"; 27 #endif /* LIBC_SCCS and not lint */ 28 29 /* Imports */ 30 31 #include "port_before.h" 32 33 #include <sys/types.h> 34 35 #include <netinet/in.h> 36 #include <arpa/nameser.h> 37 38 #include <errno.h> 39 #include <stdlib.h> 40 #include <netdb.h> 41 #include <resolv.h> 42 #include <stdio.h> 43 #include <string.h> 44 45 #include <isc/memcluster.h> 46 #include <irs.h> 47 48 #include "port_after.h" 49 50 #include "irs_p.h" 51 #include "gen_p.h" 52 53 /* Definitions */ 54 55 struct pvt { 56 struct irs_rule * rules; 57 struct irs_rule * rule; 58 struct irs_ho * ho; 59 struct __res_state * res; 60 void (*free_res)(void *); 61 }; 62 63 /* Forwards */ 64 65 static void ho_close(struct irs_ho *this); 66 static struct hostent * ho_byname(struct irs_ho *this, const char *name); 67 static struct hostent * ho_byname2(struct irs_ho *this, const char *name, 68 int af); 69 static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr, 70 int len, int af); 71 static struct hostent * ho_next(struct irs_ho *this); 72 static void ho_rewind(struct irs_ho *this); 73 static void ho_minimize(struct irs_ho *this); 74 static struct __res_state * ho_res_get(struct irs_ho *this); 75 static void ho_res_set(struct irs_ho *this, 76 struct __res_state *res, 77 void (*free_res)(void *)); 78 static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name, 79 const struct addrinfo *pai); 80 81 static int init(struct irs_ho *this); 82 83 /* Exports */ 84 85 struct irs_ho * 86 irs_gen_ho(struct irs_acc *this) { 87 struct gen_p *accpvt = (struct gen_p *)this->private; 88 struct irs_ho *ho; 89 struct pvt *pvt; 90 91 if (!(pvt = memget(sizeof *pvt))) { 92 errno = ENOMEM; 93 return (NULL); 94 } 95 memset(pvt, 0, sizeof *pvt); 96 if (!(ho = memget(sizeof *ho))) { 97 memput(pvt, sizeof *pvt); 98 errno = ENOMEM; 99 return (NULL); 100 } 101 memset(ho, 0x5e, sizeof *ho); 102 pvt->rules = accpvt->map_rules[irs_ho]; 103 pvt->rule = pvt->rules; 104 ho->private = pvt; 105 ho->close = ho_close; 106 ho->byname = ho_byname; 107 ho->byname2 = ho_byname2; 108 ho->byaddr = ho_byaddr; 109 ho->next = ho_next; 110 ho->rewind = ho_rewind; 111 ho->minimize = ho_minimize; 112 ho->res_get = ho_res_get; 113 ho->res_set = ho_res_set; 114 ho->addrinfo = ho_addrinfo; 115 return (ho); 116 } 117 118 /* Methods. */ 119 120 static void 121 ho_close(struct irs_ho *this) { 122 struct pvt *pvt = (struct pvt *)this->private; 123 124 ho_minimize(this); 125 if (pvt->res && pvt->free_res) 126 (*pvt->free_res)(pvt->res); 127 memput(pvt, sizeof *pvt); 128 memput(this, sizeof *this); 129 } 130 131 static struct hostent * 132 ho_byname(struct irs_ho *this, const char *name) { 133 struct pvt *pvt = (struct pvt *)this->private; 134 struct irs_rule *rule; 135 struct hostent *rval; 136 struct irs_ho *ho; 137 int therrno = NETDB_INTERNAL; 138 int softerror = 0; 139 140 if (init(this) == -1) 141 return (NULL); 142 143 for (rule = pvt->rules; rule; rule = rule->next) { 144 ho = rule->inst->ho; 145 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 146 errno = 0; 147 rval = (*ho->byname)(ho, name); 148 if (rval != NULL) 149 return (rval); 150 if (softerror == 0 && 151 pvt->res->res_h_errno != HOST_NOT_FOUND && 152 pvt->res->res_h_errno != NETDB_INTERNAL) { 153 softerror = 1; 154 therrno = pvt->res->res_h_errno; 155 } 156 if (rule->flags & IRS_CONTINUE) 157 continue; 158 /* 159 * The value TRY_AGAIN can mean that the service 160 * is not available, or just that this particular name 161 * cannot be resolved now. We use the errno ECONNREFUSED 162 * to distinguish. If a lookup sets that errno when 163 * H_ERRNO is TRY_AGAIN, we continue to try other lookup 164 * functions, otherwise we return the TRY_AGAIN error. 165 */ 166 if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED) 167 break; 168 } 169 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) 170 RES_SET_H_ERRNO(pvt->res, therrno); 171 return (NULL); 172 } 173 174 static struct hostent * 175 ho_byname2(struct irs_ho *this, const char *name, int af) { 176 struct pvt *pvt = (struct pvt *)this->private; 177 struct irs_rule *rule; 178 struct hostent *rval; 179 struct irs_ho *ho; 180 int therrno = NETDB_INTERNAL; 181 int softerror = 0; 182 183 if (init(this) == -1) 184 return (NULL); 185 186 for (rule = pvt->rules; rule; rule = rule->next) { 187 ho = rule->inst->ho; 188 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 189 errno = 0; 190 rval = (*ho->byname2)(ho, name, af); 191 if (rval != NULL) 192 return (rval); 193 if (softerror == 0 && 194 pvt->res->res_h_errno != HOST_NOT_FOUND && 195 pvt->res->res_h_errno != NETDB_INTERNAL) { 196 softerror = 1; 197 therrno = pvt->res->res_h_errno; 198 } 199 if (rule->flags & IRS_CONTINUE) 200 continue; 201 /* 202 * See the comments in ho_byname() explaining 203 * the interpretation of TRY_AGAIN and ECONNREFUSED. 204 */ 205 if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED) 206 break; 207 } 208 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) 209 RES_SET_H_ERRNO(pvt->res, therrno); 210 return (NULL); 211 } 212 213 static struct hostent * 214 ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) { 215 struct pvt *pvt = (struct pvt *)this->private; 216 struct irs_rule *rule; 217 struct hostent *rval; 218 struct irs_ho *ho; 219 int therrno = NETDB_INTERNAL; 220 int softerror = 0; 221 222 223 if (init(this) == -1) 224 return (NULL); 225 226 for (rule = pvt->rules; rule; rule = rule->next) { 227 ho = rule->inst->ho; 228 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 229 errno = 0; 230 rval = (*ho->byaddr)(ho, addr, len, af); 231 if (rval != NULL) 232 return (rval); 233 if (softerror == 0 && 234 pvt->res->res_h_errno != HOST_NOT_FOUND && 235 pvt->res->res_h_errno != NETDB_INTERNAL) { 236 softerror = 1; 237 therrno = pvt->res->res_h_errno; 238 } 239 240 if (rule->flags & IRS_CONTINUE) 241 continue; 242 /* 243 * See the comments in ho_byname() explaining 244 * the interpretation of TRY_AGAIN and ECONNREFUSED. 245 */ 246 if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED) 247 break; 248 } 249 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) 250 RES_SET_H_ERRNO(pvt->res, therrno); 251 return (NULL); 252 } 253 254 static struct hostent * 255 ho_next(struct irs_ho *this) { 256 struct pvt *pvt = (struct pvt *)this->private; 257 struct hostent *rval; 258 struct irs_ho *ho; 259 260 while (pvt->rule) { 261 ho = pvt->rule->inst->ho; 262 rval = (*ho->next)(ho); 263 if (rval) 264 return (rval); 265 if (!(pvt->rule->flags & IRS_CONTINUE)) 266 break; 267 pvt->rule = pvt->rule->next; 268 if (pvt->rule) { 269 ho = pvt->rule->inst->ho; 270 (*ho->rewind)(ho); 271 } 272 } 273 return (NULL); 274 } 275 276 static void 277 ho_rewind(struct irs_ho *this) { 278 struct pvt *pvt = (struct pvt *)this->private; 279 struct irs_ho *ho; 280 281 pvt->rule = pvt->rules; 282 if (pvt->rule) { 283 ho = pvt->rule->inst->ho; 284 (*ho->rewind)(ho); 285 } 286 } 287 288 static void 289 ho_minimize(struct irs_ho *this) { 290 struct pvt *pvt = (struct pvt *)this->private; 291 struct irs_rule *rule; 292 293 if (pvt->res) 294 res_nclose(pvt->res); 295 for (rule = pvt->rules; rule != NULL; rule = rule->next) { 296 struct irs_ho *ho = rule->inst->ho; 297 298 (*ho->minimize)(ho); 299 } 300 } 301 302 static struct __res_state * 303 ho_res_get(struct irs_ho *this) { 304 struct pvt *pvt = (struct pvt *)this->private; 305 306 if (!pvt->res) { 307 struct __res_state *res; 308 res = (struct __res_state *)malloc(sizeof *res); 309 if (!res) { 310 errno = ENOMEM; 311 return (NULL); 312 } 313 memset(res, 0, sizeof *res); 314 ho_res_set(this, res, free); 315 } 316 317 return (pvt->res); 318 } 319 320 static void 321 ho_res_set(struct irs_ho *this, struct __res_state *res, 322 void (*free_res)(void *)) { 323 struct pvt *pvt = (struct pvt *)this->private; 324 struct irs_rule *rule; 325 326 if (pvt->res && pvt->free_res) { 327 res_nclose(pvt->res); 328 (*pvt->free_res)(pvt->res); 329 } 330 331 pvt->res = res; 332 pvt->free_res = free_res; 333 334 for (rule = pvt->rules; rule != NULL; rule = rule->next) { 335 struct irs_ho *ho = rule->inst->ho; 336 337 (*ho->res_set)(ho, pvt->res, NULL); 338 } 339 } 340 341 static struct addrinfo * 342 ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai) 343 { 344 struct pvt *pvt = (struct pvt *)this->private; 345 struct irs_rule *rule; 346 struct addrinfo *rval = NULL; 347 struct irs_ho *ho; 348 int therrno = NETDB_INTERNAL; 349 int softerror = 0; 350 351 if (init(this) == -1) 352 return (NULL); 353 354 for (rule = pvt->rules; rule; rule = rule->next) { 355 ho = rule->inst->ho; 356 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 357 errno = 0; 358 if (ho->addrinfo == NULL) /* for safety */ 359 continue; 360 rval = (*ho->addrinfo)(ho, name, pai); 361 if (rval != NULL) 362 return (rval); 363 if (softerror == 0 && 364 pvt->res->res_h_errno != HOST_NOT_FOUND && 365 pvt->res->res_h_errno != NETDB_INTERNAL) { 366 softerror = 1; 367 therrno = pvt->res->res_h_errno; 368 } 369 if (rule->flags & IRS_CONTINUE) 370 continue; 371 /* 372 * See the comments in ho_byname() explaining 373 * the interpretation of TRY_AGAIN and ECONNREFUSED. 374 */ 375 if (pvt->res->res_h_errno != TRY_AGAIN || 376 errno != ECONNREFUSED) 377 break; 378 } 379 if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND) 380 RES_SET_H_ERRNO(pvt->res, therrno); 381 if (rval) 382 freeaddrinfo(rval); 383 return (NULL); 384 } 385 386 static int 387 init(struct irs_ho *this) { 388 struct pvt *pvt = (struct pvt *)this->private; 389 390 if (!pvt->res && !ho_res_get(this)) 391 return (-1); 392 393 if (((pvt->res->options & RES_INIT) == 0) && 394 (res_ninit(pvt->res) == -1)) 395 return (-1); 396 397 return (0); 398 } 399