#c #sockets #ssl #tcp #openssl
#c #сокеты #ssl #tcp #openssl
Вопрос:
Я пытаюсь установить SSL-соединение в Windows с помощью OpenSSL. Мои шаги следуют:
- Создайте биографию сокета TCP.
- Подключитесь к серверу с помощью TCP.
- Добавьте эту биографию в экземпляр SSL.
- Обновите соединение до 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 connectionResu<
while ((connectionResult = BIO_do_connect(this->TcpSocket)) <= 0 amp;amp; BIO_should_retry(this->TcpSocket))
{
auto retryType = BIO_retry_type(this->TcpSocket);
if (retryType amp; BIO_FLAGS_READ != 0
|| retryType amp; 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 amp; BIO_FLAGS_READ != 0)
select(handle 1, amp;handles, NULL, NULL, amp;timeout);
else
select(handle 1, NULL, amp;handles, NULL, amp;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 sslConnectResu<
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:
Ваш цикл TCP connect не учитывает BIO_do_connect()
сбой if и 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 amp; (BIO_FLAGS_READ | BIO_FLAGS_WRITE))
{
auto handle = BIO_get_fd(this->TcpSocket, NULL);
fd_set handles;
FD_ZERO(amp;handles);
FD_SET(handle, amp;handles);
timeval timeout;
timeout.tv_sec = seconds;
timeout.tv_usec = 0;
if (retryType amp; BIO_FLAGS_READ)
selectResult = select(handle 1, amp;handles, NULL, NULL, amp;timeout);
else
selectResult = select select(handle 1, NULL, amp;handles, NULL, amp;timeout);
if (selectResult < 0)
throw SocketException();
if (selectResult == 0)
throw SocketTimeoutException();
}
else
Thread::Sleep(50);
}
while (true);