tokio-rs / tokio

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...
https://tokio.rs
MIT License
27.19k stars 2.5k forks source link

net: expose more socket options on `TcpSocket` #3082

Open hawkw opened 4 years ago

hawkw commented 4 years ago

Is your feature request related to a problem? Please describe. While updating Hyper to use Tokio 0.3 (hyperium/hyper#2317), it turned out that most of the socket options that Hyper needs to set are no longer available on TcpStream or on the new TcpSocket type. Instead, it was necessary to to open the socket using socket2 and use socket2 to set the socket options, resulting in some fairly unpleasant code for converting between socket2::Socket and TcpSocket, and then performing an asynchronous connect via TcpSocket. It would be nice if TcpSocket supported these socket options directly.

In particular, it's not great to have to manually convert a socket2 Socket to a Tokio TcpSocket via IntoRawFd/FromRawFd. It's relatively easy for users to mess this up in the following ways:

Also, it requires unsafe code in downstream crates that would be nice to abstract over.

It would be nice if all of these operations could be performed on TcpSocket without having to also use socket2. Or, at least, it would be nice if the conversion between socket2 and TcpSocket was less complex.

Describe the solution you'd like Ideally, TcpSocket would provide the ability to set at least the socket options required by Hyper:

My understanding is that adding these options would require an upstream addition in mio, which I'm happy to make.

Describe alternatives you've considered

Alternatively, we could:

hawkw commented 4 years ago

It's worth noting that Mio's TcpSocket already exposes some additional socket options that Tokio doesn't expose:

We may want to expose these as well

hawkw commented 4 years ago

Opened tokio-rs/mio#1384 to expose buffer size, and tokio-rs/mio#1385 to expose the keepalive interval. We may also want to add SO_NODELAY...

Darksonn commented 4 years ago

I think it makes total sense to add these methods to TcpSocket. :+1:

Freaky commented 4 years ago

I ran into a similar difficulty while updating tarssh to Tokio 0.3 - I was setting send/recv buffers on the TcpStream from an accept() call, but there seems no way to (sensibly) replicate this behaviour in 0.3?

biluohc commented 3 years ago

So how to set TCP keepalive for socket from accept()?

Darksonn commented 3 years ago

If Tokio does not expose a method for doing it, you can do it with the socket2 crate using something like SockRef.

thedodd commented 3 years ago

Having used these methods from tokio 0.2 — namely set_keepalive — it would be great to have these in tokio 1.0 as well. For now, I'm using SockRef as @Darksonn mentioned (thanks @Darksonn).

esavier commented 3 years ago

Is there any reasoning why available socket options are not exposed? This kind of scratches Tokio out from some application

silence-coding commented 3 years ago

is there a better way to set keepalive? The way I'm doing it right now is inelegant.

4028

esavier commented 3 years ago

yeah, i have no idea why setting options is not in the tokio api, but currently this is only option that i am aware of. Basically you have to create external socket structure and hopefully cast it to the tokio's version after setting the correct option.

wutianze commented 2 years ago

BIND_DEVICE, please!!!

howellzhu commented 2 years ago

Two years have passed, any update on this issue please? Noticed that @hawkw 's commit is closed: net: expose keepalive configuration on TcpSocket But it seems no indirect solution provided, I mean, do we have to use non-safe methods?

Darksonn commented 2 years ago

The socket2 crate can generally set any socket option safely. Other than that, please open a new issue if there is some specific option that you think Tokio should provide.

howellzhu commented 2 years ago

@Darksonn thanks , following safe code can work:

use socket2::{SockRef, TcpKeepalive};
...
        info!("connecting to {addr}");
        let tcp = TcpStream::connect(&addr).await?;
        info!("tcp connected to {addr}");
        let ka = TcpKeepalive::new().with_time(std::time::Duration::from_secs(30));
        let sf = SockRef::from(&tcp);
        sf.set_tcp_keepalive(&ka)?;
...
msdrigg commented 11 months ago

@howellzhu's code worked great for me!