+2006-06-28 Simon Josefsson <jas@extundo.com>
+
+ * tests/test-getaddrinfo.c: Test getnameinfo too. Call WSAStartup
+ on _WIN32.
+
+ * modules/getaddrinfo (Depends-on): Add inet_ntop, needed by
+ getnameinfo.
+
2006-06-27 Simon Josefsson <jas@extundo.com>
* modules/sys_select: New file, suggested by Paul Eggert and
+2006-06-28 Simon Josefsson <jas@extundo.com>
+
+ * getaddrinfo.c: Try to load ws2_32.dll on Windows, to find the
+ functions there. It will succeed on Windows XP, but on Windows
+ 2000 and (presumably) earlier, it will fail, and use the internal
+ re-implementation.
+ (use_win32_p): New function.
+ (getaddrinfo): Use strtoul on servname, to support numeric ports.
+ Support AI_NUMERICSERV to disable getservbyname.
+ (getnameinfo): New function, only supports
+ NI_NUMERICHOST|NI_NUMERICSERV for now.
+
+ * getaddrinfo.h: Test and check for AI_* flags separately, MinGW
+ only have some of them. Add AI_NUMERICSERV. Add prototype for
+ getnameinfo.
+
2006-06-27 Bruno Haible <bruno@clisp.org>
* stdlib_.h (intmax_t, uintmax_t): Undefine before typedef.
/* Get address information (partial implementation).
- Copyright (C) 1997, 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
Contributed by Simon Josefsson <simon@josefsson.org>.
This program is free software; you can redistribute it and/or modify
#include "strdup.h"
+#ifdef _WIN32
+typedef void WSAAPI (*freeaddrinfo_func) (struct addrinfo*);
+typedef int WSAAPI (*getaddrinfo_func) (const char*, const char*,
+ const struct addrinfo*,
+ struct addrinfo**);
+typedef int WSAAPI (*getnameinfo_func) (const struct sockaddr*,
+ socklen_t, char*, DWORD,
+ char*, DWORD, int);
+
+static getaddrinfo_func getaddrinfo_ptr = NULL;
+static freeaddrinfo_func freeaddrinfo_ptr = NULL;
+static getnameinfo_func getnameinfo_ptr = NULL;
+
+int use_win32_p (void)
+{
+ static int done = 0;
+ HMODULE h;
+
+ if (done)
+ return getaddrinfo_ptr ? 1 : 0;
+
+ done = 1;
+
+ h = GetModuleHandle ("ws2_32.dll");
+
+ if (h)
+ {
+ getaddrinfo_ptr = GetProcAddress (h, "getaddrinfo");
+ freeaddrinfo_ptr = GetProcAddress (h, "freeaddrinfo");
+ getnameinfo_ptr = GetProcAddress (h, "getnameinfo");
+ }
+
+ /* If either is missing, something is odd. */
+ if (!getaddrinfo_ptr || !freeaddrinfo_ptr || !getnameinfo_ptr)
+ {
+ getaddrinfo_ptr = NULL;
+ freeaddrinfo_ptr = NULL;
+ getnameinfo_ptr = NULL;
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
static inline bool
validate_family (int family)
{
struct addrinfo **restrict res)
{
struct addrinfo *tmp;
- struct servent *se = NULL;
+ int port = 0;
struct hostent *he;
void *storage;
size_t size;
};
#endif
+#ifdef _WIN32
+ if (use_win32_p ())
+ return getaddrinfo_ptr (nodename, servname, hints, res);
+#endif
+
if (hints && (hints->ai_flags & ~AI_CANONNAME))
/* FIXME: Support more flags. */
return EAI_BADFLAGS;
if (servname)
{
+ struct servent *se = NULL;
const char *proto =
(hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
- /* FIXME: Use getservbyname_r if available. */
- se = getservbyname (servname, proto);
+ if (!(hints->ai_flags & AI_NUMERICSERV))
+ /* FIXME: Use getservbyname_r if available. */
+ se = getservbyname (servname, proto);
if (!se)
- return EAI_SERVICE;
+ {
+ char *c;
+ port = strtoul (servname, &c, 10);
+ if (*c)
+ return EAI_NONAME;
+ port = htons (port);
+ }
+ else
+ port = se->s_port;
}
/* FIXME: Use gethostbyname_r if available. */
struct sockaddr_in6 *sinp = &p->sockaddr_in6;
tmp = &p->addrinfo;
- if (se)
- sinp->sin6_port = se->s_port;
+ if (port)
+ sinp->sin6_port = port;
if (he->h_length != sizeof (sinp->sin6_addr))
{
struct sockaddr_in *sinp = &p->sockaddr_in;
tmp = &p->addrinfo;
- if (se)
- sinp->sin_port = se->s_port;
+ if (port)
+ sinp->sin_port = port;
if (he->h_length != sizeof (sinp->sin_addr))
{
void
freeaddrinfo (struct addrinfo *ai)
{
+#ifdef _WIN32
+ if (use_win32_p ())
+ return freeaddrinfo_ptr (ai);
+#endif
+
while (ai)
{
struct addrinfo *cur;
free (cur);
}
}
+
+int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
+ char *restrict node, socklen_t nodelen,
+ char *restrict service, socklen_t servicelen,
+ int flags)
+{
+#if _WIN32
+ if (use_win32_p ())
+ return getnameinfo_ptr (sa, salen, node, nodelen,
+ service, servicelen, flags);
+#endif
+
+ /* FIXME: Support other flags. */
+ if ((node && nodelen > 0 && !(flags & NI_NUMERICHOST)) ||
+ (service && servicelen > 0 && !(flags & NI_NUMERICHOST)) ||
+ (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV)))
+ return EAI_BADFLAGS;
+
+ if (sa == NULL || salen < sizeof (sa->sa_family))
+ return EAI_FAMILY;
+
+ switch (sa->sa_family)
+ {
+#if HAVE_IPV4
+ case AF_INET:
+ if (salen < sizeof (struct sockaddr_in))
+ return EAI_FAMILY;
+ break;
+#endif
+#if HAVE_IPV6
+ case AF_INET6:
+ if (salen < sizeof (struct sockaddr_in6))
+ return EAI_FAMILY;
+ break;
+#endif
+ default:
+ return EAI_FAMILY;
+ }
+
+ if (node && nodelen > 0 && flags & NI_NUMERICHOST)
+ {
+ switch (sa->sa_family)
+ {
+#if HAVE_IPV4
+ case AF_INET:
+ if (!inet_ntop (AF_INET,
+ (const void *)
+ &(((const struct sockaddr_in *) sa)->sin_addr),
+ node, nodelen))
+ return EAI_SYSTEM;
+ break;
+#endif
+
+#if HAVE_IPV6
+ case AF_INET6:
+ if (!inet_ntop (AF_INET6,
+ (const void *)
+ &(((const struct sockaddr_in6 *) sa)->sin6_addr),
+ node, nodelen))
+ return EAI_SYSTEM;
+ break;
+#endif
+
+ default:
+ return EAI_FAMILY;
+ }
+ }
+
+ if (service && servicelen > 0 && flags & NI_NUMERICSERV)
+ switch (sa->sa_family)
+ {
+#if HAVE_IPV4
+ case AF_INET:
+#endif
+#if HAVE_IPV6
+ case AF_INET6:
+#endif
+ if (snprintf (service, servicelen, "%d",
+ ntohs (((const struct sockaddr_in *) sa)->sin_port))
+ + 1 > servicelen)
+ return EAI_OVERFLOW;
+ break;
+ }
+
+ return 0;
+}
/* Possible values for `ai_flags' field in `addrinfo' structure. */
# ifndef AI_PASSIVE
-# define AI_PASSIVE 0x0001 /* Socket address is intended for `bind'. */
-# define AI_CANONNAME 0x0002 /* Request for canonical name. */
+# define AI_PASSIVE 0x0001 /* Socket address is intended for `bind'. */
+# endif
+# ifndef AI_CANONNAME
+# define AI_CANONNAME 0x0002 /* Request for canonical name. */
+# endif
+# ifndef AI_NUMERICHOST
# define AI_NUMERICHOST 0x0004 /* Don't use name resolution. */
-# define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */
-# define AI_ALL 0x0010 /* Return IPv4 mapped and IPv6 addresses. */
-# define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose
+# endif
+# ifndef AI_V4MAPPED
+# define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */
+# endif
+# ifndef AI_ALL
+# define AI_ALL 0x0010 /* Return IPv4 mapped and IPv6 addresses. */
+# endif
+# ifndef AI_ADDRCONFIG
+# define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose
returned address type.. */
+#endif
+#ifndef AI_NUMERICSERV
+# define AI_NUMERICSERV 0x0400 /* Don't use name resolution. */
# endif
/* Error values for `getaddrinfo' function. */
# define EAI_SOCKTYPE -7 /* `ai_socktype' not supported. */
# define EAI_SERVICE -8 /* SERVICE not supported for `ai_socktype'. */
# define EAI_MEMORY -10 /* Memory allocation failure. */
+#endif
+#ifndef EAI_OVERFLOW
+/* Not defined on mingw32. */
# define EAI_OVERFLOW -12 /* Argument buffer overflow. */
#endif
# ifndef EAI_ADDRFAMILY
-/* Not defined on mingw32. XXX May be incorrect? Perhaps it is never
- returned? */
+/* Not defined on mingw32. */
# define EAI_ADDRFAMILY -9 /* Address family for NAME not supported. */
# endif
# ifndef EAI_SYSTEM
-/* Not defined on mingw32. XXX May be incorrect? Perhaps it is never
- returned? */
+/* Not defined on mingw32. */
# define EAI_SYSTEM -11 /* System error returned in `errno'. */
# endif
extern const char *gai_strerror (int ecode);
# endif
+# if !HAVE_DECL_GETNAMEINFO
+/* Convert socket address to printable node and service names.
+ For more details, see the POSIX:2001 specification
+ <http://www.opengroup.org/susv3xsh/gai_strerror.html>. */
+extern int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen,
+ char *restrict node, socklen_t nodelen,
+ char *restrict service, socklen_t servicelen,
+ int flags);
+
+# endif
+
#endif /* GETADDRINFO_H */
+2006-06-28 Simon Josefsson <jas@extundo.com>
+
+ * getaddrinfo.m4: Look for getnameinfo prototypes too.
+
2006-06-27 Simon Josefsson <jas@extundo.com>
* sys_select_h.m4: New file, suggested by Paul Eggert and Martin
-# getaddrinfo.m4 serial 9
+# getaddrinfo.m4 serial 10
dnl Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
AC_DEFUN([gl_GETADDRINFO],
[
- AC_MSG_NOTICE([checking how to do getaddrinfo])
+ AC_MSG_NOTICE([checking how to do getaddrinfo, freeaddrinfo and getnameinfo])
AC_SEARCH_LIBS(getaddrinfo, [nsl socket])
AC_CHECK_FUNCS(getaddrinfo,, [
AC_REQUIRE([AC_C_INLINE])
AC_REQUIRE([AC_GNU_SOURCE])
AC_CHECK_HEADERS_ONCE(netinet/in.h netdb.h)
- AC_CHECK_DECLS([getaddrinfo, freeaddrinfo, gai_strerror],,,[
+ AC_CHECK_DECLS([getaddrinfo, freeaddrinfo, gai_strerror, getnameinfo],,,[
/* sys/types.h is not needed according to POSIX, but the
sys/socket.h in i386-unknown-freebsd4.10 and
powerpc-apple-darwin5.5 required it. */
stdbool
strdup
sys_socket
+inet_ntop
configure.ac:
gl_GETADDRINFO
memset (&hints, 0, sizeof (hints));
hints.ai_flags = AI_CANONNAME;
- hints.ai_family = AF_INET;
+ hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- res = getaddrinfo (host, 0, 0, &ai0);
+ res = getaddrinfo (host, service, 0, &ai0);
printf ("res %d: %s\n", res, gai_strerror (res));
buf, sizeof (buf) - 1));
if (ai->ai_canonname)
printf ("\tFound %s...\n", ai->ai_canonname);
+
+ {
+ char ipbuf[BUFSIZ];
+ char portbuf[BUFSIZ];
+
+ res = getnameinfo (ai->ai_addr, ai->ai_addrlen,
+ ipbuf, sizeof (ipbuf) - 1,
+ portbuf, sizeof (portbuf) - 1,
+ NI_NUMERICHOST|NI_NUMERICSERV);
+ printf ("\t\tgetnameinfo %d: %s\n", res, gai_strerror (res));
+ if (res == 0)
+ {
+ printf ("\t\tip %s\n", ipbuf);
+ printf ("\t\tport %s\n", portbuf);
+ }
+ }
+
}
freeaddrinfo (ai0);
#define HOST1 "www.gnu.org"
#define SERV1 "http"
#define HOST2 "www.ibm.com"
-#define SERV2 "http"
-#define HOST3 "ibm.org"
+#define SERV2 "https"
+#define HOST3 "microsoft.com"
#define SERV3 "http"
#define HOST4 "google.org"
-#define SERV4 "http"
+#define SERV4 "ldap"
int main (void)
{
+#if _WIN32
+ {
+ WORD requested;
+ WSADATA data;
+ int err;
+
+ requested = MAKEWORD (1, 1);
+ err = WSAStartup (requested, &data);
+ if (err != 0)
+ return 1;
+
+ if (data.wVersion < requested)
+ {
+ WSACleanup ();
+ return 2;
+ }
+ }
+#endif
+
return simple (HOST1, SERV1)
+ simple (HOST2, SERV2)
+ simple (HOST3, SERV3)