docs: private SSLEngineResult doHandshake(MyHandshakeCompletedCallback hsCallback) throws IOException {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.entry(tc, "doHandshake");
          }
          SSLEngineResult sslResult;
          SSLEngine sslEngine = getConnLink().getSSLEngine();
          // Line up all the buffers needed for the SSL handshake. Temporary so use
          // indirect allocation for speed.
          WsByteBuffer netBuffer = SSLUtils.allocateByteBuffer(
                                                               sslEngine.getSession().getPacketBufferSize(), true);
          WsByteBuffer decryptedNetBuffer = SSLUtils.allocateByteBuffer(
                                                                        sslEngine.getSession().getApplicationBufferSize(), false);
          try {
              getEncryptedAppBuffer(1);
          } catch (IOException up) {
              // Release buffers used in the handshake.
              netBuffer.release();
              decryptedNetBuffer.release();
              throw up;
          }
  
          if (hsCallback != null) {
              // If the callback is non null, update the callback with the buffers it
              // will have to release.
              hsCallback.setNetBuffer(netBuffer);
              hsCallback.setDecryptedNetBuffer(decryptedNetBuffer);
          }
          try {
              // Do the SSL handshake. Note, if synchronous the handshakeCallback is null.
              sslResult = SSLUtils.handleHandshake(
                                                   getConnLink(),
                                                   netBuffer,
                                                   decryptedNetBuffer,
                                                   this.encryptedAppBuffer,
                                                   null,
                                                   hsCallback,
                                                   false);
          } catch (IOException e) {
              // Release buffers used in the handshake.
              netBuffer.release();
              decryptedNetBuffer.release();
              throw e;
          } catch (ReadOnlyBufferException robe) {
              // Release buffers used in the handshake.
              netBuffer.release();
              decryptedNetBuffer.release();
              throw new IOException("Caught exception during handshake: " + robe.getMessage(), robe);
          }
          if (sslResult != null) {
              // Handshake was done synchronously.
              // Release buffers used in the handshake.
              netBuffer.release();
              decryptedNetBuffer.release();
          }
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.exit(tc, "doHandshake: " + sslResult);
          }
          return sslResult;
      }