Testing reveals that getaddrinfo does not support AI_NUMERICSERV on mingw. This patch adds the support for it.
2025-02-12 Bruno Haible <br...@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. diff --git a/doc/posix-functions/getaddrinfo.texi b/doc/posix-functions/getaddrinfo.texi index 4038bf7349..dd216d23d8 100644 --- a/doc/posix-functions/getaddrinfo.texi +++ b/doc/posix-functions/getaddrinfo.texi @@ -13,11 +13,14 @@ 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: diff --git a/lib/getaddrinfo.c b/lib/getaddrinfo.c index 4a0aeab9f1..a8c45c21c2 100644 --- a/lib/getaddrinfo.c +++ b/lib/getaddrinfo.c @@ -54,7 +54,7 @@ #if HAVE_GETADDRINFO -/* Override with cdecl calling convention. */ +/* Override with cdecl calling convention and mingw fix. */ int getaddrinfo (const char *restrict nodename, @@ -63,6 +63,10 @@ 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); } @@ -237,10 +241,17 @@ getaddrinfo (const char *restrict nodename, # 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; diff --git a/m4/getaddrinfo.m4 b/m4/getaddrinfo.m4 index 1e1fc48a59..19ae42cc15 100644 --- a/m4/getaddrinfo.m4 +++ b/m4/getaddrinfo.m4 @@ -1,5 +1,5 @@ # 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, @@ -10,6 +10,7 @@ AC_DEFUN([gl_GETADDRINFO] [ 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" @@ -88,6 +89,44 @@ AC_DEFUN([gl_GETADDRINFO] 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.]) diff --git a/tests/test-getaddrinfo.c b/tests/test-getaddrinfo.c index 8f35e6abc6..31e999cb0e 100644 --- a/tests/test-getaddrinfo.c +++ b/tests/test-getaddrinfo.c @@ -82,7 +82,9 @@ simple (int pass, char const *host, char const *service) 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; @@ -96,6 +98,9 @@ simple (int pass, char const *host, char const *service) 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 @@ -187,9 +192,13 @@ int main (void) (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) @@ -203,5 +212,13 @@ int main (void) + 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")); }