Skip to content

Conversation

maddeleine
Copy link
Contributor

@maddeleine maddeleine commented Jul 1, 2025

Release Summary:

Adds unstable feature to move s2n-tls operations out of the main thread.

Resolved issues:

resolves #2598

Description of changes:

Adds a new TLS provider that opens a new thread to complete TLS operations. This is essentially what was implemented by Mark in this diff except cleaned up a little.

Call-outs:

Testing:

Adds integ test

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@maddeleine maddeleine changed the title Initial commit feat(s2n-quic-core) TLS offloading Jul 1, 2025
@maddeleine maddeleine marked this pull request as ready for review July 7, 2025 17:45
Comment on lines +50 to +51
futures-channel = { version = "0.3", default-features = false, optional=true, features = ["std", "alloc"]}
futures = { version = "0.3", default-features = false, optional=true, features = ["std", "alloc"]}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like there was an intention to have the dependencies be alphabetically ordered (through the last two in the list broke that). Could you move these and future-test and once_cell?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default = ["alloc", "std"]
alloc = ["atomic-waker", "bytes", "crossbeam-utils", "s2n-codec/alloc"]
std = ["alloc", "once_cell"]
std = ["alloc", "once_cell", "futures-channel", "futures"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wondering if it would make more sense to have futures-channel and futures be part of the unstable-offload-tls feature in this crate. Since you don't really need those dependencies if you are only interested in using std and not the TLS offloading feature

#[cfg(feature = "alloc")]
pub mod slow_tls;

#[cfg(feature = "std")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[cfg(feature = "std")]
#[cfg(feature = "unstable-offload-tls")]

);
pub struct OffloadEndpoint<E: tls::Endpoint> {
new_session: UnboundedSender<SessionProducer<E>>,
_thread: thread::JoinHandle<()>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed?


let mut next_sessions = vec![];

// Make progress on all stored sessions, prioritizing existing sessions over incoming ones
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you clarify a bit on what you mean by "prioritizing existing sessions over incoming ones" and how that relates to sessions and next_sessions?

Comment on lines +313 to +314
// FIXME: this probably means that the parent thread is no longer interested
// in this connection and we should instead tear it down.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be fixed now or is there more investigation needed? If it can't be fixed now, would be good to link an issue

&mut self,
_session: &impl tls::TlsSession,
) -> Result<(), crate::transport::Error> {
// FIXME: needs some form of async callback, or maybe never gets called during remote phase?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for this

}) {
resp
} else {
// FIXME: either async-ify, remove, or figure out what the Pending value should be.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is needed to know the fix?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there shouldn't be any async communication in these methods. it should just simplify check if there is capacity in the queue and if the space is available.

# The feature enables the close formatter provider
unstable-provider-connection-close-formatter = []
# This feature enables the use of the offloaded TLS feature
unstable-offload-tls = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would end up being

Suggested change
unstable-offload-tls = []
unstable-offload-tls = ["s2n-quic-core/unstable-offload-tls"]


#[test]
#[cfg(feature = "unstable-offload-tls")]
fn offload_tls() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks pretty straightforward to use, but might still be worth an example in the examples directory. And that can contain some documentation on the feature in a readme

pub fn new(inner: E) -> Self {
let (tx, mut rx) = futures_channel::mpsc::unbounded::<SessionProducer<E>>();

let handle = thread::spawn(move || {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to spawn a new thread per session. This will essentially be an unbounded queue of spawning threads.

.unwrap();
let server_endpoint = Offload(server_endpoint);
let client_endpoint = Offload(client_endpoint);
test(model, |handle| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised this is working with bach. I won't like interacting with an actual async operation (interacting with a thread). My guess is it's a race condition of things actually working or not, at the very least non-deterministic.

Comment on lines +50 to +51
futures-channel = { version = "0.3", default-features = false, optional=true, features = ["std", "alloc"]}
futures = { version = "0.3", default-features = false, optional=true, features = ["std", "alloc"]}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fn receive_application(&mut self, max_len: Option<usize>) -> Option<Bytes>;

fn can_send_initial(&self) -> bool;
fn can_send_initial(&mut self) -> bool;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is technically a breaking change if applications are implementing their own TLS providers.

remote_thread: Waker,
) -> Self {
// Channel to pass requests from remote TLS thread to main thread
let (tx, rx) = futures_channel::mpsc::unbounded::<Request<S>>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we really want to avoid any kind of unbounded queues

}) {
resp
} else {
// FIXME: either async-ify, remove, or figure out what the Pending value should be.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there shouldn't be any async communication in these methods. it should just simplify check if there is capacity in the queue and if the space is available.

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

Successfully merging this pull request may close these issues.

Offload the TLS crypto operations to separate threads
3 participants