-
Notifications
You must be signed in to change notification settings - Fork 371
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 basic support for sockets #3449
Comments
As discussed on Zulip, it would probably make sense to use
The hope is that mio would give us both of these in a platform-independent way, so that we can run on Windows hosts. (Note that this issue is only about Unix targets, using the typical POSIX socket API. Support for sockets on Windows targets is out-of-scope here. But if possible we should support running Unix targets on Windows hosts, as we already do with file system access.) |
There's also a dumb way to do this: just spawn a physical host thread whenever we want to do a blocking op and poll that thread every now and then to see if it finished. |
Just so you know that someone would use socket support when it gets put in.
|
Same here! I had an example using void ptrs resulting in an IO Safety Violation error. It would've been very helpful to use Miri to see how and why the safety violation occurred! test thread::tests::make_socket ... error: unsupported operation: can't call foreign function `socket` on OS `linux`
--> /home/barrett/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pal/unix/net.rs:89:34
|
89 | let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function `socket` on OS `linux`
|
= help: if this is a basic API commonly used on this target, please report an issue with Miri
= help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases
= note: BACKTRACE on thread `thread::tests::`:
= note: inside `std::sys::pal::unix::net::Socket::new_raw` at /home/barrett/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pal/unix/net.rs:89:34: 89:79
= note: inside `std::sys::pal::unix::net::Socket::new` at /home/barrett/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pal/unix/net.rs:68:9: 68:33
= note: inside `std::sys_common::net::UdpSocket::bind` at /home/barrett/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/net.rs:524:20: 524:52
= note: inside `<for<'a> fn(std::result::Result<&'a std::net::SocketAddr, std::io::Error>) -> std::result::Result<std::sys_common::net::UdpSocket, std::io::Error> {std::sys_common::net::UdpSocket::bind} as std::ops::FnMut<(std::result::Result<&std::net::SocketAddr, std::io::Error>,)>>::call_mut - shim(for<'a> fn(std::result::Result<&'a std::net::SocketAddr, std::io::Error>) -> std::result::Result<std::sys_common::net::UdpSocket, std::io::Error> {std::sys_common::net::UdpSocket::bind})` at /home/barrett/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:166:5: 166:75
= note: inside `std::net::each_addr::<&str, for<'a> fn(std::result::Result<&'a std::net::SocketAddr, std::io::Error>) -> std::result::Result<std::sys_common::net::UdpSocket, std::io::Error> {std::sys_common::net::UdpSocket::bind}, std::sys_common::net::UdpSocket>` at /home/barrett/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/net/mod.rs:81:15: 81:27
= note: inside `std::net::UdpSocket::bind::<&str>` at /home/barrett/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/net/udp.rs:121:9: 121:57
note: inside `thread::tests::make_socket`
--> src/thread.rs:350:31
|
350 | let some_socket = UdpSocket::bind("127.0.0.1:9999").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside closure
--> src/thread.rs:339:21
|
338 | #[test] // TODO: run through miri!
| ------- in this procedural macro expansion
339 | fn make_socket() {
| ^
= note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error; 27 warnings emitted
error: test failed, to rerun pass `--lib`
Caused by:
process didn't exit successfully: `/home/barrett/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner /home/barrett/Documents/projects/Rover/gps-rs/target/miri/x86_64-unknown-linux-gnu/debug/deps/soro_gps-9208bcd2dc9e9e26 make_socket` (exit status: 1)
note: test exited abnormally; to see the full output pass --nocapture to the harness.
barrett@farts ~/D/p/R/gps-rs (feat/thread) [1]> Testing normally yielded the following output:
...and as such, I can kinda understand why this hasn't been built yet. Implementing this feature by connecting to the system prevents doing safety checks on |
Thanks for sharing! We are well aware that this is a feature folks run into regularly, no need to add further user stories here. :) However, what would be useful is getting an idea of whether TCP or UDP should be the first one to tackle. I kind of assume TCP is more common so that is what I would default to... but it's also the bigger API surface.^^ |
My use case is basic Unix stream socket (Wayland), so not TCP. It does use epoll. |
Oh right, there's a third kind of socket... and it seems like there is a wrapper for that in I hope you don't need to attach FDs to messages as I don't think that is anywhere near the top of the roadmap. We'll start with very basic |
Definitely do need to. So you're saying it's going to be a while ;) Please don't prioritize my specific use case ahead of what you think are the more important and easier cases to tackle. |
Yeah I'm afraid that will be a while.^^ |
Miri can access files but not sockets currently.
The main issue with implementing blocking sockets is that they would provide the first source of blocking in Miri that is controlled by the outside world (except for time but we've got that handled pretty well). That will be quite non-trivial to implement as Miri needs to basically become or import an async runtime. We'll have a concept of threads being blocked on a socket. When all threads are blocked and Miri goes to sleep to wait for a timeout to pass, it needs to be able to wait on "either the timeout passes or all the sockets any thread is blocked on". When the socket unblocks we should wake up the thread, even if we never reach the "all threads are blocked" state. Both of these are exactly the core operations of an async runtime.
Somewhat surprisingly, I do not think that epoll makes this a lot more complicated. Even without epoll, we could have 5 threads waiting on a different socket each, so Miri basically needs epoll on the host even if Miri programs do not have epoll available. Having epoll just means that a single Miri thread can wait on more than one socket, but since Miri anyway has to support many threads that doesn't add significant new complications.
Non-blocking sockets would be a lot simpler, but probably also a lot less interesting.
The text was updated successfully, but these errors were encountered: