SSL_connect приводит к SSL_ERROR_SYSCALL с WSAENOTCONN в Windows

0

Я пытаюсь установить SSL-соединение в Windows с OpenSSL. Мои шаги следуют:

  1. Создать TCP-сокет BIO.
  2. Подключитесь к серверу с TCP.
  3. Добавьте этот экземпляр BIO в SSL.
  4. Обновите подключение к SSL.

Однако, когда я пытаюсь вызвать SSL_connect с BIO, который наверняка недавно подключен к сокету TCP, я получаю SSL_ERROR_SYSCALL с WSAENOTCONN в Windows.

Далее следует мой код.

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();
    }
}

Какова причина ошибки? Я понимаю, что это означает, что клиент отключен от сервера. Но я не понимаю, почему. У меня хорошее подключение к Интернету, а сервер также стабилен, поэтому маловероятно, что причина в сетевом подключении.

Теги:
ssl
sockets
openssl
tcp

1 ответ

1
Лучший ответ

Ваш цикл подключения TCP не учитывается, если BIO_do_connect() завершается с ошибкой, а BIO_should_retry() возвращает false. Ваш цикл остановится в этом состоянии, и у вас не будет подключения, но вы все равно попытаетесь активировать 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);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню