* fake-addrinfo.h: New file
authorKen Raeburn <raeburn@mit.edu>
Thu, 19 Jul 2001 11:15:35 +0000 (11:15 +0000)
committerKen Raeburn <raeburn@mit.edu>
Thu, 19 Jul 2001 11:15:35 +0000 (11:15 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13608 dc483132-0cff-0310-8789-dd5450dbe970

src/include/ChangeLog
src/include/fake-addrinfo.h [new file with mode: 0644]

index 95f91e7ba2315ac29f1a70ab6393aa927f42aa1f..95b1c3435f9b1530bcde4599501ec344cb40ca84 100644 (file)
@@ -1,3 +1,7 @@
+2001-07-19  Ken Raeburn  <raeburn@mit.edu>
+
+       * fake-addrinfo.h: New file.
+
 2001-06-22  Ezra Peisach  <epeisach@mit.edu>
 
        * krb5.hin: Do not use "random_key" as argument name. When krb.h
diff --git a/src/include/fake-addrinfo.h b/src/include/fake-addrinfo.h
new file mode 100644 (file)
index 0000000..96bc79d
--- /dev/null
@@ -0,0 +1,381 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#ifndef HAVE_GETADDRINFO
+
+#ifndef FAI_PREFIX
+# error "FAI_PREFIX must be defined when fake-addrinfo.h is included"
+#endif
+
+#define FAI_CONCAT(A,B) FAI_CONCAT2(A,B)
+#define FAI_CONCAT2(A,B) A ## B
+
+#undef  getaddrinfo
+#define getaddrinfo    FAI_CONCAT(FAI_PREFIX, _fake_getaddrinfo)
+#undef  getnameinfo
+#define getnameinfo    FAI_CONCAT(FAI_PREFIX, _fake_getnameinfo)
+#undef  freeaddrinfo
+#define freeaddrinfo   FAI_CONCAT(FAI_PREFIX, _fake_freeaddrinfo)
+#undef  gai_strerror
+#define gai_strerror   FAI_CONCAT(FAI_PREFIX, _fake_gai_strerror)
+#undef  addrinfo
+#define addrinfo       FAI_CONCAT(FAI_PREFIX, _fake_addrinfo)
+
+struct addrinfo {
+    int ai_family;             /* PF_foo */
+    int ai_socktype;           /* SOCK_foo */
+    int ai_protocol;           /* 0, IPPROTO_foo */
+    int ai_flags;              /* AI_PASSIVE etc */
+    size_t ai_addrlen;         /* real length of socket address */
+    char *ai_canonname;                /* canonical name of host */
+    struct sockaddr *ai_addr;  /* pointer to variable-size address */
+    struct addrinfo *ai_next;  /* next in linked list */
+};
+
+#undef AI_PASSIVE
+#define        AI_PASSIVE      0x01
+#undef AI_CANONNAME
+#define        AI_CANONNAME    0x02
+#undef AI_NUMERICHOST
+#define        AI_NUMERICHOST  0x04
+#undef AI_V4MAPPED
+#define        AI_V4MAPPED     0x08    /* ignored */
+#undef AI_ADDRCONFIG
+#define        AI_ADDRCONFIG   0x10    /* ignored */
+#undef AI_ALL
+#define        AI_ALL          0x20    /* ignored */
+
+#define AI_DEFAULT     (AI_V4MAPPED | AI_ADDRCONFIG)
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+#ifndef NI_MAXSERV
+#define NI_MAXSERV 32
+#endif
+
+#undef NI_NUMERICHOST
+#define NI_NUMERICHOST 0x01
+#undef NI_NUMERICSERV
+#define NI_NUMERICSERV 0x02
+#undef NI_NAMEREQD
+#define NI_NAMEREQD    0x04
+#undef NI_DGRAM
+#define NI_DGRAM       0x08
+#undef NI_NOFQDN
+#define NI_NOFQDN      0x10
+
+
+#undef  EAI_ADDRFAMILY
+#define EAI_ADDRFAMILY 1
+#undef  EAI_AGAIN
+#define EAI_AGAIN      2
+#undef  EAI_BADFLAGS
+#define EAI_BADFLAGS   3
+#undef  EAI_FAIL
+#define EAI_FAIL       4
+#undef  EAI_FAMILY
+#define EAI_FAMILY     5
+#undef  EAI_MEMORY
+#define EAI_MEMORY     6
+#undef  EAI_NODATA
+#define EAI_NODATA     7
+#undef  EAI_NONAME
+#define EAI_NONAME     8
+#undef  EAI_SERVICE
+#define EAI_SERVICE    9
+#undef  EAI_SOCKTYPE
+#define EAI_SOCKTYPE   10
+#undef  EAI_SYSTEM
+#define EAI_SYSTEM     11
+
+int getaddrinfo (const char *name, const char *serv,
+                const struct addrinfo *hint, struct addrinfo **result);
+
+int getnameinfo (const struct sockaddr *addr, socklen_t len,
+                char *host, size_t hostlen,
+                char *service, size_t servicelen,
+                int flags);
+
+void freeaddrinfo (struct addrinfo *ai);
+
+char *gai_strerror (int code);
+
+#ifdef FAI_IMPLEMENTATION
+
+static int translate_h_errno (int h);
+
+static int fai_add_entry (struct addrinfo **result, void *addr, int port,
+                         const struct addrinfo *template)
+{
+    struct addrinfo *n = malloc (sizeof (struct addrinfo));
+    struct sockaddr_in *sin4;
+    if (n == 0)
+       return EAI_MEMORY;
+    if (template->ai_family != AF_INET)
+       return EAI_FAMILY;
+    *n = *template;
+    sin4 = malloc (sizeof (struct sockaddr_in));
+    if (sin4 == 0)
+       return EAI_MEMORY;
+    n->ai_addr = (struct sockaddr *) sin4;
+    sin4->sin_family = AF_INET;
+    sin4->sin_addr = *(struct in_addr *)addr;
+    sin4->sin_port = port;
+#ifdef HAVE_SA_LEN
+    sin4->sin_len = sizeof (struct sockaddr_in);
+#endif
+    n->ai_next = *result;
+    *result = n;
+    return 0;
+}
+
+static int fai_add_hosts_by_name (const char *name, int af,
+                                 struct addrinfo *template,
+                                 int portnum, int flags,
+                                 struct addrinfo **result)
+{
+    struct hostent *hp;
+    int i, r;
+
+    if (af != AF_INET)
+       /* For now, real ipv6 support needs real getaddrinfo.  */
+       return EAI_FAMILY;
+    hp = gethostbyname (name);
+    if (hp == 0)
+       return translate_h_errno (h_errno);
+    for (i = 0; hp->h_addr_list[i]; i++) {
+       r = fai_add_entry (result, hp->h_addr_list[i], portnum, template);
+       if (r)
+           return r;
+    }
+    if (*result && (flags & AI_CANONNAME))
+       (*result)->ai_canonname = strdup (hp->h_name);
+    return 0;
+}
+
+int getaddrinfo (const char *name, const char *serv,
+                const struct addrinfo *hint, struct addrinfo **result)
+{
+    struct addrinfo *res = 0;
+    int ret;
+    int port = 0, socktype;
+    int flags;
+    struct addrinfo template;
+
+    if (hint != 0) {
+       if (hint->ai_family != 0 && hint->ai_family != AF_INET)
+           return EAI_NODATA;
+       socktype = hint->ai_socktype;
+       flags = hint->ai_flags;
+    } else {
+       socktype = 0;
+       flags = 0;
+    }
+
+    if (serv) {
+       size_t numlen = strspn (serv, "0123456789");
+       if (serv[numlen] == '\0') {
+           /* pure numeric */
+#ifdef sun
+#define strtoul strtol
+#endif
+           unsigned long p = strtoul (serv, 0, 10);
+           if (p == 0 || p > 65535)
+               return EAI_NONAME;
+           port = htons (p);
+       } else {
+           struct servent *sp;
+           int try_dgram_too = 0;
+           if (socktype == 0) {
+               try_dgram_too = 1;
+               socktype = SOCK_STREAM;
+           }
+       try_service_lookup:
+           sp = getservbyname (serv, socktype == SOCK_STREAM ? "tcp" : "udp");
+           if (sp == 0) {
+               if (try_dgram_too) {
+                   socktype = SOCK_DGRAM;
+                   goto try_service_lookup;
+               }
+               return EAI_SERVICE;
+           }
+           port = sp->s_port;
+       }
+    }
+
+    if (name == 0) {
+       name = (flags & AI_PASSIVE) ? "0.0.0.0" : "127.0.0.1";
+       flags |= AI_NUMERICHOST;
+    }
+
+    template.ai_family = AF_INET;
+    template.ai_addrlen = sizeof (struct sockaddr_in);
+    template.ai_socktype = socktype;
+    template.ai_protocol = 0;
+    template.ai_flags = 0;
+    template.ai_canonname = 0;
+    template.ai_next = 0;
+    template.ai_addr = 0;
+
+    /* If NUMERICHOST is set, parse a numeric address.
+       If it's not set, don't accept such names.  */
+    if (flags & AI_NUMERICHOST) {
+       struct in_addr addr4;
+#ifdef sun
+       addr4.s_addr = inet_addr (name);
+       ret = addr4.s_addr != 0 && strcmp("0.0.0.0", name);
+#else
+       ret = inet_aton (name, &addr4);
+#endif
+       if (ret)
+           return EAI_NONAME;
+       ret = fai_add_entry (&res, &addr4, port, &template);
+    } else {
+       ret = fai_add_hosts_by_name (name, AF_INET, &template, port, flags,
+                                    &res);
+    }
+
+    if (ret && ret != NO_ADDRESS) {
+       freeaddrinfo (res);
+       return ret;
+    }
+    if (res == 0)
+       return NO_ADDRESS;
+    *result = res;
+    return 0;
+}
+
+int getnameinfo (const struct sockaddr *sa, socklen_t len,
+                char *host, size_t hostlen,
+                char *service, size_t servicelen,
+                int flags)
+{
+    struct hostent *hp;
+    const struct sockaddr_in *sinp;
+    struct servent *sp;
+
+    if (sa->sa_family != AF_INET) {
+       return EAI_FAMILY;
+    }
+    sinp = (const struct sockaddr_in *) sa;
+
+    if (host) {
+       if (flags & NI_NUMERICHOST) {
+           char *p;
+       numeric_host:
+           p = inet_ntoa (sinp->sin_addr);
+           if (strlen (p) < hostlen)
+               strcpy (host, p);
+           else
+               return EAI_FAIL; /* ?? */
+       } else {
+           hp = gethostbyaddr (&sinp->sin_addr, sizeof (struct in_addr),
+                               AF_INET);
+           if (hp == 0) {
+               if (h_errno == NO_ADDRESS && !(flags & NI_NAMEREQD)) /* ??? */
+                   goto numeric_host;
+               return translate_h_errno (h_errno);
+           }
+           if (strlen (hp->h_name) < hostlen)
+               strcpy (host, hp->h_name);
+           else
+               return EAI_FAIL; /* ?? */
+       }
+    }
+
+    if (service) {
+       if (flags & NI_NUMERICSERV) {
+           char numbuf[10];
+           int port;
+       numeric_service:
+           port = ntohs (sinp->sin_port);
+           if (port < 0 || port > 65535)
+               return EAI_FAIL;
+           sprintf (numbuf, "%d", port);
+           if (strlen (numbuf) < servicelen)
+               strcpy (service, numbuf);
+           else
+               return EAI_FAIL;
+       } else {
+           sp = getservbyport (sinp->sin_port,
+                               (flags & NI_DGRAM) ? "udp" : "tcp");
+           if (sp == 0)
+               goto numeric_service;
+           if (strlen (sp->s_name) < servicelen)
+               strcpy (service, sp->s_name);
+           else
+               return EAI_FAIL;
+       }
+    }
+
+    return 0;
+}
+
+void freeaddrinfo (struct addrinfo *ai)
+{
+    struct addrinfo *next;
+    while (ai) {
+       next = ai->ai_next;
+       free (ai->ai_canonname);
+       free (ai->ai_addr);
+       free (ai);
+       ai = next;
+    }
+}
+
+char *gai_strerror (int code)
+{
+    switch (code) {
+    case EAI_ADDRFAMILY: return "address family for nodename not supported";
+    case EAI_AGAIN:    return "temporary failure in name resolution";
+    case EAI_BADFLAGS: return "bad flags to getaddrinfo/getnameinfo";
+    case EAI_FAIL:     return "non-recoverable failure in name resolution";
+    case EAI_FAMILY:   return "ai_family not supported";
+    case EAI_MEMORY:   return "out of memory";
+    case EAI_NODATA:   return "no address associated with hostname";
+    case EAI_NONAME:   return "name does not exist";
+    case EAI_SERVICE:  return "service name not supported for specified socket type";
+    case EAI_SOCKTYPE: return "ai_socktype not supported";
+    case EAI_SYSTEM:   return strerror (errno);
+    default:           return "bogus getaddrinfo error?";
+    }
+}
+
+static int translate_h_errno (int h)
+{
+    switch (h) {
+    case 0:
+       return 0;
+#ifdef NETDB_INTERNAL
+    case NETDB_INTERNAL:
+       if (errno == ENOMEM)
+           return EAI_MEMORY;
+       return EAI_SYSTEM;
+#endif
+    case HOST_NOT_FOUND:
+       return EAI_NONAME;
+    case TRY_AGAIN:
+       return EAI_AGAIN;
+    case NO_RECOVERY:
+       return EAI_FAIL;
+    case NO_DATA:
+#if NO_DATA != NO_ADDRESS
+    case NO_ADDRESS:
+#endif
+       return EAI_NODATA;
+    }
+}
+
+#endif /* FAI_IMPLEMENTATION */
+
+#define HAVE_GETADDRINFO       /* fake it */
+#define HAVE_GETNAMEINFO       /* well, soon... */
+
+#endif /* HAVE_GETADDRINFO */
+
+/* Fudge things on older gai implementations.  */
+#ifndef AI_DEFAULT
+# define AI_DEFAULT 0 /* (AI_V4MAPPED | AI_ADDRCONFIG) */
+#endif