Skip to content

finish sometimes hangs forever #285

Description

@joshtriplett

I put together the following simple test of wtransport, as an experiment:

use clap::Parser;
use tokio::io::AsyncReadExt;

#[derive(Parser)]
#[command(name = "wtransport-test")]
enum WtransportTest {
    Client(Client),
    Server,
}

#[derive(Parser)]
struct Client {
    /// Server certificate hash
    hash: wtransport::tls::Sha256Digest,
}

#[tokio::main]
async fn main() -> eyre::Result<()> {
    match WtransportTest::parse() {
        WtransportTest::Client(args) => client(args).await,
        WtransportTest::Server => server().await,
    }
}

async fn client(args: Client) -> eyre::Result<()> {
    let config = wtransport::ClientConfig::builder()
        .with_bind_default()
        .with_server_certificate_hashes([args.hash])
        .build();
    let connection = wtransport::Endpoint::client(config)?
        .connect("https://localhost:4433/demo-path")
        .await?;
    println!("Established WebTransport connection");
    let mut recv_stream = connection.accept_uni().await?;
    println!("Accepted unidirectional stream");
    let mut s = String::new();
    recv_stream.read_to_string(&mut s).await?;
    println!("Read string: {s}");
    Ok(())
}

async fn server() -> eyre::Result<()> {
    let identity = wtransport::Identity::self_signed(["localhost"])?;
    let hash = identity.certificate_chain().as_slice()[0].hash();
    println!("Created server certificate with hash {hash}");
    let config = wtransport::ServerConfig::builder()
        .with_bind_default(4433)
        .with_identity(identity)
        .build();
    let server = wtransport::Endpoint::server(config)?;
    println!("Established listening server");
    let incoming_session = server.accept().await;
    println!(
        "Got incoming session from {}",
        incoming_session.remote_address()
    );
    let incoming_request = incoming_session.await?;
    println!(
        "Incoming request has authority {}, path {}",
        incoming_request.authority(),
        incoming_request.path()
    );
    let connection = incoming_request.accept().await?;
    println!("Accepted connection");
    let mut send_stream = connection.open_uni().await?.await?;
    println!("Established unidirectional stream");
    send_stream.write_all(b"Hello world!").await?;
    println!("Sent data");
    send_stream.finish().await?;
    println!("Finished");
    Ok(())
}

This uses the following [dependencies] in Cargo.toml:

clap = { version = "4.5.49", features = ["deprecated", "derive"] }
eyre = "0.6.12"
tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }
wtransport = { version = "0.6.1", features = ["aws-lc-rs", "self-signed"], default-features = false }

To test this, run it with server which will print a hash, then run it with client that-hash.

Sometimes, both the server and client will complete as expected. However, sometimes, the server will do this:

Created server certificate with hash 83:4e:3c:d4:4d:a3:5d:19:e8:54:f5:72:ee:7d:a0:25:e7:c3:13:a1:9d:6a:0b:75:54:f9:bc:04:d3:3b:cc:17
Established listening server
Got incoming session from [::1]:50257
Incoming request has authority localhost:4433, path /demo-path
Accepted connection
Established unidirectional stream
Sent data

And then hang, never printing "Finished".

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions