linux: fix i386 sendmmsg/recvmmsg support
Android/i386 doesn't have separate sendmmsg/recvmmsg system calls,
they're multiplexed through the socketcall system call.
(More precisely, the system calls may be present but the standard
seccomp filter rejects them, whereas socketcall is whitelisted.)
This commit removes the flags and timeout arguments from libuv's
internal system call wrappers because they're always zero and it
makes EINVAL/ENOSYS detection after a failed socketcall() easier.
Fixes: https://github.com/libuv/libuv/issues/2923
PR-URL: https://github.com/libuv/libuv/pull/2925
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Ben Noordhuis authored 3 years ago
cjihrig committed 3 years ago
263 | 263 | } |
264 | 264 | |
265 | 265 | |
266 | int uv__sendmmsg(int fd, | |
267 | struct uv__mmsghdr* mmsg, | |
268 | unsigned int vlen, | |
269 | unsigned int flags) { | |
266 | int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { | |
270 | 267 | #if __FreeBSD__ >= 11 |
271 | return sendmmsg(fd, mmsg, vlen, flags); | |
268 | return sendmmsg(fd, mmsg, vlen, /* flags */ 0); | |
272 | 269 | #else |
273 | 270 | return errno = ENOSYS, -1; |
274 | 271 | #endif |
275 | 272 | } |
276 | 273 | |
277 | 274 | |
278 | int uv__recvmmsg(int fd, | |
279 | struct uv__mmsghdr* mmsg, | |
280 | unsigned int vlen, | |
281 | unsigned int flags, | |
282 | struct timespec* timeout) { | |
275 | int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { | |
283 | 276 | #if __FreeBSD__ >= 11 |
284 | return recvmmsg(fd, mmsg, vlen, flags, timeout); | |
277 | return recvmmsg(fd, mmsg, vlen, 0 /* flags */, NULL /* timeout */); | |
285 | 278 | #else |
286 | 279 | return errno = ENOSYS, -1; |
287 | 280 | #endif |
333 | 333 | unsigned int msg_len; |
334 | 334 | }; |
335 | 335 | |
336 | int uv__recvmmsg(int fd, | |
337 | struct uv__mmsghdr* mmsg, | |
338 | unsigned int vlen, | |
339 | unsigned int flags, | |
340 | struct timespec* timeout); | |
341 | int uv__sendmmsg(int fd, | |
342 | struct uv__mmsghdr* mmsg, | |
343 | unsigned int vlen, | |
344 | unsigned int flags); | |
336 | int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen); | |
337 | int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen); | |
345 | 338 | #else |
346 | 339 | #define HAVE_MMSG 0 |
347 | 340 | #endif |
36 | 36 | #ifndef __NR_recvmmsg |
37 | 37 | # if defined(__x86_64__) |
38 | 38 | # define __NR_recvmmsg 299 |
39 | # elif defined(__i386__) | |
40 | # define __NR_recvmmsg 337 | |
41 | 39 | # elif defined(__arm__) |
42 | 40 | # define __NR_recvmmsg (UV_SYSCALL_BASE + 365) |
43 | 41 | # endif |
46 | 44 | #ifndef __NR_sendmmsg |
47 | 45 | # if defined(__x86_64__) |
48 | 46 | # define __NR_sendmmsg 307 |
49 | # elif defined(__i386__) | |
50 | # define __NR_sendmmsg 345 | |
51 | 47 | # elif defined(__arm__) |
52 | 48 | # define __NR_sendmmsg (UV_SYSCALL_BASE + 374) |
53 | 49 | # endif |
145 | 141 | |
146 | 142 | struct uv__mmsghdr; |
147 | 143 | |
148 | int uv__sendmmsg(int fd, | |
149 | struct uv__mmsghdr* mmsg, | |
150 | unsigned int vlen, | |
151 | unsigned int flags) { | |
152 | #if defined(__NR_sendmmsg) | |
153 | return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags); | |
154 | #else | |
155 | return errno = ENOSYS, -1; | |
156 | #endif | |
157 | } | |
158 | ||
159 | ||
160 | int uv__recvmmsg(int fd, | |
161 | struct uv__mmsghdr* mmsg, | |
162 | unsigned int vlen, | |
163 | unsigned int flags, | |
164 | struct timespec* timeout) { | |
165 | #if defined(__NR_recvmmsg) | |
166 | return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout); | |
144 | int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { | |
145 | #if defined(__i386__) | |
146 | unsigned long args[4]; | |
147 | int rc; | |
148 | ||
149 | args[0] = (unsigned long) fd; | |
150 | args[1] = (unsigned long) mmsg; | |
151 | args[2] = (unsigned long) vlen; | |
152 | args[3] = /* flags */ 0; | |
153 | ||
154 | /* socketcall() raises EINVAL when SYS_SENDMMSG is not supported. */ | |
155 | rc = syscall(/* __NR_socketcall */ 102, 20 /* SYS_SENDMMSG */, args); | |
156 | if (rc == -1) | |
157 | if (errno == EINVAL) | |
158 | errno = ENOSYS; | |
159 | ||
160 | return rc; | |
161 | #elif defined(__NR_sendmmsg) | |
162 | return syscall(__NR_sendmmsg, fd, mmsg, vlen, /* flags */ 0); | |
163 | #else | |
164 | return errno = ENOSYS, -1; | |
165 | #endif | |
166 | } | |
167 | ||
168 | ||
169 | int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { | |
170 | #if defined(__i386__) | |
171 | unsigned long args[5]; | |
172 | int rc; | |
173 | ||
174 | args[0] = (unsigned long) fd; | |
175 | args[1] = (unsigned long) mmsg; | |
176 | args[2] = (unsigned long) vlen; | |
177 | args[3] = /* flags */ 0; | |
178 | args[4] = /* timeout */ 0; | |
179 | ||
180 | /* socketcall() raises EINVAL when SYS_RECVMMSG is not supported. */ | |
181 | rc = syscall(/* __NR_socketcall */ 102, 19 /* SYS_RECVMMSG */, args); | |
182 | if (rc == -1) | |
183 | if (errno == EINVAL) | |
184 | errno = ENOSYS; | |
185 | ||
186 | return rc; | |
187 | #elif defined(__NR_recvmmsg) | |
188 | return syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0); | |
167 | 189 | #else |
168 | 190 | return errno = ENOSYS, -1; |
169 | 191 | #endif |
72 | 72 | s = uv__socket(AF_INET, SOCK_DGRAM, 0); |
73 | 73 | if (s < 0) |
74 | 74 | return; |
75 | ret = uv__sendmmsg(s, NULL, 0, 0); | |
75 | ret = uv__sendmmsg(s, NULL, 0); | |
76 | 76 | if (ret == 0 || errno != ENOSYS) { |
77 | 77 | uv__sendmmsg_avail = 1; |
78 | 78 | uv__recvmmsg_avail = 1; |
79 | 79 | } else { |
80 | ret = uv__recvmmsg(s, NULL, 0, 0, NULL); | |
80 | ret = uv__recvmmsg(s, NULL, 0); | |
81 | 81 | if (ret == 0 || errno != ENOSYS) |
82 | 82 | uv__recvmmsg_avail = 1; |
83 | 83 | } |
212 | 212 | } |
213 | 213 | |
214 | 214 | do |
215 | nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL); | |
215 | nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks); | |
216 | 216 | while (nread == -1 && errno == EINTR); |
217 | 217 | |
218 | 218 | if (nread < 1) { |
355 | 355 | } |
356 | 356 | |
357 | 357 | do |
358 | npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts, 0); | |
358 | npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts); | |
359 | 359 | while (npkts == -1 && errno == EINTR); |
360 | 360 | |
361 | 361 | if (npkts < 1) { |