Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /* 00002 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the project nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 */ 00029 00030 /* 00031 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. 00032 * 00033 * Issues to be discussed: 00034 * - Thread safe-ness must be checked. 00035 * - Return values. There are nonstandard return values defined and used 00036 * in the source code. This is because RFC2133 is silent about which error 00037 * code must be returned for which situation. 00038 * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. 00039 */ 00040 00041 #include "ruby/config.h" 00042 #ifdef RUBY_EXTCONF_H 00043 #include RUBY_EXTCONF_H 00044 #endif 00045 #include <sys/types.h> 00046 #ifndef _WIN32 00047 #include <sys/param.h> 00048 #if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE) 00049 # include <net/socket.h> 00050 #else 00051 # include <sys/socket.h> 00052 #endif 00053 #include <netinet/in.h> 00054 #if defined(HAVE_ARPA_INET_H) 00055 #include <arpa/inet.h> 00056 #endif 00057 #if defined(HAVE_ARPA_NAMESER_H) 00058 #include <arpa/nameser.h> 00059 #endif 00060 #include <netdb.h> 00061 #if defined(HAVE_RESOLV_H) 00062 #ifdef _SX 00063 #include <stdio.h> 00064 #endif 00065 #include <resolv.h> 00066 #endif 00067 #include <unistd.h> 00068 #else 00069 #include <winsock2.h> 00070 #include <ws2tcpip.h> 00071 #include <io.h> 00072 #endif 00073 #include <string.h> 00074 #include <stdio.h> 00075 #include <stdlib.h> 00076 #include <stddef.h> 00077 #include <ctype.h> 00078 00079 #ifdef SOCKS5 00080 #include <socks.h> 00081 #endif 00082 00083 #include "addrinfo.h" 00084 #include "sockport.h" 00085 00086 #define SUCCESS 0 00087 #define ANY 0 00088 #define YES 1 00089 #define NO 0 00090 00091 #ifdef FAITH 00092 static int translate = NO; 00093 static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT; 00094 #endif 00095 00096 static const char in_addrany[] = { 0, 0, 0, 0 }; 00097 static const char in6_addrany[] = { 00098 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 00099 }; 00100 static const char in_loopback[] = { 127, 0, 0, 1 }; 00101 static const char in6_loopback[] = { 00102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 00103 }; 00104 00105 struct sockinet { 00106 u_char si_len; 00107 u_char si_family; 00108 u_short si_port; 00109 }; 00110 00111 static const struct afd { 00112 int a_af; 00113 int a_addrlen; 00114 int a_socklen; 00115 int a_off; 00116 const char *a_addrany; 00117 const char *a_loopback; 00118 } afdl [] = { 00119 #ifdef INET6 00120 #define N_INET6 0 00121 {PF_INET6, sizeof(struct in6_addr), 00122 sizeof(struct sockaddr_in6), 00123 offsetof(struct sockaddr_in6, sin6_addr), 00124 in6_addrany, in6_loopback}, 00125 #define N_INET 1 00126 #else 00127 #define N_INET 0 00128 #endif 00129 {PF_INET, sizeof(struct in_addr), 00130 sizeof(struct sockaddr_in), 00131 offsetof(struct sockaddr_in, sin_addr), 00132 in_addrany, in_loopback}, 00133 {0, 0, 0, 0, NULL, NULL}, 00134 }; 00135 00136 #ifdef INET6 00137 #define PTON_MAX 16 00138 #else 00139 #define PTON_MAX 4 00140 #endif 00141 00142 static int get_name __P((const char *, const struct afd *, 00143 struct addrinfo **, char *, struct addrinfo *, 00144 int)); 00145 static int get_addr __P((const char *, int, struct addrinfo **, 00146 struct addrinfo *, int)); 00147 static int str_isnumber __P((const char *)); 00148 00149 static const char *const ai_errlist[] = { 00150 "success.", 00151 "address family for hostname not supported.", /* EAI_ADDRFAMILY */ 00152 "temporary failure in name resolution.", /* EAI_AGAIN */ 00153 "invalid value for ai_flags.", /* EAI_BADFLAGS */ 00154 "non-recoverable failure in name resolution.", /* EAI_FAIL */ 00155 "ai_family not supported.", /* EAI_FAMILY */ 00156 "memory allocation failure.", /* EAI_MEMORY */ 00157 "no address associated with hostname.", /* EAI_NODATA */ 00158 "hostname nor servname provided, or not known.",/* EAI_NONAME */ 00159 "servname not supported for ai_socktype.", /* EAI_SERVICE */ 00160 "ai_socktype not supported.", /* EAI_SOCKTYPE */ 00161 "system error returned in errno.", /* EAI_SYSTEM */ 00162 "invalid value for hints.", /* EAI_BADHINTS */ 00163 "resolved protocol is unknown.", /* EAI_PROTOCOL */ 00164 "unknown error.", /* EAI_MAX */ 00165 }; 00166 00167 #define GET_CANONNAME(ai, str) \ 00168 if (pai->ai_flags & AI_CANONNAME) {\ 00169 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\ 00170 strcpy((ai)->ai_canonname, (str));\ 00171 } else {\ 00172 error = EAI_MEMORY;\ 00173 goto free;\ 00174 }\ 00175 } 00176 00177 #define GET_AI(ai, afd, addr, port) {\ 00178 char *p;\ 00179 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ 00180 ((afd)->a_socklen)))\ 00181 == NULL) {\ 00182 error = EAI_MEMORY;\ 00183 goto free;\ 00184 }\ 00185 memcpy((ai), pai, sizeof(struct addrinfo));\ 00186 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ 00187 memset((ai)->ai_addr, 0, (afd)->a_socklen);\ 00188 SET_SA_LEN((ai)->ai_addr, (ai)->ai_addrlen = (afd)->a_socklen);\ 00189 (ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\ 00190 ((struct sockinet *)(ai)->ai_addr)->si_port = (port);\ 00191 p = (char *)((ai)->ai_addr);\ 00192 memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\ 00193 } 00194 00195 #define ERR(err) { error = (err); goto bad; } 00196 00197 #ifndef HAVE_GAI_STRERROR 00198 #ifdef GAI_STRERROR_CONST 00199 const 00200 #endif 00201 char * 00202 gai_strerror(int ecode) 00203 { 00204 if (ecode < 0 || ecode > EAI_MAX) 00205 ecode = EAI_MAX; 00206 return (char *)ai_errlist[ecode]; 00207 } 00208 #endif 00209 00210 void 00211 freeaddrinfo(struct addrinfo *ai) 00212 { 00213 struct addrinfo *next; 00214 00215 do { 00216 next = ai->ai_next; 00217 if (ai->ai_canonname) 00218 free(ai->ai_canonname); 00219 /* no need to free(ai->ai_addr) */ 00220 free(ai); 00221 } while ((ai = next) != NULL); 00222 } 00223 00224 static int 00225 str_isnumber(const char *p) 00226 { 00227 char *q = (char *)p; 00228 while (*q) { 00229 if (! isdigit(*q)) 00230 return NO; 00231 q++; 00232 } 00233 return YES; 00234 } 00235 00236 #ifndef HAVE_INET_PTON 00237 00238 static int 00239 inet_pton(int af, const char *hostname, void *pton) 00240 { 00241 struct in_addr in; 00242 00243 #ifdef HAVE_INET_ATON 00244 if (!inet_aton(hostname, &in)) 00245 return 0; 00246 #else 00247 int d1, d2, d3, d4; 00248 char ch; 00249 00250 if (sscanf(hostname, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 && 00251 0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 && 00252 0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) { 00253 in.s_addr = htonl( 00254 ((long) d1 << 24) | ((long) d2 << 16) | 00255 ((long) d3 << 8) | ((long) d4 << 0)); 00256 } 00257 else { 00258 return 0; 00259 } 00260 #endif 00261 memcpy(pton, &in, sizeof(in)); 00262 return 1; 00263 } 00264 #endif 00265 00266 int 00267 getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) 00268 { 00269 struct addrinfo sentinel; 00270 struct addrinfo *top = NULL; 00271 struct addrinfo *cur; 00272 int i, error = 0; 00273 char pton[PTON_MAX]; 00274 struct addrinfo ai; 00275 struct addrinfo *pai; 00276 u_short port; 00277 00278 #ifdef FAITH 00279 static int firsttime = 1; 00280 00281 if (firsttime) { 00282 /* translator hack */ 00283 { 00284 char *q = getenv("GAI"); 00285 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) 00286 translate = YES; 00287 } 00288 firsttime = 0; 00289 } 00290 #endif 00291 00292 /* initialize file static vars */ 00293 sentinel.ai_next = NULL; 00294 cur = &sentinel; 00295 pai = &ai; 00296 pai->ai_flags = 0; 00297 pai->ai_family = PF_UNSPEC; 00298 pai->ai_socktype = ANY; 00299 pai->ai_protocol = ANY; 00300 pai->ai_addrlen = 0; 00301 pai->ai_canonname = NULL; 00302 pai->ai_addr = NULL; 00303 pai->ai_next = NULL; 00304 port = ANY; 00305 00306 if (hostname == NULL && servname == NULL) 00307 return EAI_NONAME; 00308 if (hints) { 00309 /* error check for hints */ 00310 if (hints->ai_addrlen || hints->ai_canonname || 00311 hints->ai_addr || hints->ai_next) 00312 ERR(EAI_BADHINTS); /* xxx */ 00313 if (hints->ai_flags & ~AI_MASK) 00314 ERR(EAI_BADFLAGS); 00315 switch (hints->ai_family) { 00316 case PF_UNSPEC: 00317 case PF_INET: 00318 #ifdef INET6 00319 case PF_INET6: 00320 #endif 00321 break; 00322 default: 00323 ERR(EAI_FAMILY); 00324 } 00325 memcpy(pai, hints, sizeof(*pai)); 00326 switch (pai->ai_socktype) { 00327 case ANY: 00328 switch (pai->ai_protocol) { 00329 case ANY: 00330 break; 00331 case IPPROTO_UDP: 00332 pai->ai_socktype = SOCK_DGRAM; 00333 break; 00334 case IPPROTO_TCP: 00335 pai->ai_socktype = SOCK_STREAM; 00336 break; 00337 default: 00338 #if defined(SOCK_RAW) 00339 pai->ai_socktype = SOCK_RAW; 00340 #endif 00341 break; 00342 } 00343 break; 00344 #if defined(SOCK_RAW) 00345 case SOCK_RAW: 00346 break; 00347 #endif 00348 case SOCK_DGRAM: 00349 if (pai->ai_protocol != IPPROTO_UDP && 00350 pai->ai_protocol != ANY) 00351 ERR(EAI_BADHINTS); /*xxx*/ 00352 pai->ai_protocol = IPPROTO_UDP; 00353 break; 00354 case SOCK_STREAM: 00355 if (pai->ai_protocol != IPPROTO_TCP && 00356 pai->ai_protocol != ANY) 00357 ERR(EAI_BADHINTS); /*xxx*/ 00358 pai->ai_protocol = IPPROTO_TCP; 00359 break; 00360 default: 00361 ERR(EAI_SOCKTYPE); 00362 break; 00363 } 00364 } 00365 00366 /* 00367 * service port 00368 */ 00369 if (servname) { 00370 if (str_isnumber(servname)) { 00371 if (pai->ai_socktype == ANY) { 00372 /* caller accept *ANY* socktype */ 00373 pai->ai_socktype = SOCK_DGRAM; 00374 pai->ai_protocol = IPPROTO_UDP; 00375 } 00376 port = htons((unsigned short)atoi(servname)); 00377 } else if (pai->ai_flags & AI_NUMERICSERV) { 00378 ERR(EAI_NONAME); 00379 } else { 00380 struct servent *sp; 00381 const char *proto; 00382 00383 proto = NULL; 00384 switch (pai->ai_socktype) { 00385 case ANY: 00386 proto = NULL; 00387 break; 00388 case SOCK_DGRAM: 00389 proto = "udp"; 00390 break; 00391 case SOCK_STREAM: 00392 proto = "tcp"; 00393 break; 00394 default: 00395 fprintf(stderr, "panic!\n"); 00396 break; 00397 } 00398 if ((sp = getservbyname((char*)servname, proto)) == NULL) 00399 ERR(EAI_SERVICE); 00400 port = sp->s_port; 00401 if (pai->ai_socktype == ANY) 00402 if (strcmp(sp->s_proto, "udp") == 0) { 00403 pai->ai_socktype = SOCK_DGRAM; 00404 pai->ai_protocol = IPPROTO_UDP; 00405 } else if (strcmp(sp->s_proto, "tcp") == 0) { 00406 pai->ai_socktype = SOCK_STREAM; 00407 pai->ai_protocol = IPPROTO_TCP; 00408 } else 00409 ERR(EAI_PROTOCOL); /*xxx*/ 00410 } 00411 } 00412 00413 /* 00414 * hostname == NULL. 00415 * passive socket -> anyaddr (0.0.0.0 or ::) 00416 * non-passive socket -> localhost (127.0.0.1 or ::1) 00417 */ 00418 if (hostname == NULL) { 00419 const struct afd *afd; 00420 int s; 00421 00422 for (afd = &afdl[0]; afd->a_af; afd++) { 00423 if (!(pai->ai_family == PF_UNSPEC 00424 || pai->ai_family == afd->a_af)) { 00425 continue; 00426 } 00427 00428 /* 00429 * filter out AFs that are not supported by the kernel 00430 * XXX errno? 00431 */ 00432 s = socket(afd->a_af, SOCK_DGRAM, 0); 00433 if (s < 0) 00434 continue; 00435 #if defined(__BEOS__) 00436 closesocket(s); 00437 #else 00438 close(s); 00439 #endif 00440 00441 if (pai->ai_flags & AI_PASSIVE) { 00442 GET_AI(cur->ai_next, afd, afd->a_addrany, port); 00443 /* xxx meaningless? 00444 * GET_CANONNAME(cur->ai_next, "anyaddr"); 00445 */ 00446 } else { 00447 GET_AI(cur->ai_next, afd, afd->a_loopback, 00448 port); 00449 /* xxx meaningless? 00450 * GET_CANONNAME(cur->ai_next, "localhost"); 00451 */ 00452 } 00453 cur = cur->ai_next; 00454 } 00455 top = sentinel.ai_next; 00456 if (top) 00457 goto good; 00458 else 00459 ERR(EAI_FAMILY); 00460 } 00461 00462 /* hostname as numeric name */ 00463 for (i = 0; afdl[i].a_af; i++) { 00464 if (inet_pton(afdl[i].a_af, hostname, pton)) { 00465 u_long v4a; 00466 #ifdef INET6 00467 u_char pfx; 00468 #endif 00469 00470 switch (afdl[i].a_af) { 00471 case AF_INET: 00472 v4a = ((struct in_addr *)pton)->s_addr; 00473 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) 00474 pai->ai_flags &= ~AI_CANONNAME; 00475 v4a >>= IN_CLASSA_NSHIFT; 00476 if (v4a == 0 || v4a == IN_LOOPBACKNET) 00477 pai->ai_flags &= ~AI_CANONNAME; 00478 break; 00479 #ifdef INET6 00480 case AF_INET6: 00481 pfx = ((struct in6_addr *)pton)->s6_addr[0]; 00482 if (pfx == 0 || pfx == 0xfe || pfx == 0xff) 00483 pai->ai_flags &= ~AI_CANONNAME; 00484 break; 00485 #endif 00486 } 00487 00488 if (pai->ai_family == afdl[i].a_af || 00489 pai->ai_family == PF_UNSPEC) { 00490 if (! (pai->ai_flags & AI_CANONNAME)) { 00491 GET_AI(top, &afdl[i], pton, port); 00492 goto good; 00493 } 00494 /* 00495 * if AI_CANONNAME and if reverse lookup 00496 * fail, return ai anyway to pacify 00497 * calling application. 00498 * 00499 * XXX getaddrinfo() is a name->address 00500 * translation function, and it looks strange 00501 * that we do addr->name translation here. 00502 */ 00503 get_name(pton, &afdl[i], &top, pton, pai, port); 00504 goto good; 00505 } else 00506 ERR(EAI_FAMILY); /*xxx*/ 00507 } 00508 } 00509 00510 if (pai->ai_flags & AI_NUMERICHOST) 00511 ERR(EAI_NONAME); 00512 00513 /* hostname as alphabetical name */ 00514 error = get_addr(hostname, pai->ai_family, &top, pai, port); 00515 if (error == 0) { 00516 if (top) { 00517 good: 00518 *res = top; 00519 return SUCCESS; 00520 } else 00521 error = EAI_FAIL; 00522 } 00523 free: 00524 if (top) 00525 freeaddrinfo(top); 00526 bad: 00527 *res = NULL; 00528 return error; 00529 } 00530 00531 static int 00532 get_name(const char *addr, const struct afd *afd, struct addrinfo **res, char *numaddr, struct addrinfo *pai, int port0) 00533 { 00534 u_short port = port0 & 0xffff; 00535 struct hostent *hp; 00536 struct addrinfo *cur; 00537 int error = 0; 00538 #ifdef INET6 00539 int h_error; 00540 #endif 00541 00542 #ifdef INET6 00543 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); 00544 #else 00545 hp = gethostbyaddr((char*)addr, afd->a_addrlen, AF_INET); 00546 #endif 00547 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { 00548 GET_AI(cur, afd, hp->h_addr_list[0], port); 00549 GET_CANONNAME(cur, hp->h_name); 00550 } else 00551 GET_AI(cur, afd, numaddr, port); 00552 00553 #ifdef INET6 00554 if (hp) 00555 freehostent(hp); 00556 #endif 00557 *res = cur; 00558 return SUCCESS; 00559 free: 00560 if (cur) 00561 freeaddrinfo(cur); 00562 #ifdef INET6 00563 if (hp) 00564 freehostent(hp); 00565 #endif 00566 /* bad: */ 00567 *res = NULL; 00568 return error; 00569 } 00570 00571 static int 00572 get_addr(const char *hostname, int af, struct addrinfo **res, struct addrinfo *pai, int port0) 00573 { 00574 u_short port = port0 & 0xffff; 00575 struct addrinfo sentinel; 00576 struct hostent *hp; 00577 struct addrinfo *top, *cur; 00578 const struct afd *afd; 00579 int i, error = 0, h_error; 00580 char *ap; 00581 00582 top = NULL; 00583 sentinel.ai_next = NULL; 00584 cur = &sentinel; 00585 #ifdef INET6 00586 if (af == AF_UNSPEC) { 00587 hp = getipnodebyname(hostname, AF_INET6, 00588 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error); 00589 } else 00590 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error); 00591 #else 00592 hp = gethostbyname((char*)hostname); 00593 h_error = h_errno; 00594 #endif 00595 if (hp == NULL) { 00596 switch (h_error) { 00597 case HOST_NOT_FOUND: 00598 case NO_DATA: 00599 error = EAI_NODATA; 00600 break; 00601 case TRY_AGAIN: 00602 error = EAI_AGAIN; 00603 break; 00604 case NO_RECOVERY: 00605 default: 00606 error = EAI_FAIL; 00607 break; 00608 } 00609 goto bad; 00610 } 00611 00612 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || 00613 (hp->h_addr_list[0] == NULL)) 00614 ERR(EAI_FAIL); 00615 00616 for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) { 00617 switch (af) { 00618 #ifdef INET6 00619 case AF_INET6: 00620 afd = &afdl[N_INET6]; 00621 break; 00622 #endif 00623 #ifndef INET6 00624 default: /* AF_UNSPEC */ 00625 #endif 00626 case AF_INET: 00627 afd = &afdl[N_INET]; 00628 break; 00629 #ifdef INET6 00630 default: /* AF_UNSPEC */ 00631 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { 00632 ap += sizeof(struct in6_addr) - 00633 sizeof(struct in_addr); 00634 afd = &afdl[N_INET]; 00635 } else 00636 afd = &afdl[N_INET6]; 00637 break; 00638 #endif 00639 } 00640 #ifdef FAITH 00641 if (translate && afd->a_af == AF_INET) { 00642 struct in6_addr *in6; 00643 00644 GET_AI(cur->ai_next, &afdl[N_INET6], ap, port); 00645 in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr; 00646 memcpy(&in6->s6_addr, &faith_prefix, 00647 sizeof(struct in6_addr) - sizeof(struct in_addr)); 00648 memcpy(&in6->s6_addr + sizeof(struct in_addr), ap, 00649 sizeof(struct in_addr)); 00650 } else 00651 #endif /* FAITH */ 00652 GET_AI(cur->ai_next, afd, ap, port); 00653 if (cur == &sentinel) { 00654 top = cur->ai_next; 00655 GET_CANONNAME(top, hp->h_name); 00656 } 00657 cur = cur->ai_next; 00658 } 00659 #ifdef INET6 00660 freehostent(hp); 00661 #endif 00662 *res = top; 00663 return SUCCESS; 00664 free: 00665 if (top) 00666 freeaddrinfo(top); 00667 #ifdef INET6 00668 if (hp) 00669 freehostent(hp); 00670 #endif 00671 bad: 00672 *res = NULL; 00673 return error; 00674 } 00675