s2n_tls/callbacks/client_hello.rs
1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Support for application-implemented ClientHello callbacks.
5
6use crate::{callbacks::*, config::Config, connection::Connection, error::Error};
7use core::task::Poll;
8use pin_project_lite::pin_project;
9use std::{future::Future, pin::Pin};
10
11/// A trait for the callback executed after parsing the ClientHello message.
12///
13/// Use in conjunction with
14/// [config::Builder::set_client_hello_callback](`crate::config::Builder::set_client_hello_callback()`).
15pub trait ClientHelloCallback: 'static + Send + Sync {
16 /// The application can return an `Ok(None)` to resolve the callback
17 /// synchronously or return an `Ok(Some(ConnectionFuture))` if it wants to
18 /// run some asynchronous task before resolving the callback.
19 ///
20 /// [`ConfigResolver`], which implements [`ConnectionFuture`] can be
21 /// returned if the application wants to set a new [`Config`] on the connection.
22 ///
23 /// If the server_name is used to configure the connection then the application
24 /// should call [`Connection::server_name_extension_used()`].
25 fn on_client_hello(
26 // this method takes an immutable reference to self to prevent the
27 // Config from being mutated by one connection and then used in another
28 // connection, leading to undefined behavior
29 &self,
30 connection: &mut Connection,
31 ) -> ConnectionFutureResult;
32}
33
34// For more information on projection:
35// https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning
36pin_project! {
37 /// An implementation of [`ConnectionFuture`] which resolves the provided
38 /// future and sets the config on the [`Connection`].
39 pub struct ConfigResolver<F: Future<Output = Result<Config, Error>>> {
40 #[pin]
41 fut: F,
42 }
43}
44
45impl<F: 'static + Send + Future<Output = Result<Config, Error>>> ConfigResolver<F> {
46 pub fn new(fut: F) -> Self {
47 ConfigResolver { fut }
48 }
49}
50
51impl<F: 'static + Send + Sync + Future<Output = Result<Config, Error>>> ConnectionFuture
52 for ConfigResolver<F>
53{
54 fn poll(
55 self: Pin<&mut Self>,
56 connection: &mut Connection,
57 ctx: &mut core::task::Context,
58 ) -> Poll<Result<(), Error>> {
59 let this = self.project();
60 let config = match this.fut.poll(ctx) {
61 Poll::Ready(config) => config?,
62 Poll::Pending => return Poll::Pending,
63 };
64
65 connection.set_config(config)?;
66
67 Poll::Ready(Ok(()))
68 }
69}