Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement fallback for sendmmsg and recvmmsg #1504

Merged
merged 1 commit into from
Mar 8, 2023

Conversation

link2xt
Copy link
Contributor

@link2xt link2xt commented Mar 3, 2023

Some Android phones use older 2.x kernels
and do not support sendmmsg
which is available only since Linux 3.0.

Similarly, recvmmsg is only available
since Linux 2.6.34.

@link2xt
Copy link
Contributor Author

link2xt commented Mar 3, 2023

@djc
Copy link
Member

djc commented Mar 3, 2023

I changed the repo setting to only flag contributors from new GitHub members.

@@ -143,7 +143,7 @@ fn init(io: SockRef<'_>) -> io::Result<()> {
Ok(())
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a pretty heavy hammer, which impairs performance for all Android builds on account of what's presumably a pretty small minority of very old phones.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option would be to use something like tokio-rs/mio#1590: using syscall directly, so it can fail with ENOSYS and then switching to fallback.

But I am not sure it's worth the trouble, Android phones are usually clients handling a few connections and not sending much, so they do not benefit from such optimizations of the sending code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we also have a similar recvmmsg problem, it is also not available with API 16.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer the dynamic fallback. It's a common enough Linux pattern, and lets us avoid baking in assumptions about use cases. I wouldn't be surprised if we ended up needing similar tricks on other platforms sooner or later either.

Even for typical mobile applications where CPU might not be a bottleneck, power use is still important, for example.

@link2xt link2xt marked this pull request as draft March 3, 2023 22:43
@link2xt link2xt force-pushed the android-sendmmsg branch from 67d29e3 to 707bec4 Compare March 3, 2023 22:46
@link2xt link2xt changed the title Do not use sendmmsg on Android Do not use sendmmsg and recvmsg on Android Mar 3, 2023
@link2xt link2xt marked this pull request as ready for review March 3, 2023 23:36
@link2xt link2xt force-pushed the android-sendmmsg branch 4 times, most recently from 5848279 to 4f80bed Compare March 4, 2023 20:12
@link2xt link2xt changed the title Do not use sendmmsg and recvmsg on Android Implement fallback for sendmmsg and recvmmsg Mar 4, 2023
@link2xt link2xt requested review from Ralith and djc and removed request for Ralith and djc March 4, 2023 20:15
@link2xt
Copy link
Contributor Author

link2xt commented Mar 4, 2023

This is ready for review now.

@link2xt link2xt force-pushed the android-sendmmsg branch from 4f80bed to 127c016 Compare March 4, 2023 20:16
Copy link
Collaborator

@Ralith Ralith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very tidy, thanks!

quinn-udp/src/unix.rs Outdated Show resolved Hide resolved
@link2xt link2xt force-pushed the android-sendmmsg branch from 127c016 to cdfe0fa Compare March 4, 2023 23:31
Ralith
Ralith previously approved these changes Mar 4, 2023
Copy link
Collaborator

@Ralith Ralith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

quinn-udp/src/unix.rs Outdated Show resolved Hide resolved
quinn-udp/src/unix.rs Outdated Show resolved Hide resolved
quinn-udp/src/unix.rs Outdated Show resolved Hide resolved
quinn-udp/src/unix.rs Outdated Show resolved Hide resolved
match e.raw_os_error() {
Some(libc::ENOSYS) => {
// Fallback to `recvmsg`.
recvmmsg_fallback(sockfd, msgvec, vlen)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't know how much you care, but presumably we could store state on whether mmsg support is available somewhere, maybe in the UdpState, so that we don't have to fallback everytime? (I suppose that would come at the cost of one extra branch even for environments where mmsg support is available, but that should be a pretty cheap branch with prediction.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably ok to have less performance and 2 syscalls per send/receive on systems which do not support sendmmsg/recvmmsg. We are going to only use it for backup transfer for now and it only needs to work good enough for transferring a file once reliably. Adding statefullness makes things more complex.

Some Android phones use older 2.x kernels
and do not support `sendmmsg`
which is available only since Linux 3.0.

Similarly, `recvmmsg` is only available
since Linux 2.6.34.
@djc djc force-pushed the android-sendmmsg branch from 1426f78 to 842ae4d Compare March 8, 2023 11:01
@djc djc merged commit e6f1844 into quinn-rs:main Mar 8, 2023
@djc djc mentioned this pull request May 8, 2023
3 tasks
mxinden added a commit to mxinden/quinn that referenced this pull request Aug 10, 2024
> On x86-32, socketcall() was historically the only entry point for
> the sockets API.  However, starting in Linux 4.3, direct system
> calls are provided on x86-32 for the sockets API.

https://man7.org/linux/man-pages/man2/socketcall.2.html

Androids x86 even goes as far as automatically dispatching advanced socket
calls (e.g. `socket` or `recvmmsg`) through `socketcall` in its Bionic libc:

> For example, socket() syscall on i386 actually becomes:
> socketcall(__NR_socket, 1, *(rest of args on stack)).

https://android.googlesource.com/platform/bionic/+/refs/tags/android-vts-14.0_r5/libc/SYSCALLS.TXT#19

In addition Android enables seccomp filtering since Android 8:

https://android-developers.googleblog.com/2017/07/seccomp-filter-in-android-o.html

Currently `quinn-udp` calls `recvmmsg` directly on Android x86:

``` rust
let ret = libc::syscall(libc::SYS_recvmmsg, sockfd, msgvec, vlen, flags, timeout) as libc::c_int;
```

https://github.com/quinn-rs/quinn/blob/c0b1e281e3167d4f4c8496082cb1117c4a270ad8/quinn-udp/src/unix.rs#L447-L448

A direct `recvmmsg` through `libc::syscall(libc::SYS_recvmmsg` does not trigger
the automatic Android x86 Bionic libc dispatch logic through `socketcall`, but
instead calls the unimplemented `recvmmsg` syscall. Instead of triggering a
`libc::ENOSYS`, seccomp disallows the call, thus leading to a panic of the
application.

This commit changes `quinn-udp` to use `libc::recvmmsg` on Android x86, thus
leveraging Bionic's automatic dispatch of `recvmmsg` through `socketcall`.

Note that this commit only uses `libc::recvmmsg` on Android x86, not any other
Android or Linux variant. Thus quinn-udp would still support missing
`libc::recvmmsg` on those systems. See
quinn-rs#1504.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants