[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
getaddrinfo: native win32 support, getnameinfo support
From: |
Simon Josefsson |
Subject: |
getaddrinfo: native win32 support, getnameinfo support |
Date: |
Wed, 28 Jun 2006 13:08:51 +0200 |
User-agent: |
Gnus/5.110006 (No Gnus v0.6) Emacs/22.0.50 (gnu/linux) |
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 <address@hidden>
+
+ * 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 <address@hidden>
* 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 <address@hidden>.
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 <address@hidden>
+
+ * getaddrinfo.m4: Look for getnameinfo prototypes too.
+
2006-06-27 Simon Josefsson <address@hidden>
* 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 <address@hidden>
+
+ * 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 <address@hidden>
* 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)
- getaddrinfo: native win32 support, getnameinfo support,
Simon Josefsson <=