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}