diff options
| author | Rich Felker <dalias@aerifal.cx> | 2019-07-30 22:11:39 -0400 | 
|---|---|---|
| committer | Rich Felker <dalias@aerifal.cx> | 2019-07-31 20:20:57 -0400 | 
| commit | 51fd67fcbfa598e2fe1885b517451b84c0bfe3b7 (patch) | |
| tree | f1c8e0b65cc7d98ee0c0100276c74f5e78f6dc33 | |
| parent | 59324c8b0950ee94db846a50554183c845ede160 (diff) | |
| download | musl-51fd67fcbfa598e2fe1885b517451b84c0bfe3b7.tar.gz | |
get/setsockopt: add fallback for new time64 SO_RCVTIMEO/SO_SNDTIMEO
without this, the SO_RCVTIMEO and SO_SNDTIMEO socket options would
stop working on pre-5.1 kernels after time_t is switched to 64-bit and
their values are changed to the new time64 versions.
new code is written such that it's statically unreachable on 64-bit
archs, and on existing 32-bit archs until the macro values are changed
to activate 64-bit time_t.
| -rw-r--r-- | arch/mips/syscall_arch.h | 3 | ||||
| -rw-r--r-- | arch/mips64/syscall_arch.h | 3 | ||||
| -rw-r--r-- | arch/mipsn32/syscall_arch.h | 3 | ||||
| -rw-r--r-- | arch/powerpc/syscall_arch.h | 3 | ||||
| -rw-r--r-- | arch/powerpc64/syscall_arch.h | 3 | ||||
| -rw-r--r-- | src/internal/syscall.h | 7 | ||||
| -rw-r--r-- | src/network/getsockopt.c | 27 | ||||
| -rw-r--r-- | src/network/setsockopt.c | 32 | 
8 files changed, 79 insertions, 2 deletions
diff --git a/arch/mips/syscall_arch.h b/arch/mips/syscall_arch.h index e4854f50..2ef8a952 100644 --- a/arch/mips/syscall_arch.h +++ b/arch/mips/syscall_arch.h @@ -141,3 +141,6 @@ static inline long __syscall7(long n, long a, long b, long c, long d, long e, lo  #define VDSO_USEFUL  #define VDSO_CGT_SYM "__vdso_clock_gettime"  #define VDSO_CGT_VER "LINUX_2.6" + +#define SO_SNDTIMEO_OLD 0x1005 +#define SO_RCVTIMEO_OLD 0x1006 diff --git a/arch/mips64/syscall_arch.h b/arch/mips64/syscall_arch.h index 852ac263..013908dd 100644 --- a/arch/mips64/syscall_arch.h +++ b/arch/mips64/syscall_arch.h @@ -117,3 +117,6 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo  #define VDSO_USEFUL  #define VDSO_CGT_SYM "__vdso_clock_gettime"  #define VDSO_CGT_VER "LINUX_2.6" + +#define SO_SNDTIMEO_OLD 0x1005 +#define SO_RCVTIMEO_OLD 0x1006 diff --git a/arch/mipsn32/syscall_arch.h b/arch/mipsn32/syscall_arch.h index 78b217fa..5a6da0ed 100644 --- a/arch/mipsn32/syscall_arch.h +++ b/arch/mipsn32/syscall_arch.h @@ -112,3 +112,6 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo  #define VDSO_USEFUL  #define VDSO_CGT_SYM "__vdso_clock_gettime"  #define VDSO_CGT_VER "LINUX_2.6" + +#define SO_SNDTIMEO_OLD 0x1005 +#define SO_RCVTIMEO_OLD 0x1006 diff --git a/arch/powerpc/syscall_arch.h b/arch/powerpc/syscall_arch.h index e26a3c34..ede97c1c 100644 --- a/arch/powerpc/syscall_arch.h +++ b/arch/powerpc/syscall_arch.h @@ -89,3 +89,6 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo  }  #define SYSCALL_FADVISE_6_ARG + +#define SO_RCVTIMEO_OLD  18 +#define SO_SNDTIMEO_OLD  19 diff --git a/arch/powerpc64/syscall_arch.h b/arch/powerpc64/syscall_arch.h index 1e730625..76b4e335 100644 --- a/arch/powerpc64/syscall_arch.h +++ b/arch/powerpc64/syscall_arch.h @@ -85,3 +85,6 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo  	:: "memory", "cr0", "r9", "r10", "r11", "r12");  	return r3;  } + +#define SO_RCVTIMEO_OLD  18 +#define SO_SNDTIMEO_OLD  19 diff --git a/src/internal/syscall.h b/src/internal/syscall.h index 5db18b05..16edf30a 100644 --- a/src/internal/syscall.h +++ b/src/internal/syscall.h @@ -299,6 +299,13 @@ hidden long __syscall_ret(unsigned long),  #define __SC_recvmmsg    19  #define __SC_sendmmsg    20 +#ifndef SO_RCVTIMEO_OLD +#define SO_RCVTIMEO_OLD  20 +#endif +#ifndef SO_SNDTIMEO_OLD +#define SO_SNDTIMEO_OLD  21 +#endif +  #ifdef SYS_open  #define __sys_open2(x,pn,fl) __syscall2(SYS_open, pn, (fl)|O_LARGEFILE)  #define __sys_open3(x,pn,fl,mo) __syscall3(SYS_open, pn, (fl)|O_LARGEFILE, mo) diff --git a/src/network/getsockopt.c b/src/network/getsockopt.c index 28079d8c..e871d624 100644 --- a/src/network/getsockopt.c +++ b/src/network/getsockopt.c @@ -1,7 +1,32 @@  #include <sys/socket.h> +#include <sys/time.h> +#include <errno.h>  #include "syscall.h"  int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t *restrict optlen)  { -	return socketcall(getsockopt, fd, level, optname, optval, optlen, 0); +	long tv32[2]; +	struct timeval *tv; + +	int r = __socketcall(getsockopt, fd, level, optname, optval, optlen, 0); + +	if (r==-ENOPROTOOPT) switch (level) { +	case SOL_SOCKET: +		switch (optname) { +		case SO_RCVTIMEO: +		case SO_SNDTIMEO: +			if (SO_RCVTIMEO == SO_RCVTIMEO_OLD) break; +			if (*optlen < sizeof *tv) return __syscall_ret(-EINVAL); +			if (optname==SO_RCVTIMEO) optname=SO_RCVTIMEO_OLD; +			if (optname==SO_SNDTIMEO) optname=SO_SNDTIMEO_OLD; +			r = __socketcall(getsockopt, fd, level, optname, +				tv32, (socklen_t[]){sizeof tv32}, 0); +			if (r<0) break; +			tv = optval; +			tv->tv_sec = tv32[0]; +			tv->tv_usec = tv32[1]; +			*optlen = sizeof *tv; +		} +	} +	return __syscall_ret(r);  } diff --git a/src/network/setsockopt.c b/src/network/setsockopt.c index c960c9ca..2c188a96 100644 --- a/src/network/setsockopt.c +++ b/src/network/setsockopt.c @@ -1,7 +1,37 @@  #include <sys/socket.h> +#include <sys/time.h> +#include <errno.h>  #include "syscall.h" +#define IS32BIT(x) !((x)+0x80000000ULL>>32) +#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63)) +  int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)  { -	return socketcall(setsockopt, fd, level, optname, optval, optlen, 0); +	const struct timeval *tv; +	time_t s; +	suseconds_t us; + +	int r = __socketcall(setsockopt, fd, level, optname, optval, optlen, 0); + +	if (r==-ENOPROTOOPT) switch (level) { +	case SOL_SOCKET: +		switch (optname) { +		case SO_RCVTIMEO: +		case SO_SNDTIMEO: +			if (SO_RCVTIMEO == SO_RCVTIMEO_OLD) break; +			if (optlen < sizeof *tv) return __syscall_ret(-EINVAL); +			tv = optval; +			s = tv->tv_sec; +			us = tv->tv_usec; +			if (!IS32BIT(s)) return __syscall_ret(-ENOTSUP); + +			if (optname==SO_RCVTIMEO) optname=SO_RCVTIMEO_OLD; +			if (optname==SO_SNDTIMEO) optname=SO_SNDTIMEO_OLD; + +			r = __socketcall(setsockopt, fd, level, optname, +				((long[]){s, CLAMP(us)}), 2*sizeof(long), 0); +		} +	} +	return __syscall_ret(r);  }  | 
