Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/socket/getaddrinfo.c

Go to the documentation of this file.

    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