bool AsyncSSLSocket::willBlock(
    int ret,
    int* sslErrorOut,
    unsigned long* errErrorOut) noexcept {
  *errErrorOut = 0;
  int error = *sslErrorOut = SSL_get_error(ssl_.get(), ret);
  if (error == SSL_ERROR_WANT_READ) {
    // Register for read event if not already.
    updateEventRegistration(EventHandler::READ, EventHandler::WRITE);
    return true;
  } else if (error == SSL_ERROR_WANT_WRITE) {
    VLOG(3) << "AsyncSSLSocket(fd=" << fd_ << ", state=" << int(state_)
            << ", sslState=" << sslState_ << ", events=" << eventFlags_ << "): "
            << "SSL_ERROR_WANT_WRITE";
    // Register for write event if not already.
    updateEventRegistration(EventHandler::WRITE, EventHandler::READ);
    return true;
  } else if ((false
#ifdef SSL_ERROR_WANT_ASYNC // OpenSSL 1.1.0 Async API
              || error == SSL_ERROR_WANT_ASYNC
#endif
              )) {
    // An asynchronous request has been kicked off. On completion, it will
    // invoke a callback to re-call handleAccept
    sslState_ = STATE_ASYNC_PENDING;

    // Unregister for all events while blocked here
    updateEventRegistration(
        EventHandler::NONE, EventHandler::READ | EventHandler::WRITE);

#ifdef SSL_ERROR_WANT_ASYNC
    if (error == SSL_ERROR_WANT_ASYNC) {
      size_t numfds;
      if (SSL_get_all_async_fds(ssl_.get(), NULL, &numfds) <= 0) {
        VLOG(4) << "SSL_ERROR_WANT_ASYNC but no async FDs set!";
        return false;
      }
      if (numfds != 1) {
        VLOG(4) << "SSL_ERROR_WANT_ASYNC expected exactly 1 async fd, got "
                << numfds;
        return false;
      }
      OSSL_ASYNC_FD ofd; // This should just be an int in POSIX
      if (SSL_get_all_async_fds(ssl_.get(), &ofd, &numfds) <= 0) {
        VLOG(4) << "SSL_ERROR_WANT_ASYNC cant get async fd";
        return false;
      }

      // On POSIX systems, OSSL_ASYNC_FD is type int, but on win32
      // it has type HANDLE.
      // Our NetworkSocket::native_handle_type is type SOCKET on
      // win32, which means that we need to explicitly construct
      // a native handle type to pass to the constructor.
      auto native_handle = NetworkSocket::native_handle_type(ofd);

      auto asyncPipeReader =
          AsyncPipeReader::newReader(eventBase_, NetworkSocket(native_handle));
      auto asyncPipeReaderPtr = asyncPipeReader.get();
      if (!asyncOperationFinishCallback_) {
        asyncOperationFinishCallback_.reset(
            new DefaultOpenSSLAsyncFinishCallback(
                std::move(asyncPipeReader), this, DestructorGuard(this)));
      }
      asyncPipeReaderPtr->setReadCB(asyncOperationFinishCallback_.get());
    }
#endif

    // The timeout (if set) keeps running here
    return true;
  } else {
    unsigned long lastError = *errErrorOut = ERR_get_error();
    VLOG(6) << "AsyncSSLSocket(fd=" << fd_ << ", "
            << "state=" << state_ << ", "
            << "sslState=" << sslState_ << ", "
            << "events=" << std::hex << eventFlags_ << "): "
            << "SSL error: " << error << ", "
            << "errno: " << errno << ", "
            << "ret: " << ret << ", "
            << "read: " << BIO_number_read(SSL_get_rbio(ssl_.get())) << ", "
            << "written: " << BIO_number_written(SSL_get_wbio(ssl_.get()))
            << ", "
            << "func: " << ERR_func_error_string(lastError) << ", "
            << "reason: " << ERR_reason_error_string(lastError);
    return false;
  }
}