On 64-bit HP-UX, socklen_t is defined as the 64-bit type 'size_t';
however the system calls getsockname() etc. read only the first 32 bits
from &addr_len.  Because the endianness is BIG_ENDIAN, this reads as 0,
and thus these system calls don't fill in an address in the supplied
buffer (but nevertheless return 0).  This problem is known to HP for
15 years [1]. Their response is described in "man xopen_networking" [2].

Namely, they first provided a fix that consists in linking with -lxnet.
Then they realized that this approach breaks all code (e.g. in libraries)
that assumes that the functions take an 'int *' (old BSD convention)
rather than a 'socklen_t *'.

So they now provide a different fix, namely wrappers called _xpg_getsockname
etc., which is enabled by defining the macro _HPUX_ALT_XOPEN_SOCKET_API.

But they don't enable this second fix by default!!

This fix works only when the appropriate feature macros are defined, but this
is not a problem in practice:
  - If you use CC="cc +DD64 -AC99", the compiler will add -D_HPUX_SOURCE=1
    by default.
  - If you use CC="cc +DD64 -AC99 -D_XOPEN_SOURCE=500", the compiler will
    automatically add -D_HPUX_SOURCE=1 -D_XOPEN_SOURCE_EXTENDED

Here's what I'm committing for gnulib:
1) A test case for getsockname() that highlights the problem: It fails
   on HP-UX in 64-bit mode (but succeeds in 32-bit mode).
2) A modification of the 'extensions' module to define the
   _HPUX_ALT_XOPEN_SOCKET_API macro.

With this fix, the getsockname test now works also in 64-bit mode.

[1] https://marc.info/?l=hpux-devtools&m=106742181731126&w=2
[2] https://support.hpe.com/hpsc/doc/public/display?docId=emr_na-c02281864

>From 46e7ff4afee45c1b2b52849bd36b3b258417ec51 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 27 Jan 2018 08:52:31 +0100
Subject: [PATCH 1/2] getsockname tests: More tests.

* tests/test-getsockname.c (open_server_socket): New function, mostly
copied from test-poll.c.
(main): Check that getsockname fills in addr.
* modules/getsockname-tests (Depends-on): Add the necessary
dependencies.
(test_getsockname_LDADD): Link with $(INET_PTON_LIB).
---
 ChangeLog                 | 10 ++++++++++
 modules/getsockname-tests | 10 +++++++++-
 tests/test-getsockname.c  | 48 ++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 4994460..70d4219 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2018-01-27  Bruno Haible  <br...@clisp.org>
+
+	getsockname tests: More tests.
+	* tests/test-getsockname.c (open_server_socket): New function, mostly
+	copied from test-poll.c.
+	(main): Check that getsockname fills in addr.
+	* modules/getsockname-tests (Depends-on): Add the necessary
+	dependencies.
+	(test_getsockname_LDADD): Link with $(INET_PTON_LIB).
+
 2018-01-26  Paul Eggert  <egg...@cs.ucla.edu>
 
 	manywarnings: fix maintainer comment
diff --git a/modules/getsockname-tests b/modules/getsockname-tests
index 0134e4c..9141254 100644
--- a/modules/getsockname-tests
+++ b/modules/getsockname-tests
@@ -5,11 +5,19 @@ tests/macros.h
 
 Depends-on:
 netinet_in
+arpa_inet
+inet_pton
+errno
+perror
 sockets
+socket
+setsockopt
+bind
+listen
 
 configure.ac:
 
 Makefile.am:
 TESTS += test-getsockname
 check_PROGRAMS += test-getsockname
-test_getsockname_LDADD = $(LDADD) @LIBSOCKET@
+test_getsockname_LDADD = $(LDADD) @LIBSOCKET@ $(INET_PTON_LIB)
diff --git a/tests/test-getsockname.c b/tests/test-getsockname.c
index 95f2217..2c951fb 100644
--- a/tests/test-getsockname.c
+++ b/tests/test-getsockname.c
@@ -21,13 +21,47 @@
 #include "signature.h"
 SIGNATURE_CHECK (getsockname, int, (int, struct sockaddr *, socklen_t *));
 
-#include <errno.h>
+#include <stdio.h>
+#include <string.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #include <unistd.h>
+#include <errno.h>
 
 #include "sockets.h"
 #include "macros.h"
 
+static int
+open_server_socket (void)
+{
+  int s, x;
+  struct sockaddr_in ia;
+
+  s = socket (AF_INET, SOCK_STREAM, 0);
+
+  x = 1;
+  setsockopt (s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof (x));
+
+  memset (&ia, 0, sizeof (ia));
+  ia.sin_family = AF_INET;
+  inet_pton (AF_INET, "0.0.0.0", &ia.sin_addr);
+  /* Port 0 means that the system should assign a port.  */
+  ia.sin_port = htons (0);
+  if (bind (s, (struct sockaddr *) &ia, sizeof (ia)) < 0)
+    {
+      perror ("bind");
+      exit (77);
+    }
+
+  if (listen (s, 1) < 0)
+    {
+      perror ("listen");
+      exit (77);
+    }
+
+  return s;
+}
+
 int
 main (void)
 {
@@ -52,5 +86,17 @@ main (void)
     ASSERT (errno == EBADF);
   }
 
+  /* Test behaviour for a server socket.  */
+  {
+    int s = open_server_socket ();
+    struct sockaddr_in addr;
+    socklen_t addrlen = sizeof (addr);
+
+    memset (&addr, 0, sizeof (addr));
+    ASSERT (getsockname (s, (struct sockaddr *) &addr, &addrlen) == 0);
+    ASSERT (addr.sin_family == AF_INET);
+    ASSERT (ntohs (addr.sin_port) != 0);
+  }
+
   return 0;
 }
-- 
2.7.4

>From d4f6a210f44a2bbfedfc60353758c39fb86f8d7a Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 27 Jan 2018 10:57:59 +0100
Subject: [PATCH 2/2] Fix malfunction of socket functions on HP-UX in 64-bit
 mode.

* m4/socketlib.m4 (gl_SOCKETLIB): Add comment.
* m4/extensions.m4 (AC_USE_SYSTEM_EXTENSIONS): Define
_HPUX_ALT_XOPEN_SOCKET_API.
* modules/accept (Depends-on): Add 'extensions'.
* modules/getpeername (Depends-on): Likewise.
* modules/getsockname (Depends-on): Likewise.
* modules/getsockopt (Depends-on): Likewise.
* modules/recvfrom (Depends-on): Likewise.
* doc/posix-functions/accept.texi: Mention the HP-UX socklen_t problem.
* doc/posix-functions/getpeername.texi: Likewise.
* doc/posix-functions/getsockname.texi: Likewise.
* doc/posix-functions/getsockopt.texi: Likewise.
* doc/posix-functions/recvfrom.texi: Likewise.
---
 ChangeLog                            | 17 +++++++++++++++++
 doc/posix-functions/accept.texi      |  5 +++++
 doc/posix-functions/getpeername.texi |  5 +++++
 doc/posix-functions/getsockname.texi |  5 +++++
 doc/posix-functions/getsockopt.texi  |  5 +++++
 doc/posix-functions/recvfrom.texi    |  5 +++++
 m4/extensions.m4                     |  8 +++++++-
 m4/socketlib.m4                      |  6 +++++-
 modules/accept                       |  1 +
 modules/getpeername                  |  1 +
 modules/getsockname                  |  1 +
 modules/getsockopt                   |  1 +
 modules/recvfrom                     |  1 +
 13 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 70d4219..e4e24f6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,22 @@
 2018-01-27  Bruno Haible  <br...@clisp.org>
 
+	Fix malfunction of socket functions on HP-UX in 64-bit mode.
+	* m4/socketlib.m4 (gl_SOCKETLIB): Add comment.
+	* m4/extensions.m4 (AC_USE_SYSTEM_EXTENSIONS): Define
+	_HPUX_ALT_XOPEN_SOCKET_API.
+	* modules/accept (Depends-on): Add 'extensions'.
+	* modules/getpeername (Depends-on): Likewise.
+	* modules/getsockname (Depends-on): Likewise.
+	* modules/getsockopt (Depends-on): Likewise.
+	* modules/recvfrom (Depends-on): Likewise.
+	* doc/posix-functions/accept.texi: Mention the HP-UX socklen_t problem.
+	* doc/posix-functions/getpeername.texi: Likewise.
+	* doc/posix-functions/getsockname.texi: Likewise.
+	* doc/posix-functions/getsockopt.texi: Likewise.
+	* doc/posix-functions/recvfrom.texi: Likewise.
+
+2018-01-27  Bruno Haible  <br...@clisp.org>
+
 	getsockname tests: More tests.
 	* tests/test-getsockname.c (open_server_socket): New function, mostly
 	copied from test-poll.c.
diff --git a/doc/posix-functions/accept.texi b/doc/posix-functions/accept.texi
index a92ea3f..b1216ee 100644
--- a/doc/posix-functions/accept.texi
+++ b/doc/posix-functions/accept.texi
@@ -17,6 +17,11 @@ the @code{accept} function cannot be used in calls to @code{read},
 On Windows platforms (excluding Cygwin), error codes from this function
 are not placed in @code{errno}, and @code{WSAGetLastError} must be used
 instead.
+@item
+On HP-UX 11, in 64-bit mode, when the macro @code{_HPUX_ALT_XOPEN_SOCKET_API}
+is not defined, this function behaves incorrectly because it is declared
+to take a pointer to a 64-bit wide @code{socklen_t} entity but in fact
+considers it as a pointer to a 32-bit wide @code{unsigned int} entity.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/doc/posix-functions/getpeername.texi b/doc/posix-functions/getpeername.texi
index 5b2776e..8476e0a 100644
--- a/doc/posix-functions/getpeername.texi
+++ b/doc/posix-functions/getpeername.texi
@@ -12,6 +12,11 @@ Portability problems fixed by Gnulib:
 On Windows platforms (excluding Cygwin), error codes from this function
 are not placed in @code{errno}, and @code{WSAGetLastError} must be used
 instead.
+@item
+On HP-UX 11, in 64-bit mode, when the macro @code{_HPUX_ALT_XOPEN_SOCKET_API}
+is not defined, this function behaves incorrectly because it is declared
+to take a pointer to a 64-bit wide @code{socklen_t} entity but in fact
+considers it as a pointer to a 32-bit wide @code{unsigned int} entity.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/doc/posix-functions/getsockname.texi b/doc/posix-functions/getsockname.texi
index 7d462a7..714565d 100644
--- a/doc/posix-functions/getsockname.texi
+++ b/doc/posix-functions/getsockname.texi
@@ -12,6 +12,11 @@ Portability problems fixed by Gnulib:
 On Windows platforms (excluding Cygwin), error codes from this function
 are not placed in @code{errno}, and @code{WSAGetLastError} must be used
 instead.
+@item
+On HP-UX 11, in 64-bit mode, when the macro @code{_HPUX_ALT_XOPEN_SOCKET_API}
+is not defined, this function behaves incorrectly because it is declared
+to take a pointer to a 64-bit wide @code{socklen_t} entity but in fact
+considers it as a pointer to a 32-bit wide @code{unsigned int} entity.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/doc/posix-functions/getsockopt.texi b/doc/posix-functions/getsockopt.texi
index 9e7d26e..f15c934 100644
--- a/doc/posix-functions/getsockopt.texi
+++ b/doc/posix-functions/getsockopt.texi
@@ -12,6 +12,11 @@ Portability problems fixed by Gnulib:
 On Windows platforms (excluding Cygwin), error codes from this function
 are not placed in @code{errno}, and @code{WSAGetLastError} must be used
 instead.
+@item
+On HP-UX 11, in 64-bit mode, when the macro @code{_HPUX_ALT_XOPEN_SOCKET_API}
+is not defined, this function behaves incorrectly because it is declared
+to take a pointer to a 64-bit wide @code{socklen_t} entity but in fact
+considers it as a pointer to a 32-bit wide @code{unsigned int} entity.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/doc/posix-functions/recvfrom.texi b/doc/posix-functions/recvfrom.texi
index f591d0c..251ed5c 100644
--- a/doc/posix-functions/recvfrom.texi
+++ b/doc/posix-functions/recvfrom.texi
@@ -16,6 +16,11 @@ OSF/1 5.1.
 On Windows platforms (excluding Cygwin), error codes from this function
 are not placed in @code{errno}, and @code{WSAGetLastError} must be used
 instead.
+@item
+On HP-UX 11, in 64-bit mode, when the macro @code{_HPUX_ALT_XOPEN_SOCKET_API}
+is not defined, this function behaves incorrectly because it is declared
+to take a pointer to a 64-bit wide @code{socklen_t} entity but in fact
+considers it as a pointer to a 32-bit wide @code{unsigned int} entity.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/m4/extensions.m4 b/m4/extensions.m4
index d1b2321..71a854f 100644
--- a/m4/extensions.m4
+++ b/m4/extensions.m4
@@ -1,4 +1,4 @@
-# serial 17  -*- Autoconf -*-
+# serial 18  -*- Autoconf -*-
 # Enable extensions on systems that normally disable them.
 
 # Copyright (C) 2003, 2006-2018 Free Software Foundation, Inc.
@@ -118,6 +118,11 @@ dnl configure.ac when using autoheader 2.62.
 #ifndef _XOPEN_SOURCE
 # undef _XOPEN_SOURCE
 #endif
+/* Enable X/Open compliant socket functions that do not require linking
+   with -lxnet on HP-UX 11.11.  */
+#ifndef _HPUX_ALT_XOPEN_SOCKET_API
+# undef _HPUX_ALT_XOPEN_SOCKET_API
+#endif
 /* Enable general extensions on Solaris.  */
 #ifndef __EXTENSIONS__
 # undef __EXTENSIONS__
@@ -163,6 +168,7 @@ dnl configure.ac when using autoheader 2.62.
           [ac_cv_should_define__xopen_source=yes])])])
   test $ac_cv_should_define__xopen_source = yes &&
     AC_DEFINE([_XOPEN_SOURCE], [500])
+  AC_DEFINE([_HPUX_ALT_XOPEN_SOCKET_API])
 ])# AC_USE_SYSTEM_EXTENSIONS
 
 # gl_USE_SYSTEM_EXTENSIONS
diff --git a/m4/socketlib.m4 b/m4/socketlib.m4
index ca240b1..a725d3c 100644
--- a/m4/socketlib.m4
+++ b/m4/socketlib.m4
@@ -1,4 +1,4 @@
-# socketlib.m4 serial 1
+# socketlib.m4 serial 2
 dnl Copyright (C) 2008-2018 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -38,6 +38,10 @@ AC_DEFUN([gl_SOCKETLIB],
     dnl Solaris has most socket functions in libsocket.
     dnl Haiku has most socket functions in libnetwork.
     dnl BeOS has most socket functions in libnet.
+    dnl On HP-UX, do NOT link with libxnet, because in 64-bit mode this would
+    dnl break code (e.g. in libraries) that invokes accept(), getpeername(),
+    dnl getsockname(), getsockopt(), or recvfrom() with a 32-bit addrlen. See
+    dnl "man xopen_networking" for details.
     AC_CACHE_CHECK([for library containing setsockopt], [gl_cv_lib_socket], [
       gl_cv_lib_socket=
       AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern
diff --git a/modules/accept b/modules/accept
index 059a56d..b997566 100644
--- a/modules/accept
+++ b/modules/accept
@@ -6,6 +6,7 @@ lib/accept.c
 lib/w32sock.h
 
 Depends-on:
+extensions
 sys_socket
 socketlib
 errno           [test "$ac_cv_header_winsock2_h" = yes]
diff --git a/modules/getpeername b/modules/getpeername
index d1ef822..53f077b 100644
--- a/modules/getpeername
+++ b/modules/getpeername
@@ -7,6 +7,7 @@ lib/getpeername.c
 lib/w32sock.h
 
 Depends-on:
+extensions
 sys_socket
 socketlib
 errno           [test "$ac_cv_header_winsock2_h" = yes]
diff --git a/modules/getsockname b/modules/getsockname
index 15cf490..8a8ffe0 100644
--- a/modules/getsockname
+++ b/modules/getsockname
@@ -7,6 +7,7 @@ lib/getsockname.c
 lib/w32sock.h
 
 Depends-on:
+extensions
 sys_socket
 socketlib
 errno           [test "$ac_cv_header_winsock2_h" = yes]
diff --git a/modules/getsockopt b/modules/getsockopt
index 1cd1f2e..adb4b87 100644
--- a/modules/getsockopt
+++ b/modules/getsockopt
@@ -6,6 +6,7 @@ lib/getsockopt.c
 lib/w32sock.h
 
 Depends-on:
+extensions
 sys_socket
 socketlib
 sys_time        [test "$ac_cv_header_winsock2_h" = yes]
diff --git a/modules/recvfrom b/modules/recvfrom
index 2b051b4..590f6fe 100644
--- a/modules/recvfrom
+++ b/modules/recvfrom
@@ -6,6 +6,7 @@ lib/recvfrom.c
 lib/w32sock.h
 
 Depends-on:
+extensions
 sys_socket
 socketlib
 errno           [test "$ac_cv_header_winsock2_h" = yes]
-- 
2.7.4

Reply via email to