]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
missing files
authorTatuya JINMEI 神明達哉 <jinmei@isc.org>
Wed, 12 May 2004 07:06:40 +0000 (07:06 +0000)
committerTatuya JINMEI 神明達哉 <jinmei@isc.org>
Wed, 12 May 2004 07:06:40 +0000 (07:06 +0000)
contrib/queryperf/missing/addrinfo.h [new file with mode: 0644]
contrib/queryperf/missing/getaddrinfo.c [new file with mode: 0644]
contrib/queryperf/missing/getnameinfo.c [new file with mode: 0644]

diff --git a/contrib/queryperf/missing/addrinfo.h b/contrib/queryperf/missing/addrinfo.h
new file mode 100644 (file)
index 0000000..54a5e85
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef HAVE_GETADDRINFO
+
+/*
+ * Error return codes from getaddrinfo()
+ */
+#define        EAI_ADDRFAMILY   1      /* address family for hostname not supported */
+#define        EAI_AGAIN        2      /* temporary failure in name resolution */
+#define        EAI_BADFLAGS     3      /* invalid value for ai_flags */
+#define        EAI_FAIL         4      /* non-recoverable failure in name resolution */
+#define        EAI_FAMILY       5      /* ai_family not supported */
+#define        EAI_MEMORY       6      /* memory allocation failure */
+#define        EAI_NODATA       7      /* no address associated with hostname */
+#define        EAI_NONAME       8      /* hostname nor servname provided, or not known */
+#define        EAI_SERVICE      9      /* servname not supported for ai_socktype */
+#define        EAI_SOCKTYPE    10      /* ai_socktype not supported */
+#define        EAI_SYSTEM      11      /* system error returned in errno */
+#define EAI_BADHINTS   12
+#define EAI_PROTOCOL   13
+#define EAI_MAX                14
+
+/*
+ * Flag values for getaddrinfo()
+ */
+#define        AI_PASSIVE      0x00000001 /* get address to use bind() */
+#define        AI_CANONNAME    0x00000002 /* fill ai_canonname */
+#define        AI_NUMERICHOST  0x00000004 /* prevent name resolution */
+/* valid flags for addrinfo */
+#define        AI_MASK         (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
+
+#define        AI_ALL          0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */
+#define        AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */
+#define        AI_ADDRCONFIG   0x00000400 /* only if any address is assigned */
+#define        AI_V4MAPPED     0x00000800 /* accept IPv4-mapped IPv6 address */
+/* special recommended flags for getipnodebyname */
+#define        AI_DEFAULT      (AI_V4MAPPED_CFG | AI_ADDRCONFIG)
+
+/*
+ * Constants for getnameinfo()
+ */
+#define        NI_MAXHOST      1025
+#define        NI_MAXSERV      32
+
+/*
+ * Flag values for getnameinfo()
+ */
+#define        NI_NOFQDN       0x00000001
+#define        NI_NUMERICHOST  0x00000002
+#define        NI_NAMEREQD     0x00000004
+#define        NI_NUMERICSERV  0x00000008
+#define        NI_DGRAM        0x00000010
+
+struct addrinfo {
+       int     ai_flags;       /* AI_PASSIVE, AI_CANONNAME */
+       int     ai_family;      /* PF_xxx */
+       int     ai_socktype;    /* SOCK_xxx */
+       int     ai_protocol;    /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+       size_t  ai_addrlen;     /* length of ai_addr */
+       char    *ai_canonname;  /* canonical name for hostname */
+       struct sockaddr *ai_addr;       /* binary address */
+       struct addrinfo *ai_next;       /* next structure in linked list */
+};
+
+struct sockaddr_storage {
+       u_char __ss_len;
+       u_char __ss_family;
+       u_char fill[126];
+};
+
+extern void freehostent(struct hostent *);
+extern char *gai_strerror(int);
+#endif
diff --git a/contrib/queryperf/missing/getaddrinfo.c b/contrib/queryperf/missing/getaddrinfo.c
new file mode 100644 (file)
index 0000000..69eb748
--- /dev/null
@@ -0,0 +1,632 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "addrinfo.h"
+
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO  0
+
+static const char in_addrany[] = { 0, 0, 0, 0 };
+static const char in6_addrany[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+static const char in_loopback[] = { 127, 0, 0, 1 }; 
+static const char in6_loopback[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+};
+
+struct sockinet {
+       u_char  si_len;
+       u_char  si_family;
+       u_short si_port;
+};
+
+static struct afd {
+       int a_af;
+       int a_addrlen;
+       int a_socklen;
+       int a_off;
+       const char *a_addrany;
+       const char *a_loopback; 
+} afdl [] = {
+#ifdef INET6
+#define N_INET6 0
+       {PF_INET6, sizeof(struct in6_addr),
+        sizeof(struct sockaddr_in6),
+        offsetof(struct sockaddr_in6, sin6_addr),
+        in6_addrany, in6_loopback},
+#define N_INET  1
+#else
+#define N_INET  0
+#endif
+       {PF_INET, sizeof(struct in_addr),
+        sizeof(struct sockaddr_in),
+        offsetof(struct sockaddr_in, sin_addr),
+        in_addrany, in_loopback},
+       {0, 0, 0, 0, NULL, NULL},
+};
+
+#ifdef INET6
+#define PTON_MAX       16
+#else
+#define PTON_MAX       4
+#endif
+
+
+static int get_name(const char *, struct afd *,
+                   struct addrinfo **, char *, struct addrinfo *,
+                   int);
+static int get_addr(const char *, int, struct addrinfo **,
+                   struct addrinfo *, int);
+static int get_addr0(const char *, int, struct addrinfo **,
+                    struct addrinfo *, int);
+static int str_isnumber(const char *);
+       
+static char *ai_errlist[] = {
+       "Success",
+       "Address family for hostname not supported",    /* EAI_ADDRFAMILY */
+       "Temporary failure in name resolution",         /* EAI_AGAIN      */
+       "Invalid value for ai_flags",                   /* EAI_BADFLAGS   */
+       "Non-recoverable failure in name resolution",   /* EAI_FAIL       */
+       "ai_family not supported",                      /* EAI_FAMILY     */
+       "Memory allocation failure",                    /* EAI_MEMORY     */
+       "No address associated with hostname",          /* EAI_NODATA     */
+       "hostname nor servname provided, or not known",/* EAI_NONAME     */
+       "servname not supported for ai_socktype",       /* EAI_SERVICE    */
+       "ai_socktype not supported",                    /* EAI_SOCKTYPE   */
+       "System error returned in errno",               /* EAI_SYSTEM     */
+       "Invalid value for hints",                      /* EAI_BADHINTS   */
+       "Resolved protocol is unknown",                 /* EAI_PROTOCOL   */
+       "Unknown error",                                /* EAI_MAX        */
+};
+
+#define GET_CANONNAME(ai, str) \
+if (pai->ai_flags & AI_CANONNAME) {\
+       if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
+               strcpy((ai)->ai_canonname, (str));\
+       } else {\
+               error = EAI_MEMORY;\
+               goto free;\
+       }\
+}
+
+#ifdef HAVE_SA_LEN
+#define        SET_AILEN(ai,l) (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (l)
+#else
+#define        SET_AILEN(ai,l) (ai)->ai_addrlen = (l)
+#endif
+
+#define GET_AI(ai, afd, addr, port) {\
+       char *p;\
+       if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
+                                             ((afd)->a_socklen)))\
+           == NULL) {\
+               error = EAI_MEMORY;\
+               goto free;\
+       }\
+       memcpy(ai, pai, sizeof(struct addrinfo));\
+       (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
+       memset((ai)->ai_addr, 0, (afd)->a_socklen);\
+       SET_AILEN((ai), (afd)->a_socklen);\
+       (ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\
+       ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
+       p = (char *)((ai)->ai_addr);\
+       memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\
+}
+
+#define ERR(err) { error = (err); goto bad; }
+
+char *
+gai_strerror(ecode)
+       int ecode;
+{
+       if (ecode < 0 || ecode > EAI_MAX)
+               ecode = EAI_MAX;
+       return ai_errlist[ecode];
+}
+
+void
+freeaddrinfo(ai)
+       struct addrinfo *ai;
+{
+       struct addrinfo *next;
+
+       do {
+               next = ai->ai_next;
+               if (ai->ai_canonname)
+                       free(ai->ai_canonname);
+               /* no need to free(ai->ai_addr) */
+               free(ai);
+       } while ((ai = next) != NULL);
+}
+
+static int
+str_isnumber(p)
+       const char *p;
+{
+       char *q = (char *)p;
+       while (*q) {
+               if (! isdigit(*q))
+                       return NO;
+               q++;
+       }
+       return YES;
+}
+
+int
+getaddrinfo(hostname, servname, hints, res)
+       const char *hostname, *servname;
+       const struct addrinfo *hints;
+       struct addrinfo **res;
+{
+       struct addrinfo sentinel;
+       struct addrinfo *top = NULL;
+       struct addrinfo *cur;
+       int i, error = 0;
+       char pton[PTON_MAX];
+       struct addrinfo ai;
+       struct addrinfo *pai;
+       u_short port;
+
+       /* initialize file static vars */
+       sentinel.ai_next = NULL;
+       cur = &sentinel;
+       pai = &ai;
+       pai->ai_flags = 0;
+       pai->ai_family = PF_UNSPEC;
+       pai->ai_socktype = ANY;
+       pai->ai_protocol = ANY;
+       pai->ai_addrlen = 0;
+       pai->ai_canonname = NULL;
+       pai->ai_addr = NULL;
+       pai->ai_next = NULL;
+       port = ANY;
+       
+       if (hostname == NULL && servname == NULL)
+               return EAI_NONAME;
+       if (hints) {
+               /* error check for hints */
+               if (hints->ai_addrlen || hints->ai_canonname ||
+                   hints->ai_addr || hints->ai_next)
+                       ERR(EAI_BADHINTS); /* xxx */
+               if (hints->ai_flags & ~AI_MASK)
+                       ERR(EAI_BADFLAGS);
+               switch (hints->ai_family) {
+               case PF_UNSPEC:
+               case PF_INET:
+#ifdef INET6
+               case PF_INET6:
+#endif
+                       break;
+               default:
+                       ERR(EAI_FAMILY);
+               }
+               memcpy(pai, hints, sizeof(*pai));
+               switch (pai->ai_socktype) {
+               case ANY:
+                       switch (pai->ai_protocol) {
+                       case ANY:
+                               break;
+                       case IPPROTO_UDP:
+                               pai->ai_socktype = SOCK_DGRAM;
+                               break;
+                       case IPPROTO_TCP:
+                               pai->ai_socktype = SOCK_STREAM;
+                               break;
+                       default:
+                               pai->ai_socktype = SOCK_RAW;
+                               break;
+                       }
+                       break;
+               case SOCK_RAW:
+                       break;
+               case SOCK_DGRAM:
+                       if (pai->ai_protocol != IPPROTO_UDP &&
+                           pai->ai_protocol != ANY)
+                               ERR(EAI_BADHINTS);      /*xxx*/
+                       pai->ai_protocol = IPPROTO_UDP;
+                       break;
+               case SOCK_STREAM:
+                       if (pai->ai_protocol != IPPROTO_TCP &&
+                           pai->ai_protocol != ANY)
+                               ERR(EAI_BADHINTS);      /*xxx*/
+                       pai->ai_protocol = IPPROTO_TCP;
+                       break;
+               default:
+                       ERR(EAI_SOCKTYPE);
+                       break;
+               }
+       }
+
+       /*
+        * service port
+        */
+       if (servname) {
+               if (str_isnumber(servname)) {
+                       if (pai->ai_socktype == ANY) {
+                               /* caller accept *ANY* socktype */
+                               pai->ai_socktype = SOCK_DGRAM;
+                               pai->ai_protocol = IPPROTO_UDP;
+                       }
+                       port = htons(atoi(servname));
+               } else {
+                       struct servent *sp;
+                       char *proto;
+
+                       proto = NULL;
+                       switch (pai->ai_socktype) {
+                       case ANY:
+                               proto = NULL;
+                               break;
+                       case SOCK_DGRAM:
+                               proto = "udp";
+                               break;
+                       case SOCK_STREAM:
+                               proto = "tcp";
+                               break;
+                       default:
+                               fprintf(stderr, "panic!\n");
+                               break;
+                       }
+                       if ((sp = getservbyname(servname, proto)) == NULL)
+                               ERR(EAI_SERVICE);
+                       port = sp->s_port;
+                       if (pai->ai_socktype == ANY) {
+                               if (strcmp(sp->s_proto, "udp") == 0) {
+                                       pai->ai_socktype = SOCK_DGRAM;
+                                       pai->ai_protocol = IPPROTO_UDP;
+                               } else if (strcmp(sp->s_proto, "tcp") == 0) {
+                                       pai->ai_socktype = SOCK_STREAM;
+                                       pai->ai_protocol = IPPROTO_TCP;
+                               } else
+                                       ERR(EAI_PROTOCOL);      /*xxx*/
+                       }
+               }
+       }
+       
+       /*
+        * hostname == NULL.
+        * passive socket -> anyaddr (0.0.0.0 or ::)
+        * non-passive socket -> localhost (127.0.0.1 or ::1)
+        */
+       if (hostname == NULL) {
+               struct afd *afd;
+               int s;
+
+               for (afd = &afdl[0]; afd->a_af; afd++) {
+                       if (!(pai->ai_family == PF_UNSPEC
+                          || pai->ai_family == afd->a_af)) {
+                               continue;
+                       }
+
+                       /*
+                        * filter out AFs that are not supported by the kernel
+                        * XXX errno?
+                        */
+                       s = socket(afd->a_af, SOCK_DGRAM, 0);
+                       if (s < 0)
+                               continue;
+                       close(s);
+
+                       if (pai->ai_flags & AI_PASSIVE) {
+                               GET_AI(cur->ai_next, afd, afd->a_addrany, port);
+                               /* xxx meaningless?
+                                * GET_CANONNAME(cur->ai_next, "anyaddr");
+                                */
+                       } else {
+                               GET_AI(cur->ai_next, afd, afd->a_loopback,
+                                       port);
+                               /* xxx meaningless?
+                                * GET_CANONNAME(cur->ai_next, "localhost");
+                                */
+                       }
+                       cur = cur->ai_next;
+               }
+               top = sentinel.ai_next;
+               if (top)
+                       goto good;
+               else
+                       ERR(EAI_FAMILY);
+       }
+       
+       /* hostname as numeric name */
+       for (i = 0; afdl[i].a_af; i++) {
+               if (inet_pton(afdl[i].a_af, hostname, pton) == 1) {
+                       u_long v4a;
+                       u_char pfx;
+
+                       switch (afdl[i].a_af) {
+                       case AF_INET:
+                               v4a = ntohl(((struct in_addr *)pton)->s_addr);
+                               if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+                                       pai->ai_flags &= ~AI_CANONNAME;
+                               v4a >>= IN_CLASSA_NSHIFT;
+                               if (v4a == 0 || v4a == IN_LOOPBACKNET)
+                                       pai->ai_flags &= ~AI_CANONNAME;
+                               break;
+#ifdef INET6
+                       case AF_INET6:
+                               pfx = ((struct in6_addr *)pton)->s6_addr[0];
+                               if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
+                                       pai->ai_flags &= ~AI_CANONNAME;
+                               break;
+#endif
+                       }
+                       
+                       if (pai->ai_family == afdl[i].a_af ||
+                           pai->ai_family == PF_UNSPEC) {
+                               if (! (pai->ai_flags & AI_CANONNAME)) {
+                                       GET_AI(top, &afdl[i], pton, port);
+                                       goto good;
+                               }
+                               /*
+                                * if AI_CANONNAME and if reverse lookup
+                                * fail, return ai anyway to pacify
+                                * calling application.
+                                *
+                                * XXX getaddrinfo() is a name->address
+                                * translation function, and it looks strange
+                                * that we do addr->name translation here.
+                                */
+                               get_name(pton, &afdl[i], &top, pton, pai, port);
+                               goto good;
+                       } else 
+                               ERR(EAI_FAMILY);        /*xxx*/
+               }
+       }
+
+       if (pai->ai_flags & AI_NUMERICHOST)
+               ERR(EAI_NONAME);
+
+       /* hostname as alphabetical name */
+       error = get_addr(hostname, pai->ai_family, &top, pai, port);
+       if (error == 0) {
+               if (top) {
+ good:
+                       *res = top;
+                       return SUCCESS;
+               } else
+                       error = EAI_FAIL;
+       }
+ free:
+       if (top)
+               freeaddrinfo(top);
+ bad:
+       *res = NULL;
+       return error;
+}
+
+static int
+get_name(addr, afd, res, numaddr, pai, port0)
+       const char *addr;
+       struct afd *afd;
+       struct addrinfo **res;
+       char *numaddr;
+       struct addrinfo *pai;
+       int port0;
+{
+       u_short port = port0 & 0xffff;
+       struct hostent *hp;
+       struct addrinfo *cur;
+       int error = 0;
+       hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
+       if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
+               GET_AI(cur, afd, hp->h_addr_list[0], port);
+               GET_CANONNAME(cur, hp->h_name);
+       } else
+               GET_AI(cur, afd, numaddr, port);
+       
+       *res = cur;
+       return SUCCESS;
+ free:
+       if (cur)
+               freeaddrinfo(cur);
+
+ /* bad: */
+       *res = NULL;
+       return error;
+}
+
+static int
+get_addr(hostname, af, res0, pai, port0)
+       const char *hostname;
+       int af;
+       struct addrinfo **res0;
+       struct addrinfo *pai;
+       int port0;
+{
+       int i, error, ekeep;
+       struct addrinfo *cur;
+       struct addrinfo **res;
+       int retry;
+       int s;
+
+       res = res0;
+       ekeep = 0;
+       error = 0;
+       for (i = 0; afdl[i].a_af; i++) {
+               retry = 0;
+               if (af == AF_UNSPEC) {
+                       /*
+                        * filter out AFs that are not supported by the kernel
+                        * XXX errno?
+                        */
+                       s = socket(afdl[i].a_af, SOCK_DGRAM, 0);
+                       if (s < 0)
+                               continue;
+                       close(s);
+               } else {
+                       if (af != afdl[i].a_af)
+                               continue;
+               }
+               /* It is WRONG, we need getipnodebyname(). */
+again:
+               error = get_addr0(hostname, afdl[i].a_af, res, pai, port0);
+               switch (error) {
+               case EAI_AGAIN:
+                       if (++retry < 3)
+                               goto again;
+                       /* FALL THROUGH*/
+               default:
+                       if (ekeep == 0)
+                               ekeep = error;
+                       break;
+               }
+               if (*res) {
+                       /* make chain of addrs */
+                       for (cur = *res;
+                            cur && cur->ai_next;
+                            cur = cur->ai_next)
+                               ;
+                       if (!cur)
+                               return EAI_FAIL;
+                       res = &cur->ai_next;
+               }
+       }
+
+       /* if we got something, it's okay */
+       if (*res0)
+               return 0;
+
+       return error ? error : ekeep;
+}
+
+static int
+get_addr0(hostname, af, res, pai, port0)
+       const char *hostname;
+       int af;
+       struct addrinfo **res;
+       struct addrinfo *pai;
+       int port0;
+{
+       u_short port = port0 & 0xffff;
+       struct addrinfo sentinel;
+       struct hostent *hp;
+       struct addrinfo *top, *cur;
+       struct afd *afd;
+       int i, error = 0, h_error;
+       char *ap;
+
+       top = NULL;
+       sentinel.ai_next = NULL;
+       cur = &sentinel;
+
+#ifdef HAVE_GETHOSTBYNAME2
+       if (af == AF_UNSPEC) {
+               error = EAI_FAIL;
+               goto bad;
+       }
+       hp = gethostbyname2(hostname, af);
+#else
+       if (af != AF_UNSPEC && af != AF_INET) {
+               error = EAI_FAIL;
+               goto bad;
+       }
+       hp = gethostbyname(hostname);
+#endif
+       h_error = h_errno;
+
+       if (hp == NULL) {
+               switch (h_error) {
+               case HOST_NOT_FOUND:
+               case NO_DATA:
+                       error = EAI_NODATA;
+                       break;
+               case TRY_AGAIN:
+                       error = EAI_AGAIN;
+                       break;
+               case NO_RECOVERY:
+               case NETDB_INTERNAL:
+               default:
+                       error = EAI_FAIL;
+                       break;
+               }
+               goto bad;
+       }
+
+       if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
+           (hp->h_addr_list[0] == NULL))
+               ERR(EAI_FAIL);
+       
+       for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
+               switch (af) {
+#ifdef INET6
+               case AF_INET6:
+                       afd = &afdl[N_INET6];
+                       break;
+#endif
+#ifndef INET6
+               default:        /* AF_UNSPEC */
+#endif
+               case AF_INET:
+                       afd = &afdl[N_INET];
+                       break;
+#ifdef INET6
+               default:        /* AF_UNSPEC */
+                       if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
+                               ap += sizeof(struct in6_addr) -
+                                       sizeof(struct in_addr);
+                               afd = &afdl[N_INET];
+                       } else
+                               afd = &afdl[N_INET6];
+                       break;
+#endif
+               }
+               GET_AI(cur->ai_next, afd, ap, port);
+               if (cur == &sentinel) {
+                       top = cur->ai_next;
+                       GET_CANONNAME(top, hp->h_name);
+               }
+               cur = cur->ai_next;
+       }
+       *res = top;
+       return SUCCESS;
+ free:
+       if (top)
+               freeaddrinfo(top);
+ bad:
+       *res = NULL;
+       return error;
+}
diff --git a/contrib/queryperf/missing/getnameinfo.c b/contrib/queryperf/missing/getnameinfo.c
new file mode 100644 (file)
index 0000000..6b1cbe1
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked
+ * - Return values.  There seems to be no standard for return value (RFC2553)
+ *   but INRIA implementation returns EAI_xxx defined for getaddrinfo().
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <stddef.h>
+
+#include "addrinfo.h"
+
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO  0
+
+static struct afd {
+       int a_af;
+       int a_addrlen;
+       int a_socklen;
+       int a_off;
+} afdl [] = {
+#ifdef INET6
+       {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
+               offsetof(struct sockaddr_in6, sin6_addr)},
+#endif
+       {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
+               offsetof(struct sockaddr_in, sin_addr)},
+       {0, 0, 0},
+};
+
+struct sockinet {
+       u_char  si_len;
+       u_char  si_family;
+       u_short si_port;
+};
+
+#define ENI_NOSOCKET   0
+#define ENI_NOSERVNAME 1
+#define ENI_NOHOSTNAME 2
+#define ENI_MEMORY     3
+#define ENI_SYSTEM     4
+#define ENI_FAMILY     5
+#define ENI_SALEN      6
+
+int
+getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
+       const struct sockaddr *sa;
+       size_t salen;
+       char *host;
+       size_t hostlen;
+       char *serv;
+       size_t servlen;
+       int flags;
+{
+       struct afd *afd;
+       struct servent *sp;
+       struct hostent *hp;
+       u_short port;
+       int family, len, i;
+       char *addr, *p;
+       u_long v4a;
+       int h_error;
+       char numserv[512];
+       char numaddr[512];
+
+       if (sa == NULL)
+               return ENI_NOSOCKET;
+
+#ifdef HAVE_SA_LEN
+       len = sa->sa_len;
+       if (len != salen) return ENI_SALEN;
+#else
+       len = salen;
+#endif
+       
+       family = sa->sa_family;
+       for (i = 0; afdl[i].a_af; i++)
+               if (afdl[i].a_af == family) {
+                       afd = &afdl[i];
+                       goto found;
+               }
+       return ENI_FAMILY;
+       
+ found:
+       if (len != afd->a_socklen) return ENI_SALEN;
+       
+       port = ((struct sockinet *)sa)->si_port; /* network byte order */
+       addr = (char *)sa + afd->a_off;
+
+       if (serv == NULL || servlen == 0) {
+               /* what we should do? */
+       } else if (flags & NI_NUMERICSERV) {
+               snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
+               if (strlen(numserv) > servlen)
+                       return ENI_MEMORY;
+               strcpy(serv, numserv);
+       } else {
+               sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
+               if (sp) {
+                       if (strlen(sp->s_name) > servlen)
+                               return ENI_MEMORY;
+                       strcpy(serv, sp->s_name);
+               } else
+                       return ENI_NOSERVNAME;
+       }
+
+       switch (sa->sa_family) {
+       case AF_INET:
+               v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
+               if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+                       flags |= NI_NUMERICHOST;
+               v4a >>= IN_CLASSA_NSHIFT;
+               if (v4a == 0 || v4a == IN_LOOPBACKNET)
+                       flags |= NI_NUMERICHOST;                        
+               break;
+#ifdef INET6
+       case AF_INET6:
+           {
+               struct sockaddr_in6 *sin6;
+               sin6 = (struct sockaddr_in6 *)sa;
+               switch (sin6->sin6_addr.s6_addr[0]) {
+               case 0x00:
+                       if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+                               ;
+                       else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
+                               ;
+                       else
+                               flags |= NI_NUMERICHOST;
+                       break;
+               default:
+                       if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+                               flags |= NI_NUMERICHOST;
+                       else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
+                               flags |= NI_NUMERICHOST;
+                       break;
+               }
+           }
+               break;
+#endif
+       }
+       if (host == NULL || hostlen == 0) {
+               /* what should we do? */
+       } else if (flags & NI_NUMERICHOST) {
+               /* NUMERICHOST and NAMEREQD conflicts with each other */
+               if (flags & NI_NAMEREQD)
+                       return ENI_NOHOSTNAME;
+               if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
+                   == NULL)
+                       return ENI_SYSTEM;
+               if (strlen(numaddr) > hostlen)
+                       return ENI_MEMORY;
+               strcpy(host, numaddr);
+       } else {
+#ifdef USE_GETIPNODEBY
+               hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
+#else
+               hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
+               h_error = h_errno;
+#endif
+
+               if (hp) {
+                       if (flags & NI_NOFQDN) {
+                               p = strchr(hp->h_name, '.');
+                               if (p) *p = '\0';
+                       }
+                       if (strlen(hp->h_name) > hostlen) {
+#ifdef USE_GETIPNODEBY
+                               freehostent(hp);
+#endif
+                               return ENI_MEMORY;
+                       }
+                       strcpy(host, hp->h_name);
+#ifdef USE_GETIPNODEBY
+                       freehostent(hp);
+#endif
+               } else {
+                       if (flags & NI_NAMEREQD)
+                               return ENI_NOHOSTNAME;
+                       if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
+                           == NULL)
+                               return ENI_NOHOSTNAME;
+                       if (strlen(numaddr) > hostlen)
+                               return ENI_MEMORY;
+                       strcpy(host, numaddr);
+               }
+       }
+       return SUCCESS;
+}