From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
To: libc-alpha@sourceware.org
Subject: [RFC 12/14] linux: Add fallback for 64-bit time_t SO_{RCV,SND}TIMEO
Date: Tue, 8 Sep 2020 11:57:36 -0300 [thread overview]
Message-ID: <20200908145738.640039-12-adhemerval.zanella@linaro.org> (raw)
In-Reply-To: <20200908145738.640039-1-adhemerval.zanella@linaro.org>
The constant value will be changed for __TIMESIZE=64, so binaries built
with 64-bit time support might fail to work properly on old kernels.
Both {get,set}sockopt will retry the syscall with the old constant
values and the timeout value adjusted when kernel returns ENOTPROTOPT.
It also changes to SO_{RCV,SND}TIMEO to follow the uapi kernel values
where SO_{RCV,SND}TIMEO_OLD indicates pre 64-bit time support and
SO_{RCV,SND}TIMEO_NEW indicate time64 support. It allows to refer to
constant independently of the time_t abi used (since kernel defines
SO_{RCV,SND}TIMEO depending of the time_t size).
The hppa, mips, powerpc, and sparc provides its own socket-constant.h,
which are also updated the the SO_{RCV,SND}TIMEO constants (they are
missed on 019d828669df966 patch).
Checked on x86_64-linux-gnu and i686-linux-gnu (on 5.4 and on 4.15
kernel).
---
.../unix/sysv/linux/bits/socket-constants.h | 19 ++---
sysdeps/unix/sysv/linux/getsockopt.c | 72 ++++++++++++++++--
.../sysv/linux/hppa/bits/socket-constants.h | 15 +++-
.../sysv/linux/mips/bits/socket-constants.h | 17 ++++-
.../linux/powerpc/bits/socket-constants.h | 19 ++++-
sysdeps/unix/sysv/linux/setsockopt.c | 76 +++++++++++++++++--
.../sysv/linux/sparc/bits/socket-constants.h | 17 ++++-
7 files changed, 202 insertions(+), 33 deletions(-)
diff --git a/sysdeps/unix/sysv/linux/bits/socket-constants.h b/sysdeps/unix/sysv/linux/bits/socket-constants.h
index d02e1cbc7c..c7478651fb 100644
--- a/sysdeps/unix/sysv/linux/bits/socket-constants.h
+++ b/sysdeps/unix/sysv/linux/bits/socket-constants.h
@@ -32,19 +32,20 @@
#define SO_OOBINLINE 10
#define SO_RCVBUF 8
#define SO_RCVLOWAT 18
-#if (__TIMESIZE == 64 && __WORDSIZE == 32 \
- && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32))
-# define SO_RCVTIMEO 66
-#else
-# define SO_RCVTIMEO 20
-#endif
#define SO_REUSEADDR 2
#define SO_SNDBUF 7
#define SO_SNDLOWAT 19
+#define SO_TYPE 3
+
+#define SO_RCVTIMEO_OLD 20
+#define SO_SNDTIMEO_OLD 21
+#define SO_RCVTIMEO_NEW 66
+#define SO_SNDTIMEO_NEW 67
#if (__TIMESIZE == 64 && __WORDSIZE == 32 \
&& (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32))
-# define SO_SNDTIMEO 67
+# define SO_RCVTIMEO SO_RCVTIMEO_NEW
+# define SO_SNDTIMEO SO_SNDTIMEO_NEW
#else
-# define SO_SNDTIMEO 21
+# define SO_RCVTIMEO SO_RCVTIMEO_OLD
+# define SO_SNDTIMEO SO_SNDTIMEO_OLD
#endif
-#define SO_TYPE 3
diff --git a/sysdeps/unix/sysv/linux/getsockopt.c b/sysdeps/unix/sysv/linux/getsockopt.c
index 11939660c1..5dce0e29ee 100644
--- a/sysdeps/unix/sysv/linux/getsockopt.c
+++ b/sysdeps/unix/sysv/linux/getsockopt.c
@@ -15,16 +15,20 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#include <errno.h>
-#include <signal.h>
#include <sys/socket.h>
-
+/* The kernel header with SO_* constants is used as default for _GNU_SOURCE,
+ however the new constants that describe 64-bit time support were added
+ only on v5.1. */
+#if !defined(SO_RCVTIMEO_NEW) || !defined(SO_RCVTIMEO_OLD)
+# include <bits/socket-constants.h>
+#endif
+#include <time.h>
+#include <sysdep.h>
#include <socketcall.h>
-#include <kernel-features.h>
-#include <sys/syscall.h>
-int
-__getsockopt (int fd, int level, int optname, void *optval, socklen_t *len)
+static int
+getsockopt_syscall (int fd, int level, int optname, void *optval,
+ socklen_t *len)
{
#ifdef __ASSUME_GETSOCKOPT_SYSCALL
return INLINE_SYSCALL (getsockopt, 5, fd, level, optname, optval, len);
@@ -32,4 +36,58 @@ __getsockopt (int fd, int level, int optname, void *optval, socklen_t *len)
return SOCKETCALL (getsockopt, fd, level, optname, optval, len);
#endif
}
+
+#ifndef __ASSUME_TIME64_SYSCALLS
+static int
+getsockopt32 (int fd, int level, int optname, void *optval,
+ socklen_t *len)
+{
+ int r = -1;
+
+ if (level != SOL_SOCKET)
+ return r;
+
+ switch (optname)
+ {
+ case SO_RCVTIMEO_NEW:
+ case SO_SNDTIMEO_NEW:
+ {
+ if (*len < sizeof (struct __timeval64))
+ {
+ __set_errno (EINVAL);
+ break;
+ }
+
+ if (optname == SO_RCVTIMEO_NEW)
+ optname = SO_RCVTIMEO_OLD;
+ if (optname == SO_SNDTIMEO_NEW)
+ optname = SO_SNDTIMEO_OLD;
+
+ struct __timeval32 tv32;
+ r = getsockopt_syscall (fd, level, optname, &tv32,
+ (socklen_t[]) { sizeof tv32 });
+ if (r < 0)
+ break;
+ struct __timeval64 *tv64 = (struct __timeval64 *) optval;
+ *tv64 = valid_timeval32_to_timeval64 (tv32);
+ *len = sizeof (*tv64);
+ }
+ }
+
+ return r;
+}
+#endif
+
+int
+__getsockopt (int fd, int level, int optname, void *optval, socklen_t *len)
+{
+ int r = getsockopt_syscall (fd, level, optname, optval, len);
+
+#ifndef __ASSUME_TIME64_SYSCALLS
+ if (r == -1 && errno == ENOPROTOOPT)
+ r = getsockopt32 (fd, level, optname, optval, len);
+#endif
+
+ return r;
+}
weak_alias (__getsockopt, getsockopt)
diff --git a/sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h b/sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h
index fda7f95d44..eca5fe045c 100644
--- a/sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h
+++ b/sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h
@@ -30,9 +30,20 @@
#define SO_OOBINLINE 256
#define SO_RCVBUF 4098
#define SO_RCVLOWAT 4100
-#define SO_RCVTIMEO 4102
#define SO_REUSEADDR 4
#define SO_SNDBUF 4097
#define SO_SNDLOWAT 4099
-#define SO_SNDTIMEO 4101
#define SO_TYPE 4104
+
+#define SO_RCVTIMEO_OLD 4102
+#define SO_SNDTIMEO_OLD 4101
+#define SO_RCVTIMEO_NEW 16448
+#define SO_SNDTIMEO_NEW 16449
+#if (__TIMESIZE == 64 && __WORDSIZE == 32 \
+ && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32))
+# define SO_RCVTIMEO SO_RCVTIMEO_NEW
+# define SO_SNDTIMEO SO_SNDTIMEO_NEW
+#else
+# define SO_RCVTIMEO SO_RCVTIMEO_OLD
+# define SO_SNDTIMEO SO_SNDTIMEO_OLD
+#endif
diff --git a/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h b/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h
index daa47c6c7c..961fad21b8 100644
--- a/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h
+++ b/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h
@@ -20,6 +20,8 @@
# error "Never include <bits/socket-constants.h> directly; use <sys/socket.h> instead."
#endif
+#include <bits/timesize.h>
+
#define SOL_SOCKET 65535
#define SO_ACCEPTCONN 4105
#define SO_BROADCAST 32
@@ -30,9 +32,20 @@
#define SO_OOBINLINE 256
#define SO_RCVBUF 4098
#define SO_RCVLOWAT 4100
-#define SO_RCVTIMEO 4102
#define SO_REUSEADDR 4
#define SO_SNDBUF 4097
#define SO_SNDLOWAT 4099
-#define SO_SNDTIMEO 4101
#define SO_TYPE 4104
+
+#define SO_RCVTIMEO_OLD 4100
+#define SO_SNDTIMEO_OLD 4101
+#define SO_RCVTIMEO_NEW 66
+#define SO_SNDTIMEO_NEW 67
+#if (__TIMESIZE == 64 && __WORDSIZE == 32 \
+ && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32))
+# define SO_RCVTIMEO SO_RCVTIMEO_NEW
+# define SO_SNDTIMEO SO_SNDTIMEO_NEW
+#else
+# define SO_RCVTIMEO SO_RCVTIMEO_OLD
+# define SO_SNDTIMEO SO_SNDTIMEO_OLD
+#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h b/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h
index 77fc8b207e..d0ec3cb4fc 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h
@@ -20,6 +20,8 @@
# error "Never include <bits/socket-constants.h> directly; use <sys/socket.h> instead."
#endif
+#include <bits/timesize.h>
+
#define SOL_SOCKET 1
#define SO_ACCEPTCONN 30
#define SO_BROADCAST 6
@@ -30,9 +32,20 @@
#define SO_OOBINLINE 10
#define SO_RCVBUF 8
#define SO_RCVLOWAT 16
-#define SO_RCVTIMEO 18
#define SO_REUSEADDR 2
#define SO_SNDBUF 7
-#define SO_SNDLOWAT 17
-#define SO_SNDTIMEO 19
+#define SO_SNDTIMEO 67
#define SO_TYPE 3
+
+#define SO_RCVTIMEO_OLD 18
+#define SO_SNDTIMEO_OLD 19
+#define SO_RCVTIMEO_NEW 66
+#define SO_SNDTIMEO_NEW 67
+#if (__TIMESIZE == 64 && __WORDSIZE == 32 \
+ && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32))
+# define SO_RCVTIMEO SO_RCVTIMEO_NEW
+# define SO_SNDTIMEO SO_SNDTIMEO_NEW
+#else
+# define SO_RCVTIMEO SO_RCVTIMEO_OLD
+# define SO_SNDTIMEO SO_SNDTIMEO_OLD
+#endif
diff --git a/sysdeps/unix/sysv/linux/setsockopt.c b/sysdeps/unix/sysv/linux/setsockopt.c
index 20c0868783..ebc32d788c 100644
--- a/sysdeps/unix/sysv/linux/setsockopt.c
+++ b/sysdeps/unix/sysv/linux/setsockopt.c
@@ -15,21 +15,81 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#include <errno.h>
-#include <signal.h>
#include <sys/socket.h>
-
+/* The kernel header with SO_* constants is used as default for _GNU_SOURCE,
+ however the new constants that describe 64-bit time support were added
+ only on v5.1. */
+#if !defined(SO_RCVTIMEO_NEW) || !defined(SO_RCVTIMEO_OLD)
+# include <bits/socket-constants.h>
+#endif
+#include <time.h>
+#include <sysdep.h>
#include <socketcall.h>
-#include <kernel-features.h>
-#include <sys/syscall.h>
-int
-setsockopt (int fd, int level, int optname, const void *optval, socklen_t len)
+static int
+setsockopt_syscall (int fd, int level, int optname, const void *optval,
+ socklen_t len)
{
#ifdef __ASSUME_SETSOCKOPT_SYSCALL
- return INLINE_SYSCALL (setsockopt, 5, fd, level, optname, optval, len);
+ return INLINE_SYSCALL_CALL (setsockopt, fd, level, optname, optval, len);
#else
return SOCKETCALL (setsockopt, fd, level, optname, optval, len);
#endif
}
+
+#ifndef __ASSUME_TIME64_SYSCALLS
+static int
+setsockopt32 (int fd, int level, int optname, const void *optval,
+ socklen_t len)
+{
+ int r = -1;
+
+ if (level != SOL_SOCKET)
+ return r;
+
+ switch (optname)
+ {
+ case SO_RCVTIMEO_NEW:
+ case SO_SNDTIMEO_NEW:
+ {
+ if (len < sizeof (struct __timeval64))
+ {
+ __set_errno (EINVAL);
+ break;
+ }
+
+ struct __timeval64 *tv64 = (struct __timeval64 *) optval;
+ if (! in_time_t_range (tv64->tv_sec))
+ {
+ __set_errno (EOVERFLOW);
+ break;
+ }
+
+ if (optname == SO_RCVTIMEO_NEW)
+ optname = SO_RCVTIMEO_OLD;
+ if (optname == SO_SNDTIMEO_NEW)
+ optname = SO_SNDTIMEO_OLD;
+
+ struct __timeval32 tv32 = valid_timeval64_to_timeval32 (*tv64);
+
+ r = setsockopt_syscall (fd, level, optname, &tv32, sizeof (tv32));
+ }
+ }
+
+ return r;
+}
+#endif
+
+int
+setsockopt (int fd, int level, int optname, const void *optval, socklen_t len)
+{
+ int r = setsockopt_syscall (fd, level, optname, optval, len);
+
+#ifndef __ASSUME_TIME64_SYSCALLS
+ if (r == -1 && errno == ENOPROTOOPT)
+ r = setsockopt32 (fd, level, optname, optval, len);
+#endif
+
+ return r;
+}
weak_alias (setsockopt, __setsockopt)
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h b/sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h
index 6ef575e521..d4bf8f79d6 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h
@@ -20,6 +20,8 @@
# error "Never include <bits/socket-constants.h> directly; use <sys/socket.h> instead."
#endif
+#include <bits/timesize.h>
+
#define SOL_SOCKET 65535
#define SO_ACCEPTCONN 32768
#define SO_BROADCAST 32
@@ -30,9 +32,20 @@
#define SO_OOBINLINE 256
#define SO_RCVBUF 4098
#define SO_RCVLOWAT 2048
-#define SO_RCVTIMEO 8192
#define SO_REUSEADDR 4
#define SO_SNDBUF 4097
#define SO_SNDLOWAT 4096
-#define SO_SNDTIMEO 16384
#define SO_TYPE 4104
+
+#define SO_RCVTIMEO_OLD 8192
+#define SO_SNDTIMEO_OLD 16384
+#define SO_RCVTIMEO_NEW 68
+#define SO_SNDTIMEO_NEW 69
+#if (__TIMESIZE == 64 && __WORDSIZE == 32 \
+ && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32))
+# define SO_RCVTIMEO SO_RCVTIMEO_NEW
+# define SO_SNDTIMEO SO_SNDTIMEO_NEW
+#else
+# define SO_RCVTIMEO SO_RCVTIMEO_OLD
+# define SO_SNDTIMEO SO_SNDTIMEO_OLD
+#endif
--
2.25.1
next prev parent reply other threads:[~2020-09-08 14:58 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-08 14:57 [PATCH v2 01/14] linux: Simplify clock_getres Adhemerval Zanella
2020-09-08 14:57 ` [PATCH v2 02/14] linux: Add ppoll time64 optimization Adhemerval Zanella
2020-09-10 19:21 ` Alistair Francis
2020-09-08 14:57 ` [PATCH v2 03/14] linux: Add time64 semtimedop support Adhemerval Zanella
2020-09-10 19:23 ` Alistair Francis
2020-09-08 14:57 ` [PATCH v2 04/14] linux: Add time64 pselect support Adhemerval Zanella
2020-09-10 19:35 ` Alistair Francis
2020-09-12 1:22 ` H.J. Lu
2020-09-08 14:57 ` [PATCH v2 05/14] linux: Add time64 select support Adhemerval Zanella
2020-09-11 20:44 ` Alistair Francis
2020-09-08 14:57 ` [PATCH v2 06/14] linux: Add time64 sigtimedwait support Adhemerval Zanella
2020-09-11 20:56 ` Alistair Francis
2020-09-08 14:57 ` [PATCH v2 07/14] linux: Use 64-bit time_t syscall on clock_getcputclockid Adhemerval Zanella
2020-09-16 15:26 ` Alistair Francis
2020-09-08 14:57 ` [PATCH v2 08/14] linux: Consolidate utimes Adhemerval Zanella
2020-09-16 15:30 ` Alistair Francis
2020-09-08 14:57 ` [PATCH v2 09/14] linux: Fix time64 support for futimesat Adhemerval Zanella
2020-09-08 14:57 ` [PATCH v2 10/14] linux: Add time64 support for nanosleep Adhemerval Zanella
2020-09-16 17:16 ` Alistair Francis
2020-09-08 14:57 ` [PATCH v2 11/14] linux: Add time64 recvmmsg support Adhemerval Zanella
2020-09-25 21:18 ` Alistair Francis
2020-09-08 14:57 ` Adhemerval Zanella [this message]
2020-09-08 14:57 ` [RFC 13/14] linux: Add fallback for 64-bit time_t SO_TIMESTAMP{NS} Adhemerval Zanella
2020-09-08 14:57 ` [RFC 14/14] linux: Add recvvmsg " Adhemerval Zanella
2020-09-10 19:20 ` [PATCH v2 01/14] linux: Simplify clock_getres Alistair Francis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200908145738.640039-12-adhemerval.zanella@linaro.org \
--to=adhemerval.zanella@linaro.org \
--cc=libc-alpha@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).