mirror of git://git.musl-libc.org/musl
hook recvmmsg up to SO_TIMESTAMP[NS] fallback for pre-time64 kernels
always try the time64 syscall first since we can use its success to conclude that no conversion is needed (any setsockopt for the timestamp options would have succeeded without need for fallbacks). otherwise, we have to remember the original controllen for each msghdr, requiring O(vlen) space, so vlen must be bounded. linux clamps it to IOV_MAX for sendmmsg only (not recvmmsg), but doing the same for recvmmsg is not unreasonable, especially since the limitation will only apply to old kernels. we could optimize to avoid trying SYS_recvmmsg_time64 first if all msghdrs have controllen zero, or support unlimited vlen by looping and emulating the timeout logic, but I'm not inclined to do complex and error-prone optimizations on a function that has so many underlying problems it should really never be used.
This commit is contained in:
parent
ae388becb5
commit
114178dc8d
|
@ -8,6 +8,8 @@
|
||||||
#define IS32BIT(x) !((x)+0x80000000ULL>>32)
|
#define IS32BIT(x) !((x)+0x80000000ULL>>32)
|
||||||
#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
|
#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
|
||||||
|
|
||||||
|
hidden void __convert_scm_timestamps(struct msghdr *, socklen_t);
|
||||||
|
|
||||||
int recvmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec *timeout)
|
int recvmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec *timeout)
|
||||||
{
|
{
|
||||||
#if LONG_MAX > INT_MAX
|
#if LONG_MAX > INT_MAX
|
||||||
|
@ -19,14 +21,18 @@ int recvmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int fla
|
||||||
#ifdef SYS_recvmmsg_time64
|
#ifdef SYS_recvmmsg_time64
|
||||||
time_t s = timeout ? timeout->tv_sec : 0;
|
time_t s = timeout ? timeout->tv_sec : 0;
|
||||||
long ns = timeout ? timeout->tv_nsec : 0;
|
long ns = timeout ? timeout->tv_nsec : 0;
|
||||||
int r = -ENOSYS;
|
int r = __syscall_cp(SYS_recvmmsg_time64, fd, msgvec, vlen, flags,
|
||||||
if (SYS_recvmmsg == SYS_recvmmsg_time64 || !IS32BIT(s))
|
|
||||||
r = __syscall_cp(SYS_recvmmsg_time64, fd, msgvec, vlen, flags,
|
|
||||||
timeout ? ((long long[]){s, ns}) : 0);
|
timeout ? ((long long[]){s, ns}) : 0);
|
||||||
if (SYS_recvmmsg == SYS_recvmmsg_time64 || r!=-ENOSYS)
|
if (SYS_recvmmsg == SYS_recvmmsg_time64 || r!=-ENOSYS)
|
||||||
return __syscall_ret(r);
|
return __syscall_ret(r);
|
||||||
return syscall_cp(SYS_recvmmsg, fd, msgvec, vlen, flags,
|
if (vlen > IOV_MAX) vlen = IOV_MAX;
|
||||||
|
socklen_t csize[vlen];
|
||||||
|
for (int i=0; i<vlen; i++) csize[i] = msgvec[i].msg_hdr.msg_controllen;
|
||||||
|
r = __syscall_cp(SYS_recvmmsg, fd, msgvec, vlen, flags,
|
||||||
timeout ? ((long[]){CLAMP(s), ns}) : 0);
|
timeout ? ((long[]){CLAMP(s), ns}) : 0);
|
||||||
|
for (int i=0; i<r; i++)
|
||||||
|
__convert_scm_timestamps(&msgvec[i].msg_hdr, csize[i]);
|
||||||
|
return __syscall_ret(r);
|
||||||
#else
|
#else
|
||||||
return syscall_cp(SYS_recvmmsg, fd, msgvec, vlen, flags, timeout);
|
return syscall_cp(SYS_recvmmsg, fd, msgvec, vlen, flags, timeout);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
|
|
||||||
static void convert_scm_timestamps(struct msghdr *msg, socklen_t csize)
|
hidden void __convert_scm_timestamps(struct msghdr *, socklen_t);
|
||||||
|
|
||||||
|
void __convert_scm_timestamps(struct msghdr *msg, socklen_t csize)
|
||||||
{
|
{
|
||||||
if (SCM_TIMESTAMP == SCM_TIMESTAMP_OLD) return;
|
if (SCM_TIMESTAMP == SCM_TIMESTAMP_OLD) return;
|
||||||
if (!msg->msg_control || !msg->msg_controllen) return;
|
if (!msg->msg_control || !msg->msg_controllen) return;
|
||||||
|
@ -58,7 +60,7 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
r = socketcall_cp(recvmsg, fd, msg, flags, 0, 0, 0);
|
r = socketcall_cp(recvmsg, fd, msg, flags, 0, 0, 0);
|
||||||
if (r >= 0) convert_scm_timestamps(msg, orig_controllen);
|
if (r >= 0) __convert_scm_timestamps(msg, orig_controllen);
|
||||||
#if LONG_MAX > INT_MAX
|
#if LONG_MAX > INT_MAX
|
||||||
if (orig) *orig = h;
|
if (orig) *orig = h;
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue