+2025-02-12 Bruno Haible <bruno@clisp.org>
+
+ getaddrinfo: Support the AI_NUMERICSERV flag.
+ * m4/getaddrinfo.m4 (gl_GETADDRINFO): Require AC_CANONICAL_HOST. Test
+ whether getaddrinfo supports AI_NUMERICSERV.
+ * lib/getaddrinfo.c (getaddrinfo): Accept and implement the
+ AI_NUMERICSERV flag.
+ * tests/test-getaddrinfo.c (simple): In pass 4, pass the AI_NUMERICSERV
+ flag.
+ (main): Test numeric services in pass 1. Add pass 4.
+ * doc/posix-functions/getaddrinfo.texi: Mention the native Windows bug.
+
2025-02-12 Bruno Haible <bruno@clisp.org>
getaddrinfo: Support the AI_NUMERICHOST flag.
This function is missing on some platforms:
HP-UX 11.11, Cygwin 1.5.x, mingw, MSVC 14.
@item
-On Windows, this function is declared in @code{<ws2tcpip.h>} rather than in
-@code{<netdb.h>}.
+On native Windows, this function is declared in @code{<ws2tcpip.h>}
+rather than in @code{<netdb.h>}.
@item
-On Windows, in 32-bit mode, this function is defined with a calling convention
-that is different from @code{cdecl}.
+On native Windows, this function does not support
+the @code{AI_NUMERICSERV} hints flag.
+@item
+On native Windows, in 32-bit mode, this function is defined
+with a calling convention that is different from @code{cdecl}.
@end itemize
Portability problems not fixed by Gnulib:
#if HAVE_GETADDRINFO
-/* Override with cdecl calling convention. */
+/* Override with cdecl calling convention and mingw fix. */
int
getaddrinfo (const char *restrict nodename,
struct addrinfo **restrict res)
# undef getaddrinfo
{
+ if (hints && (hints->ai_flags & AI_NUMERICSERV) != 0
+ && servname && !(*servname >= '0' && *servname <= '9'))
+ return EAI_NONAME;
+
return getaddrinfo (nodename, servname, hints, res);
}
# ifdef WINDOWS_NATIVE
if (use_win32_p ())
- return getaddrinfo_ptr (nodename, servname, hints, res);
+ {
+ if (hints && (hints->ai_flags & AI_NUMERICSERV) != 0
+ && servname && !(*servname >= '0' && *servname <= '9'))
+ return EAI_NONAME;
+ return getaddrinfo_ptr (nodename, servname, hints, res);
+ }
# endif
- if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE|AI_NUMERICHOST)))
+ if (hints
+ && (hints->ai_flags
+ & ~(AI_CANONNAME | AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV)))
/* FIXME: Support more flags. */
return EAI_BADFLAGS;
# getaddrinfo.m4
-# serial 35
+# serial 36
dnl Copyright (C) 2004-2025 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_REQUIRE([gl_SYS_SOCKET_H])dnl for HAVE_SYS_SOCKET_H, HAVE_WINSOCK2_H
AC_REQUIRE([gl_NETDB_H])dnl for HAVE_NETDB_H
+ AC_REQUIRE([AC_CANONICAL_HOST])
GETADDRINFO_LIB=
gai_saved_LIBS="$LIBS"
HAVE_GETADDRINFO=0
fi
fi
+ AC_CACHE_CHECK([whether getaddrinfo supports AI_NUMERICSERV],
+ [gl_cv_func_getaddrinfo_works],
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+#include <stddef.h>
+#include <string.h>
+ ]], [[
+ struct addrinfo hints;
+ struct addrinfo ai;
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_flags = AI_NUMERICSERV;
+ return getaddrinfo ("www.gnu.org", "http", &hints, &ai) != EAI_NONAME;
+ ]])
+ ],
+ [gl_cv_func_getaddrinfo_works=yes],
+ [gl_cv_func_getaddrinfo_works=no],
+ [case "$host_os" in
+ # Guess no on native Windows.
+ mingw* | windows*) gl_cv_func_getaddrinfo_works="guessing no" ;;
+ # Guess yes otherwise.
+ *) gl_cv_func_getaddrinfo_works="guessing yes" ;;
+ esac
+ ])
+ ])
+ case "$gl_cv_func_getaddrinfo_works" in
+ *yes) ;;
+ *) REPLACE_GETADDRINFO=1 ;;
+ esac
AC_DEFINE_UNQUOTED([HAVE_GETADDRINFO], [$HAVE_GETADDRINFO],
[Define to 1 if getaddrinfo exists, or to 0 otherwise.])
else
{
memset (&hints, 0, sizeof (hints));
- hints.ai_flags = AI_CANONNAME | (pass == 3 ? AI_NUMERICHOST : 0);
+ hints.ai_flags = AI_CANONNAME
+ | (pass == 3 ? AI_NUMERICHOST : 0)
+ | (pass == 4 ? AI_NUMERICSERV : 0);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints_p = &hints;
if (pass == 3 && ! isdigit (host[0]))
return res != EAI_NONAME;
+ if (pass == 4 && ! isdigit (service[0]))
+ return res != EAI_NONAME;
+
if (res != 0)
{
/* EAI_AGAIN is returned if no network is available. Don't fail
(void) gl_sockets_startup (SOCKETS_1_1);
return ( simple (1, HOST1, SERV1)
+ + simple (1, HOST1, "80")
+ simple (1, HOST2, SERV2)
+ + simple (1, HOST2, "443")
+ simple (1, HOST3, SERV3)
+ + simple (1, HOST3, "80")
+ simple (1, HOST4, SERV4)
+ + simple (1, HOST4, "389")
+ simple (2, HOST1, SERV1)
+ simple (2, HOST2, SERV2)
+ simple (2, HOST3, SERV3)
+ simple (3, HOST1, SERV1)
+ simple (3, HOST2, SERV2)
+ simple (3, HOST3, SERV3)
- + simple (3, HOST4, SERV4));
+ + simple (3, HOST4, SERV4)
+ + simple (4, HOST1, SERV1)
+ + simple (4, HOST1, "80")
+ + simple (4, HOST2, SERV2)
+ + simple (4, HOST2, "443")
+ + simple (4, HOST3, SERV3)
+ + simple (4, HOST3, "80")
+ + simple (4, HOST4, SERV4)
+ + simple (4, HOST4, "389"));
}