Hi! Some getaddrinfo improvements. See the ChangeLog entry for the details. I've installed this.
/Simon Index: lib/ChangeLog =================================================================== RCS file: /sources/gnulib/gnulib/lib/ChangeLog,v retrieving revision 1.1170 diff -u -p -r1.1170 ChangeLog --- lib/ChangeLog 27 Jun 2006 13:15:26 -0000 1.1170 +++ lib/ChangeLog 28 Jun 2006 11:07:26 -0000 @@ -1,3 +1,19 @@ +2006-06-28 Simon Josefsson <[EMAIL PROTECTED]> + + * 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 <[EMAIL PROTECTED]> * stdlib_.h (intmax_t, uintmax_t): Undefine before typedef. Index: lib/getaddrinfo.c =================================================================== RCS file: /sources/gnulib/gnulib/lib/getaddrinfo.c,v retrieving revision 1.8 diff -u -p -r1.8 getaddrinfo.c --- lib/getaddrinfo.c 21 Jun 2006 17:22:32 -0000 1.8 +++ lib/getaddrinfo.c 28 Jun 2006 11:07:26 -0000 @@ -1,5 +1,5 @@ /* 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 <[EMAIL PROTECTED]>. This program is free software; you can redistribute it and/or modify @@ -40,6 +40,51 @@ #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) { @@ -66,7 +111,7 @@ getaddrinfo (const char *restrict nodena struct addrinfo **restrict res) { struct addrinfo *tmp; - struct servent *se = NULL; + int port = 0; struct hostent *he; void *storage; size_t size; @@ -83,6 +128,11 @@ getaddrinfo (const char *restrict nodena }; #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; @@ -101,14 +151,24 @@ getaddrinfo (const char *restrict nodena 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. */ @@ -147,8 +207,8 @@ getaddrinfo (const char *restrict nodena 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)) { @@ -171,8 +231,8 @@ getaddrinfo (const char *restrict nodena 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)) { @@ -225,6 +285,11 @@ getaddrinfo (const char *restrict nodena void freeaddrinfo (struct addrinfo *ai) { +#ifdef _WIN32 + if (use_win32_p ()) + return freeaddrinfo_ptr (ai); +#endif + while (ai) { struct addrinfo *cur; @@ -236,3 +301,89 @@ freeaddrinfo (struct addrinfo *ai) 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; +} Index: lib/getaddrinfo.h =================================================================== RCS file: /sources/gnulib/gnulib/lib/getaddrinfo.h,v retrieving revision 1.12 diff -u -p -r1.12 getaddrinfo.h --- lib/getaddrinfo.h 27 Jan 2006 12:50:41 -0000 1.12 +++ lib/getaddrinfo.h 28 Jun 2006 11:07:26 -0000 @@ -48,13 +48,26 @@ struct addrinfo /* 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. */ @@ -68,16 +81,17 @@ struct addrinfo # 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 @@ -117,4 +131,15 @@ extern void freeaddrinfo (struct addrinf 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 */ Index: m4/ChangeLog =================================================================== RCS file: /sources/gnulib/gnulib/m4/ChangeLog,v retrieving revision 1.838 diff -u -p -r1.838 ChangeLog --- m4/ChangeLog 27 Jun 2006 21:21:13 -0000 1.838 +++ m4/ChangeLog 28 Jun 2006 11:07:26 -0000 @@ -1,3 +1,7 @@ +2006-06-28 Simon Josefsson <[EMAIL PROTECTED]> + + * getaddrinfo.m4: Look for getnameinfo prototypes too. + 2006-06-27 Simon Josefsson <[EMAIL PROTECTED]> * sys_select_h.m4: New file, suggested by Paul Eggert and Martin Index: m4/getaddrinfo.m4 =================================================================== RCS file: /sources/gnulib/gnulib/m4/getaddrinfo.m4,v retrieving revision 1.16 diff -u -p -r1.16 getaddrinfo.m4 --- m4/getaddrinfo.m4 21 Jun 2006 17:22:32 -0000 1.16 +++ m4/getaddrinfo.m4 28 Jun 2006 11:07:26 -0000 @@ -1,4 +1,4 @@ -# 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, @@ -6,7 +6,7 @@ dnl with or without modifications, as lo 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,, [ @@ -58,7 +58,7 @@ AC_DEFUN([gl_PREREQ_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. */ Index: ChangeLog =================================================================== RCS file: /sources/gnulib/gnulib/ChangeLog,v retrieving revision 1.530 diff -u -p -r1.530 ChangeLog --- ChangeLog 27 Jun 2006 21:21:13 -0000 1.530 +++ ChangeLog 28 Jun 2006 11:07:26 -0000 @@ -1,3 +1,11 @@ +2006-06-28 Simon Josefsson <[EMAIL PROTECTED]> + + * 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 <[EMAIL PROTECTED]> * modules/sys_select: New file, suggested by Paul Eggert and Index: modules/getaddrinfo =================================================================== RCS file: /sources/gnulib/gnulib/modules/getaddrinfo,v retrieving revision 1.6 diff -u -p -r1.6 getaddrinfo --- modules/getaddrinfo 16 Feb 2006 09:47:28 -0000 1.6 +++ modules/getaddrinfo 28 Jun 2006 11:07:26 -0000 @@ -15,6 +15,7 @@ socklen stdbool strdup sys_socket +inet_ntop configure.ac: gl_GETADDRINFO Index: tests/test-getaddrinfo.c =================================================================== RCS file: /sources/gnulib/gnulib/tests/test-getaddrinfo.c,v retrieving revision 1.1 diff -u -p -r1.1 test-getaddrinfo.c --- tests/test-getaddrinfo.c 21 Jun 2006 17:22:32 -0000 1.1 +++ tests/test-getaddrinfo.c 28 Jun 2006 11:07:26 -0000 @@ -15,9 +15,9 @@ int simple (char *host, char *service) 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)); @@ -38,6 +38,23 @@ int simple (char *host, char *service) 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); @@ -48,14 +65,33 @@ int simple (char *host, char *service) #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)