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

Initial implementation of Wasi-tls (Transport Layer Security) #10249

Merged
merged 18 commits into from
Mar 7, 2025
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update signature of close-notify
badeend authored and jsturtevant committed Mar 7, 2025
commit 470034dd012a6da33a5fbaef2d0aaf443cea3b52
2 changes: 1 addition & 1 deletion crates/test-programs/src/bin/tls_sample_application.rs
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ fn test_tls_sample_application() {

tls_output.blocking_write_util(request.as_bytes()).unwrap();
client_connection
.blocking_close_notify(&tls_output)
.blocking_close_output(&tls_output)
.unwrap();
socket.shutdown(ShutdownType::Send).unwrap();
let response = tls_input.blocking_read_to_end().unwrap();
13 changes: 9 additions & 4 deletions crates/test-programs/src/tls.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::wasi::clocks::monotonic_clock;
use crate::wasi::io::streams::StreamError;
use crate::wasi::tls::types::{ClientConnection, ClientHandshake, InputStream, OutputStream};

const TIMEOUT_NS: u64 = 1_000_000_000;
@@ -23,17 +24,21 @@ impl ClientHandshake {
}

impl ClientConnection {
pub fn blocking_close_notify(
pub fn blocking_close_output(
&self,
output: &OutputStream,
) -> Result<(), crate::wasi::io::error::Error> {
let timeout = monotonic_clock::subscribe_duration(TIMEOUT_NS);
let pollable = output.subscribe();

self.close_output();

loop {
match self.close_notify() {
None => pollable.block_until(&timeout).expect("timed out"),
Some(result) => return result,
match output.check_write() {
Ok(0) => pollable.block_until(&timeout).expect("timed out"),
Ok(_) => unreachable!("After calling close_output, the output stream should never accept new writes again."),
Err(StreamError::Closed) => return Ok(()),
Err(StreamError::LastOperationFailed(e)) => return Err(e),
}
}
}
36 changes: 7 additions & 29 deletions crates/wasi-tls/src/lib.rs
Original file line number Diff line number Diff line change
@@ -90,7 +90,6 @@ use wasmtime_wasi::OutputStream;
use wasmtime_wasi::{
async_trait,
bindings::io::{
error::Error as HostError,
poll::Pollable as HostPollable,
streams::{InputStream as BoxInputStream, OutputStream as BoxOutputStream},
},
@@ -297,17 +296,8 @@ pub struct ClientConnection {
}

impl<'a> generated::types::HostClientConnection for WasiTlsCtx<'a> {
fn close_notify(
&mut self,
this: Resource<ClientConnection>,
) -> wasmtime::Result<Option<Result<(), wasmtime::component::Resource<HostError>>>> {
let result = self.table.get_mut(&this)?.writer.close_notify();

Ok(match result {
None => None,
Some(Ok(())) => Some(Ok(())),
Some(Err(e)) => Some(Err(self.table.push(anyhow::Error::new(e))?)),
})
fn close_output(&mut self, this: Resource<ClientConnection>) -> wasmtime::Result<()> {
self.table.get_mut(&this)?.writer.close()
}

fn drop(&mut self, this: Resource<ClientConnection>) -> wasmtime::Result<()> {
@@ -524,14 +514,13 @@ impl TlsWriter {
}
}

fn close_notify(&mut self) -> Option<Result<(), io::Error>> {
fn close(&mut self) {
match std::mem::replace(&mut self.state, WriteState::Closed) {
// No write in progress, immediately shut down:
WriteState::Ready(mut stream) => {
self.state = WriteState::Closing(wasmtime_wasi::runtime::spawn(async move {
stream.shutdown().await
}));
None
}

// Schedule the shutdown after the current write has finished:
@@ -540,15 +529,12 @@ impl TlsWriter {
let mut stream = write.await?;
stream.shutdown().await
}));
None
}

WriteState::Closing(t) => {
self.state = WriteState::Closing(t);
None
}
WriteState::Closed => Some(Ok(())),
WriteState::Error(e) => Some(Err(e.into())),
WriteState::Closed | WriteState::Error(_) => {}
}
}

@@ -587,17 +573,9 @@ impl AsyncTlsWriteStream {
AsyncTlsWriteStream(Arc::new(Mutex::new(writer)))
}

fn close_notify(&mut self) -> Option<Result<(), StreamError>> {
let mut writer = match try_lock_for_stream(&self.0) {
Ok(writer) => writer,
Err(err) => return Some(Err(err)),
};

match writer.close_notify() {
None => None,
Some(Ok(())) => Some(Ok(())),
Some(Err(e)) => Some(Err(StreamError::LastOperationFailed(e.into()))),
}
fn close(&mut self) -> wasmtime::Result<()> {
try_lock_for_stream(&self.0)?.close();
Ok(())
}
}

4 changes: 1 addition & 3 deletions crates/wasi-tls/wit/world.wit
Original file line number Diff line number Diff line change
@@ -8,8 +8,6 @@ world imports {

@unstable(feature = tls)
interface types {
@unstable(feature = tls)
use wasi:io/error@0.2.3.{error as io-error};
@unstable(feature = tls)
use wasi:io/streams@0.2.3.{input-stream, output-stream};
@unstable(feature = tls)
@@ -27,7 +25,7 @@ interface types {
@unstable(feature = tls)
resource client-connection {
@unstable(feature = tls)
close-notify: func() -> option<result<_, io-error>>;
close-output: func();
}

@unstable(feature = tls)