c++ - SSL_connect 在 Windows 上导致 SSL_ERROR_SYSCALL 和 WSAENOTCONN

标签 c++ sockets ssl tcp openssl

我尝试在 Windows 上使用 OpenSSL 设置 SSL 连接。我的步骤如下:

  1. 创建 TCP 套接字 BIO。
  2. 使用 TCP 连接到服务器。
  3. 将此 BIO 添加到 SSL 实例。
  4. 将连接升级到 SSL。

但是,当我尝试使用确定最近连接到 TCP 套接字的 BIO 调用 SSL_connect 时,我在 Windows 上收到带有 WSAENOTCONN 的 SSL_ERROR_SYSCALL。

我的代码如下。

this->TcpSocket = BIO_new(BIO_s_connect());
BIO_set_nbio(this->TcpSocket, 1);
BIO_set_conn_hostname(this->TcpSocket, hostname);
BIO_set_conn_port(this->TcpSocket, port);
int connectionResult;
while ((connectionResult = BIO_do_connect(this->TcpSocket)) <= 0 && BIO_should_retry(this->TcpSocket))
{
        auto retryType = BIO_retry_type(this->TcpSocket);
        if (retryType & BIO_FLAGS_READ != 0
            || retryType & BIO_FLAGS_WRITE != 0)
        {
            auto handle = BIO_get_fd(this->TcpSocket, NULL);
            fd_set handles;
            handles.fd_count = 1;
            handles.fd_array[0] = handle;
            timeval timeout;
            timeout.tv_sec = seconds;
            timeout.tv_usec = 0;
            if (retryType & BIO_FLAGS_READ != 0)
                select(handle + 1, &handles, NULL, NULL, &timeout);
            else
                select(handle + 1, NULL, &handles, NULL, &timeout);
        }
        else
            Thread::Sleep(50);
}
this->SslContext = SSL_CTX_new(SSLv23_client_method());
SSL_CTX_set_verify(this->SslContext, SSL_VERIFY_NONE, NULL);
this->SslSocket = SSL_new(this->SslContext);
SSL_set_bio(this->SslSocket, this->TcpSocket, this->TcpSocket);
int sslConnectResult;
while ((sslConnectResult = SSL_connect(this->SslSocket)) == -1)
{
    auto now = time(NULL);
    int sslConnectErrorCode = SSL_get_error(this->SslSocket, sslConnectResult);
    switch (sslConnectErrorCode)
    {
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
        if (now >= deadline)
            throw SocketTimeoutException();
        else
            this->WaitForTcpSocket(deadline - now);
        break;
    case SSL_ERROR_SYSCALL:
        {
            auto err = GetLastError();
            this->RaiseOpenSSLException();
        }
        break;
    default:
        this->RaiseOpenSSLException();
    }
}

错误的原因是什么?我知道这意味着客户端与服务器断开连接。但我不明白为什么。我有良好的互联网连接,服务器也很稳定,所以不太可能是网络连接的原因。

最佳答案

如果 BIO_do_connect() 失败并且 BIO_should_retry() 返回 false,则您的 TCP 连接循环没有考虑在内。您的循环将在这种情况下停止并且您将没有连接,但您仍然尝试激活 SSL,这可能会导致 WSAENOTCONN 错误。

尝试更像这样的东西:

do
{
    connectionResult = BIO_do_connect(this->TcpSocket);
    if (connectionResult > 0)
        break;

    if (!BIO_should_retry(this->TcpSocket))
        throw SocketException();

    auto retryType = BIO_retry_type(this->TcpSocket);
    if (retryType & (BIO_FLAGS_READ | BIO_FLAGS_WRITE))
    {
        auto handle = BIO_get_fd(this->TcpSocket, NULL);
        fd_set handles;
        FD_ZERO(&handles);
        FD_SET(handle, &handles);
        timeval timeout;
        timeout.tv_sec = seconds;
        timeout.tv_usec = 0;
        if (retryType & BIO_FLAGS_READ)
            selectResult = select(handle + 1, &handles, NULL, NULL, &timeout);
        else
            selectResult = select select(handle + 1, NULL, &handles, NULL, &timeout);

        if (selectResult < 0)
            throw SocketException();

        if (selectResult == 0)
            throw SocketTimeoutException();
    }
    else
        Thread::Sleep(50);
}
while (true);

关于c++ - SSL_connect 在 Windows 上导致 SSL_ERROR_SYSCALL 和 WSAENOTCONN,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24264050/

相关文章:

c++ - 为什么要费心使用 Apache 或 Nginx 等?

c++ - 在 V8 中使用访问器的问题

linux - 从套接字写入输出

c++ - 如何在 LLVM 模块中增加全局变量?

java - ServerSocket可以在从客户端读取之前先写入客户端吗?

ios - Swift 4 OutputStream 产生的输出多于输入

php - 由于 SSL,无法检查站点是启动还是关闭

docker - 如何通过 Docker Compose 在 RabbitMQ 上使用 SSL?

html - nodejs https网站无法在IE11中显示

c++ - C++ 的 Option/Maybe 类