fn scheduled_renegotiate_with_async_callback()

in bindings/rust/extended/s2n-tls/src/renegotiate.rs [988:1062]


    fn scheduled_renegotiate_with_async_callback() -> Result<(), Box<dyn Error>> {
        // To test how renegotiate handles blocking on async callbacks,
        // we need an async callback that triggers on the client.
        // Currently our only option is the async pkey callback.
        struct TestAsyncCallback {
            count: usize,
            op: Option<PrivateKeyOperation>,
        }
        impl PrivateKeyCallback for TestAsyncCallback {
            fn handle_operation(
                &self,
                _: &mut Connection,
                operation: PrivateKeyOperation,
            ) -> ConnectionFutureResult {
                Ok(Some(Box::pin(TestAsyncCallback {
                    count: self.count,
                    op: Some(operation),
                })))
            }
        }
        impl ConnectionFuture for TestAsyncCallback {
            fn poll(
                self: Pin<&mut Self>,
                conn: &mut Connection,
                ctx: &mut core::task::Context,
            ) -> Poll<Result<(), crate::error::Error>> {
                ctx.waker().wake_by_ref();
                let this = self.get_mut();
                if this.count > 1 {
                    // Repeatedly block the handshake in order to verify
                    // that renegotiate can handle Pending callbacks.
                    this.count -= 1;
                    Pending
                } else {
                    // Perform the pkey operation with the selected cert / key pair.
                    let op = this.op.take().unwrap();
                    let opt_ptr = op.as_ptr();
                    let chain_ptr = conn.selected_cert().unwrap().as_ptr();
                    unsafe {
                        // SAFETY, mut cast: get_private_key does not modify the
                        // chain, and it is invalid to modify key through `key_ptr`
                        let key_ptr = s2n_cert_chain_and_key_get_private_key(chain_ptr as *mut _)
                            .into_result()?
                            .as_ptr();
                        s2n_async_pkey_op_perform(opt_ptr, key_ptr).into_result()?;
                        s2n_async_pkey_op_apply(opt_ptr, conn.as_ptr()).into_result()?;
                    }
                    Ready(Ok(()))
                }
            }
        }

        let count_per_handshake = 10;
        let async_callback = TestAsyncCallback {
            count: count_per_handshake,
            op: None,
        };

        let mut builder = config::Builder::new();
        builder.set_renegotiate_callback(RenegotiateResponse::Schedule)?;
        builder.set_private_key_callback(async_callback)?;
        let mut pair = RenegotiateTestPair::from(builder)?;

        let (waker, wake_count) = new_count_waker();
        pair.client.set_waker(Some(&waker))?;

        pair.handshake().expect("Initial handshake");
        assert_eq!(wake_count, count_per_handshake);
        pair.send_renegotiate_request()
            .expect("Server sends request");
        pair.assert_renegotiate()?;

        assert_eq!(wake_count, count_per_handshake * 2);
        Ok(())
    }