SSL_connect在Windows上生成带有WSAENOTCONN的SSL_ERROR_SYSCALL

时间:2014-06-17 12:39:15

标签: c++ sockets ssl tcp openssl

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

  1. 创建TCP套接字BIO。
  2. 使用TCP连接到服务器。
  3. 将此BIO添加到SSL实例。
  4. 升级到SSL的连接。
  5. 但是,当我尝试用最近确定连接到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();
        }
    }
    

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

1 个答案:

答案 0 :(得分:1)

如果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);