int SSLconnect::sslHandshake()

in nlsCppSdk/transport/SSLconnect.cpp [81:184]


int SSLconnect::sslHandshake(int socketFd, const char *hostname) {
  // LOG_DEBUG("Begin sslHandshake.");
  if (_sslCtx == NULL) {
    LOG_ERROR("SSL(%p) _sslCtx has been released.", this);
    return -(SslCtxEmpty);
  }

  MUTEX_LOCK(_mtxSSL);

  int ret;
  if (_ssl == NULL) {
    _ssl = SSL_new(_sslCtx);
    if (_ssl == NULL) {
      memset(_errorMsg, 0x0, MaxSslErrorLength);
      const char *SSL_new_ret = "return of SSL_new: ";
      const int SSL_new_str_size = strnlen(SSL_new_ret, 24);
      memcpy(_errorMsg, SSL_new_ret, SSL_new_str_size);
      ERR_error_string_n(ERR_get_error(), _errorMsg + SSL_new_str_size,
                         MaxSslErrorLength - SSL_new_str_size - 1);
      LOG_ERROR("SSL(%p) Invoke SSL_new failed:%s.", this, _errorMsg);
      MUTEX_UNLOCK(_mtxSSL);
      return -(SslNewFailed);
    } else {
      if (hostname) {
        if (!SSL_set_tlsext_host_name(_ssl, hostname)) {
          LOG_ERROR("Error setting SNI host name");
        } else {
          LOG_INFO("Set SNI %s success", hostname);
        }
      }
    }

    ret = SSL_set_fd(_ssl, socketFd);
    if (ret == 0) {
      memset(_errorMsg, 0x0, MaxSslErrorLength);
      const char *SSL_set_fd_ret = "return of SSL_set_fd: ";
      const int SSL_set_fd_str_size = strnlen(SSL_set_fd_ret, 24);
      memcpy(_errorMsg, SSL_set_fd_ret, SSL_set_fd_str_size);
      ERR_error_string_n(ERR_get_error(), _errorMsg + SSL_set_fd_str_size,
                         MaxSslErrorLength - SSL_set_fd_str_size - 1);
      LOG_ERROR("SSL(%p) Invoke SSL_set_fd failed:%s.", this, _errorMsg);
      MUTEX_UNLOCK(_mtxSSL);
      return -(SslSetFailed);
    }

    SSL_set_mode(_ssl, SSL_MODE_ENABLE_PARTIAL_WRITE |
                           SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
                           SSL_MODE_AUTO_RETRY);

    SSL_set_connect_state(_ssl);
  } else {
    // LOG_DEBUG("SSL has existed.");
  }

  ret = SSL_connect(_ssl);
  if (ret < 0) {
    int sslError = SSL_get_error(_ssl, ret);

    /* err == SSL_ERROR_ZERO_RETURN
       "SSL_connect: close notify received from peer" */
    // sslError == SSL_ERROR_WANT_X509_LOOKUP
    // SSL_ERROR_SYSCALL
    if (sslError == SSL_ERROR_WANT_READ || sslError == SSL_ERROR_WANT_WRITE) {
      // LOG_DEBUG("sslHandshake continue.");
      MUTEX_UNLOCK(_mtxSSL);
      return sslError;
    } else if (sslError == SSL_ERROR_SYSCALL) {
      int errno_code = utility::getLastErrorCode();
      LOG_INFO("SSL(%p) SSL connect error_syscall failed, errno:%d.", this,
               errno_code);

      if (NLS_ERR_CONNECT_RETRIABLE(errno_code) ||
          NLS_ERR_RW_RETRIABLE(errno_code)) {
        MUTEX_UNLOCK(_mtxSSL);
        return SSL_ERROR_WANT_READ;
      } else if (errno_code == 0) {
        LOG_DEBUG("SSL(%p) SSL connect syscall success.", this);
        MUTEX_UNLOCK(_mtxSSL);
        return Success;
      } else {
        MUTEX_UNLOCK(_mtxSSL);
        return -(SslConnectFailed);
      }
    } else {
      memset(_errorMsg, 0x0, MaxSslErrorLength);
      const char *SSL_connect_ret = "return of SSL_connect: ";
      const int SSL_connect_str_size = strnlen(SSL_connect_ret, 64);
      memcpy(_errorMsg, SSL_connect_ret, SSL_connect_str_size);
      ERR_error_string_n(ERR_get_error(), _errorMsg + SSL_connect_str_size,
                         MaxSslErrorLength - SSL_connect_str_size - 1);
      LOG_ERROR("SSL(%p) SSL connect failed:%s.", this, _errorMsg);
      MUTEX_UNLOCK(_mtxSSL);
      this->sslClose();
      return -(SslConnectFailed);
    }
  } else {
    // LOG_DEBUG("sslHandshake success.");
    MUTEX_UNLOCK(_mtxSSL);
    return Success;
  }

  MUTEX_UNLOCK(_mtxSSL);
  return Success;
}