diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/sendmmsg.c')
-rw-r--r-- | sysdeps/unix/sysv/linux/sendmmsg.c | 72 |
1 files changed, 21 insertions, 51 deletions
diff --git a/sysdeps/unix/sysv/linux/sendmmsg.c b/sysdeps/unix/sysv/linux/sendmmsg.c index 9b193438ce..6e0d46be9e 100644 --- a/sysdeps/unix/sysv/linux/sendmmsg.c +++ b/sysdeps/unix/sysv/linux/sendmmsg.c @@ -16,10 +16,12 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ +#include <errno.h> #include <sys/socket.h> -#include <socketcall.h> + #include <sysdep-cancel.h> -#include <shlib-compat.h> +#include <sys/syscall.h> +#include <kernel-features.h> /* Do not use the sendmmsg syscall on socketcall architectures unless it was added at the same time as the socketcall support or can be @@ -30,53 +32,31 @@ # undef __NR_sendmmsg #endif -#if __WORDSIZE == 64 -static inline int -send_mmsghdr (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags) -{ - /* Emulate kernel interface for vlen size. */ - if (vlen > IOV_MAX) - vlen = IOV_MAX; - if (vlen == 0) - return 0; - /* POSIX specifies that both msghdr::msg_iovlen and msghdr::msg_controllen - to be int and socklen_t respectively, however Linux defines it as both - size_t. So for 64-bit it requires some adjustments by copying to - temporary header and zeroing the pad fields. - The problem is sendmmsg's msghdr may points to an already-filled control - buffer and modifying it is not part of sendmmsg contract (the data may - be in ro map). So interact over the msghdr calling the sendmsg that - adjust the header using a temporary buffer. */ - for (unsigned int i = 0; i < vlen; i++) - { - ssize_t ret = __sendmsg (fd, &vmessages[i].msg_hdr, flags); - if (ret < 0) - return -1; - vmessages[i].msg_len = ret; - } - return 1; -} -#endif - +#ifdef __NR_sendmmsg int __sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags) { -#if __WORDSIZE == 64 - return send_mmsghdr (fd, vmessages, vlen, flags); -#elif defined __NR_sendmmsg return SYSCALL_CANCEL (sendmmsg, fd, vmessages, vlen, flags); +} +libc_hidden_def (__sendmmsg) +weak_alias (__sendmmsg, sendmmsg) #elif defined __NR_socketcall +# include <socketcall.h> # ifdef __ASSUME_SENDMMSG_SOCKETCALL +int +__sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags) +{ return SOCKETCALL_CANCEL (sendmmsg, fd, vmessages, vlen, flags); +} # else - static int have_sendmmsg; +static int have_sendmmsg; + +int +__sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags) +{ if (__glibc_likely (have_sendmmsg >= 0)) { -# if __WORDSIZE == 64 - int ret = send_mmsghdr (fd, vmessages, vlen, flags); -# else int ret = SOCKETCALL_CANCEL (sendmmsg, fd, vmessages, vlen, flags); -# endif /* The kernel returns -EINVAL for unknown socket operations. We need to convert that error to an ENOSYS error. */ if (__builtin_expect (ret < 0, 0) @@ -104,20 +84,10 @@ __sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags) } __set_errno (ENOSYS); return -1; -# endif /* __ASSUME_SENDMMSG_SOCKETCALL */ -#else /* defined __NR_socketcall */ -# define STUB 1 - __set_errno (ENOSYS); - return -1; -#endif } -#ifdef STUB -stub_warning (sendmmsg) -#endif - +# endif /* __ASSUME_SENDMMSG_SOCKETCALL */ libc_hidden_def (__sendmmsg) -#if __WORDSIZE == 64 -versioned_symbol (libc, __sendmmsg, sendmmsg, GLIBC_2_24); -#else weak_alias (__sendmmsg, sendmmsg) +#else +# include <socket/sendmmsg.c> #endif |