rust: bssl-tls: Drive handshake to completion

For sync connectors and acceptors, we should drive handshake to
completion to match those connectors and acceptors from other crates as
convention.

Signed-off-by: Xiangfei Ding <xfding@google.com>
Change-Id: Ibf9d16e53f4ba463c3d900f24d5aeec76a6a6964
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/101414
Reviewed-by: David Benjamin <davidben@google.com>
Reviewed-by: Rudolf Polzer <rpolzer@google.com>
Reviewed-by: Adam Langley <agl@google.com>
Presubmit-BoringSSL-Verified: boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/rust/bssl-tls/src/sync_io.rs b/rust/bssl-tls/src/sync_io.rs
index f6aeac6..9a654c8 100644
--- a/rust/bssl-tls/src/sync_io.rs
+++ b/rust/bssl-tls/src/sync_io.rs
@@ -19,7 +19,11 @@
         TlsConnection, //
     },
     context::TlsContext,
-    io::sync_io::{NoAsync, StdIoWithReactor}, //
+    errors::Error,
+    io::sync_io::{
+        NoAsync,
+        StdIoWithReactor, //
+    }, //
 };
 
 use std::{
@@ -41,22 +45,27 @@
         Self { ctx }
     }
 
-    /// Connect to the given domain using the provided stream.
-    pub fn connect<S>(
-        &self,
-        domain: &str,
-        stream: S,
-    ) -> Result<TlsStream<Client, S>, crate::errors::Error>
+    /// Connect to the given domain using the provided stream in one shot.
+    ///
+    /// This function will drive the handshake until completion.
+    ///
+    /// This function will **block** on pending I/Os.
+    /// For `async` I/O support, use [`TlsConnection::async_handshake`].
+    ///
+    /// If a non-I/O suspension occurs, including asynchronous certificate verification or a private
+    /// key operation, this function returns an error.
+    pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<Client, S>, Error>
     where
         S: Read + Write + Send + 'static,
     {
         let mut conn = self.ctx.new_client_connection().build();
-        {
-            conn.in_handshake()
-                .expect("connection is freshly constructed and it cannot already be established")
-                .set_host(domain)?;
-            conn.set_io(StdIoWithReactor::new(stream, NoAsync))?
-                .do_handshake()?;
+        #[allow(clippy::expect_used)]
+        conn.in_handshake()
+            .expect("connection is freshly constructed and it cannot already be established")
+            .set_host(domain)?;
+        conn.set_io(StdIoWithReactor::new(stream, NoAsync))?;
+        if let Some(reason) = conn.do_handshake()? {
+            return Err(Error::Unknown(Box::new(reason)));
         }
 
         Ok(TlsStream {
@@ -77,14 +86,24 @@
         Self { ctx }
     }
 
-    /// Accept a new connection using the provided stream.
-    pub fn accept<S>(&self, stream: S) -> Result<TlsStream<Server, S>, crate::errors::Error>
+    /// Accept a new connection using the provided stream in one shot.
+    ///
+    /// This function will drive the handshake until completion.
+    ///
+    /// This function will **block** on pending I/Os.
+    /// For `async` I/O support, use [`TlsConnection::async_handshake`].
+    ///
+    /// If a non-I/O suspension occurs, including asynchronous certificate verification or a private
+    /// key operation, this function returns an error.
+    pub fn accept<S>(&self, stream: S) -> Result<TlsStream<Server, S>, Error>
     where
         S: Read + Write + Send + 'static,
     {
         let mut conn = self.ctx.new_server_connection().build();
         conn.set_io(StdIoWithReactor::new(stream, NoAsync))?;
-        conn.do_handshake()?;
+        if let Some(reason) = conn.do_handshake()? {
+            return Err(Error::Unknown(Box::new(reason)));
+        }
 
         Ok(TlsStream {
             conn,