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

Issue with native-tls handshake #450

Open
mirandole opened this issue Nov 7, 2024 · 2 comments
Open

Issue with native-tls handshake #450

mirandole opened this issue Nov 7, 2024 · 2 comments

Comments

@mirandole
Copy link

mirandole commented Nov 7, 2024

Hello,

I got an issue using tungstenite with native-tls feature. Sometimes when my project try to connect to a websocket with tungteniste using native-tls, the connection with client_tls panic with this error : "Bug: TLS handshake not blocked".
It's annoying because I don't know how to catch that kind of panic in my connection retry mechanism.

So my question is why does this code needs to panic when TlsHandshakeError::WouldBlock ?
It would be much pleasant if the code will return an error instead of panic. So I can retry to connect with client_tls without getting my project exit with panic.

To try to find a way to avoid my rust program to panic, I now use rustls instead of native-tls. But I think it would be better to return an error instead of panic.

match mode {
                Mode::Plain => Ok(MaybeTlsStream::Plain(socket)),
                Mode::Tls => {
                    let try_connector = tls_connector.map_or_else(TlsConnector::new, Ok);
                    let connector = try_connector.map_err(TlsError::Native)?;
                    let connected = connector.connect(domain, socket);
                    match connected {
                        Err(e) => match e {
                            TlsHandshakeError::Failure(f) => Err(Error::Tls(f.into())),
                            TlsHandshakeError::WouldBlock(_) => {
                                panic!("Bug: TLS handshake not blocked")
                            }
                        },
                        Ok(s) => Ok(MaybeTlsStream::NativeTls(s)),
                    }
                }
            }

https://github.com/snapview/tungstenite-rs/blob/master/src/tls.rs

@daniel-abramov
Copy link
Member

Tungstenite must not panic unless there is a bug in a crate. As the panic says, this error indicates a bug in a library and must not happen. I don't remember why this exact panic is there, i.e., why this error is considered a bug, as this commit has been there for more than seven years, so I'll mention @agalakhov here, he certainly knows this part better.

However, I must also say that we've never encountered this panic, and I don't remember it ever being reported. Is it reproducible?

@mirandole
Copy link
Author

mirandole commented Nov 7, 2024

Yes, upon reflection, I was able to reproduce it some minutes ago. It happens when my internet connection drop while executing client_tls method using tcp_stream.set_read_timeout and tcp_stream.set_write_timeout. If I disconnect my internet connection during the sleep time just before client_tls(). The panic happens because of tcp_stream timeout.

Removing tcp_stream.set_read_timeout and tcp_stream.set_write_timeout resolved my issue but client_tls timeout happens without any panic after 5min which is quite long for me but ok to manage. It would be nice to be able to set a custom timeout in client_tls() or to remove this annoying panic! to be able to benefit of the tcpstream timeout feature.

use std::{net::{TcpStream, ToSocketAddrs}, time::Duration};
use tungstenite::{client::IntoClientRequest, connect, http::{self, request, Uri}, ClientRequestBuilder};
use tungstenite::client_tls;

fn main() {
    let timeout = Duration::from_secs(30);
    let hostname_port = "stream.binance.com:443";
    let socket_addr = hostname_port.to_socket_addrs().unwrap().next().unwrap();
    let wss_addr = "wss://stream.binance.com/ws/btcusdt@ticker";

    match TcpStream::connect_timeout(&socket_addr, timeout) {
        Ok(tcp_stream) => {
            println!("tcpstream connected");
            tcp_stream.set_read_timeout(Some(timeout)).expect("Can't set read timeout");
            tcp_stream.set_write_timeout(Some(timeout)).expect("Can't set write timeout");

            // DISCONNECT INTERNET CONNECTION DURING SLEEP TIME
            println!("10s sleep time to disconnect internet and reproduce panic");
            std::thread::sleep(std::time::Duration::from_secs(10));

            let uri: Uri = wss_addr.parse().unwrap();
            let request = ClientRequestBuilder::new(uri).into_client_request().unwrap();

            println!("begin client_tls connection");
            match client_tls(request, tcp_stream) {
                Ok(mut answer) => {
                    println!("client_tls connected");
                    match answer.0.get_mut() {
                        tungstenite::stream::MaybeTlsStream::Plain(stream) => {
                            println!("tungstenite::stream::MaybeTlsStream::Plain");
                            let _ = stream.set_nonblocking(true).unwrap();
                            println!("nonblocking set");
                        },
                        tungstenite::stream::MaybeTlsStream::NativeTls(stream) => {
                            println!("tungstenite::stream::MaybeTlsStream::NativeTls");
                            let _ = stream.get_mut().set_nonblocking(true).unwrap();
                            println!("nonblocking set");
                        },
                        _ => {
                            println!("unimplemented");
                            unimplemented!();
                        },
                    };

                },
                Err(e) => {
                    println!("{}", format!("Error during handshake {}", e));
                },
            }
        },
        Err(e) => {
            println!("{}", format!("error connecting to : {}\nconnection error: {}", &socket_addr, e));
        },
    }
}

PS: When I use rustls instead of native-tls, I got the same error message without panic.

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

No branches or pull requests

2 participants