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 /src/network/setsockopt.c | |
parent | 59324c8b0950ee94db846a50554183c845ede160 (diff) | |
download | musl-51fd67fcbfa598e2fe1885b517451b84c0bfe3b7.tar.gz musl-51fd67fcbfa598e2fe1885b517451b84c0bfe3b7.tar.bz2 musl-51fd67fcbfa598e2fe1885b517451b84c0bfe3b7.tar.xz musl-51fd67fcbfa598e2fe1885b517451b84c0bfe3b7.zip |
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.
Diffstat (limited to 'src/network/setsockopt.c')
-rw-r--r-- | src/network/setsockopt.c | 32 |
1 files changed, 31 insertions, 1 deletions
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); } |