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"));
 }




Reply via email to