1 /* Copyright (C) 2010-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <sys/socket.h>
19 #include <sysdep.h>
20 #include <socketcall.h>
21 
22 static int
recvmmsg_syscall(int fd,struct mmsghdr * vmessages,unsigned int vlen,int flags,struct __timespec64 * timeout)23 recvmmsg_syscall (int fd, struct mmsghdr *vmessages, unsigned int vlen,
24 		  int flags, struct __timespec64 *timeout)
25 {
26 #ifndef __NR_recvmmsg_time64
27 # define __NR_recvmmsg_time64 __NR_recvmmsg
28 #endif
29   int r = SYSCALL_CANCEL (recvmmsg_time64, fd, vmessages, vlen, flags,
30 			  timeout);
31 #ifndef __ASSUME_TIME64_SYSCALLS
32   if (r >= 0 || errno != ENOSYS)
33     return r;
34 
35   struct timespec ts32, *pts32 = NULL;
36   if (timeout != NULL)
37     {
38       if (! in_time_t_range (timeout->tv_sec))
39 	{
40 	  __set_errno (EINVAL);
41 	  return -1;
42 	}
43       ts32 = valid_timespec64_to_timespec (*timeout);
44       pts32 = &ts32;
45     }
46 
47 # ifdef __ASSUME_RECVMMSG_SYSCALL
48   r = SYSCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags, pts32);
49 # else
50   r = SOCKETCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags, pts32);
51 # endif
52   if (r >= 0)
53     {
54       if (timeout != NULL)
55         *timeout = valid_timespec_to_timespec64 (ts32);
56     }
57 #endif
58   return r;
59 }
60 
61 int
__recvmmsg64(int fd,struct mmsghdr * vmessages,unsigned int vlen,int flags,struct __timespec64 * timeout)62 __recvmmsg64 (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags,
63 	      struct __timespec64 *timeout)
64 {
65 #if __TIMESIZE != 64
66   socklen_t csize[IOV_MAX];
67   if (vlen > IOV_MAX)
68     vlen = IOV_MAX;
69   for (int i = 0; i < vlen; i++)
70     csize[i] = vmessages[i].msg_hdr.msg_controllen;
71 #endif
72 
73   int r = recvmmsg_syscall (fd, vmessages, vlen, flags, timeout);
74 #if __TIMESIZE != 64
75   if (r > 0)
76     {
77       for (int i=0; i < r; i++)
78         __convert_scm_timestamps (&vmessages[i].msg_hdr, csize[i]);
79     }
80 #endif
81   return r;
82 }
83 #if __TIMESIZE != 64
libc_hidden_def(__recvmmsg64)84 libc_hidden_def (__recvmmsg64)
85 
86 int
87 __recvmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags,
88 	    struct timespec *timeout)
89 {
90   struct __timespec64 ts64, *pts64 = NULL;
91   if (timeout != NULL)
92     {
93       ts64 = valid_timespec_to_timespec64 (*timeout);
94       pts64 = &ts64;
95     }
96   int r = recvmmsg_syscall (fd, vmessages, vlen, flags, pts64);
97   if (r >= 0 && timeout != NULL)
98     /* The remanining timeout will be always less the input TIMEOUT.  */
99     *timeout = valid_timespec64_to_timespec (ts64);
100   return r;
101 }
102 #endif
103 weak_alias (__recvmmsg, recvmmsg)
104