Проблема с OpenSSL
От: i3F  
Дата: 10.12.13 10:35
Оценка:
Есть программа, использует WinInet, нормально общается с сервером в интернете по HTTPS.
Чтобы иметь больший контроль над сокетами хочется отказаться от WinInet, создавать и настраивать сокеты вручную, поддержку HTTPS реализовать, например, с помощью OpenSSL.
Тут обнаруживается проблема: через примерно 40-50 секунд после установления соединения вызов SSL_read возвращает 0,
при этом
SSL_get_error() = 5 (SSL_ERROR_SYSCALL)
ERR_get_error() = 0
WSAGetLastError() = 0
GetLastError() = 0
errno = 0


Судя по обсуждениям в интеренете причиной может быть закрытие соединения сервером.
Пока не догадываюсь, как искать причину такого поведения сервера.
Напоминаю, что WinInet-версия приложения работает без таких проблем, так что ошибка скорее всего наведена клиентским приложением.

Сокеты создаю обычной командой
WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0 );
Каких-то особенных опций сокету не выставляю.

В HTTP-запросах "Connection: Keep-Alive" указываю (хоть для HTTP 1.1 это не принципиально).
Приложение отправляет запрос на сервер и получает ответ не реже 1 раза в секунду.
Вообще, формы НТТР-запросов подсмотрел фидлером у WinInet-версии программы и использую их в OpenSSL-версии.
Только cookie из запросов выбросил, но уверен на 99,9% что дело не в них.

Возможно дело в неправильном использовании OpenSSL?
Работаю с ним впервые.
Какие могут быть идеи, в чем может быть проблема или как её искать?

Основной поток вызывает
SSL_load_error_strings();
SSL_library_init();
SSL_CTX *sslContext = SSL_CTX_new( SSLv23_client_method() );


Далее основной поток создаёт 2 соединения
SOCKET socket[ 2 ];
SSL* sslHandle[ 2 ];
for ( int i = 0; i < 2; ++i ) {
    socket[ i ] = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0 );
    connect( socket[ i ], &saddr, sizeof( saddr ) );
    sslHandle[ i ] = SSL_new( sslContext );
    SSL_set_fd( sslHandle[ i ], socket[ i ] );
    SSL_connect( sslHandle[ i ] );
}


Эти 2 соединения будут использоваться паралельно и независимо друг от друга.
Например, как если бы они были установлены разными браузерами или даже установлены с разных компьютеров.

После чего основной поток использует первое соединение
SSL_write( sslHandle[0], ... )
SSL_read( sslHandle[0], ... )


Второй поток использует второе соединение
SSL_write( sslHandle[1], ... )
SSL_read( sslHandle[1], ... )


Оба потока успешно выполняют положенную работу:
SSL_write возвращает управление мгновенно (видимо, копирует данные в локальные буферы),
SSL_read (вызванный сразу после выхода из SSL_write) возвращает управление через несколько сотен миллисекунд, когда приходит ответ из сети.

Через 40-50 секунд всё ломается.
SSL_write возвращает правильное число записанных байт.
После чего SSL_read немедленно возвращает 0.
SSL_get_error() возвращает SSL_ERROR_SYSCALL.

Использую
VC++ 2010
Win32 OpenSSL v1.0.1e

Приложение линкуется статически с библиотеками
...\OpenSSL-Win32\lib\VC\static\libeay32MT.lib
...\OpenSSL-Win32\lib\VC\static\ssleay32MT.lib

Как думаете, в чем может быть проблема или как искать причину сбоя?
Re: Проблема с OpenSSL
От: okman Беларусь https://searchinform.ru/
Дата: 10.12.13 10:49
Оценка: 2 (1)
Здравствуйте, i3F, Вы писали:

i3F>...


i3F>Как думаете, в чем может быть проблема или как искать причину сбоя?


1. Не знаток OpenSSL, но в приведенном коде смущает то, что один объект SSL_CTX
используется для двух сокетов.

2. Попробуйте все-таки проверить так, чтобы ваши запросы совпадали с запросами от
WinInet, включая cookie и keep-alive.

3. Написать еще один вариант этого кода, использующий, к примеру, Boost.Asio (там
есть поддержка OpenSSL) и сравнить полученные результаты.
Re: Проблема с OpenSSL
От: Mиxa Украина  
Дата: 10.12.13 10:54
Оценка: 13 (2)
Здравствуйте, i3F, Вы писали:

i3F>Судя по обсуждениям в интеренете причиной может быть закрытие соединения сервером.

i3F>Пока не догадываюсь, как искать причину такого поведения сервера.
i3F>Напоминаю, что WinInet-версия приложения работает без таких проблем, так что ошибка скорее всего наведена клиентским приложением.

WinInet может молча пересоздавать соединение, он такой.
Посмотри тем же фидлером, что там с соединением происходит.
Re[2]: Проблема с OpenSSL
От: i3F  
Дата: 10.12.13 17:10
Оценка:
Здравствуйте, Mиxa, Вы писали:

M>WinInet может молча пересоздавать соединение, он такой.

M>Посмотри тем же фидлером, что там с соединением происходит.

Вы правы, подержал фидлер несколько минут, видны периодические (как раз через ~40 секунд) реконнекты.
Спасибо!
Теперь надо понять, почему эти реконнекты происходят.
Попробую с техподдержкой сервера пообщаться.
Re[2]: Проблема с OpenSSL
От: SkyDance Земля  
Дата: 10.12.13 23:15
Оценка: 2 (1)
O>1. Не знаток OpenSSL, но в приведенном коде смущает то, что один объект SSL_CTX
O>используется для двух сокетов.

Так и должно быть, CTX (context) — это, по сути, объект, который держит сертификаты, настройки шифров и т.п.. Потом из одного контекста нужно спавнить сколько угодно соединений с одинаковыми сертификатами.
Re[3]: Проблема с OpenSSL
От: Mиxa Украина  
Дата: 11.12.13 10:06
Оценка: 2 (1)
Здравствуйте, i3F, Вы писали:

i3F>Теперь надо понять, почему эти реконнекты происходят.

i3F>Попробую с техподдержкой сервера пообщаться.

А зачем вообще низкий уровень потребовался? Если WinInet не устраивает, то есть еще WinHTTP. Да и cURL в конце-концов.
Re[4]: Проблема с OpenSSL
От: i3F  
Дата: 11.12.13 10:25
Оценка:
Здравствуйте, Mиxa, Вы писали:

M>Здравствуйте, i3F, Вы писали:


i3F>>Теперь надо понять, почему эти реконнекты происходят.

i3F>>Попробую с техподдержкой сервера пообщаться.

M>А зачем вообще низкий уровень потребовался? Если WinInet не устраивает, то есть еще WinHTTP. Да и cURL в конце-концов.



Нужно указать используемый локальный сетевой интерфейс.
bind() требует знания сокета.

Нужно отключить алоритм Нагла.
Вроде как WinInet в моем случае нагла выключает (хук на setsocketopt это показывает), но нет уверенности, что WinInet всегда так делает.
Re[5]: Проблема с OpenSSL
От: Mиxa Украина  
Дата: 11.12.13 10:48
Оценка: 2 (1)
Здравствуйте, i3F, Вы писали:

M>>А зачем вообще низкий уровень потребовался? Если WinInet не устраивает, то есть еще WinHTTP. Да и cURL в конце-концов.


i3F>Нужно указать используемый локальный сетевой интерфейс.

i3F>Нужно отключить алоритм Нагла.

cURL это все позволяет делать. CURLOPT_INTERFACE и CURLOPT_TCP_NODELAY.
Re: Проблема с OpenSSL
От: neokoder  
Дата: 12.12.13 09:43
Оценка: 2 (1)
Здравствуйте, i3F, Вы писали:
i3F>Как думаете, в чем может быть проблема или как искать причину сбоя?

Прежде чем общаться с техподдержкой сервера проверьте правильно ли у вас всё с I/O:
1) Сокеты блокируемые?
2) SSL_ERROR_WANT_READ,SSL_ERROR_WANT_READ обрабатываете?
В общем если подробнее код вашего I/O покажете, тогда можно о чем-то говорить.

Хотя если отключате Nagle, то могут и отсюда какие-то проблемы. Вроде как отключение Nagle может быть опциональным как с стороны клиента так и сервера. Так вот если в вашем случае отключение идёт только с клиентской стороны могут быть и в связи с этим какие-то проблемы.
Re: Проблема с OpenSSL
От: neokoder  
Дата: 12.12.13 09:46
Оценка: 2 (1)
Пробовали без отключения Nagle, чтобы исключить это вариант?
Re[2]: Проблема с OpenSSL
От: SkyDance Земля  
Дата: 12.12.13 22:51
Оценка: 2 (1) +2
N>Пробовали без отключения Nagle, чтобы исключить это вариант?

Господа.
Оставьте вы этого Нагла в покое.

В 99.99% случаев его включение-выключение не влияет ни на что. Иногда я вообще жалею, что программистам дали простую возможность эту опцию дёргать.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.