precio - boost:: asio y async SSL: ¿cómo detectar el cierre de fin de datos/conexión?
let''s encrypt (2)
El error SSL_R_SHORT_READ
se espera aquí. Cuando el servidor inicia un cierre limpio con SSL_Shutdown
esto envía la alerta de cierre de notificación de cierre al cliente. La implementación de Asio asigna esto a un error SSL_R_SHORT_READ
con la categoría de error::get_ssl_category()
. Lo hace detectando si el par ha iniciado el cierre a través de SSL_get_shutdown
.
Esto se puede ver al inspeccionar el encabezado asio/ssl/detail/impl/engine.ipp
y específicamente la función engine::map_error_code(boost::system::error_code&)
.
Creo que la implementación de SSL se reescribió en el impulso 1.47, por lo que las versiones anteriores tienen un comportamiento potencialmente diferente.
Estoy tratando de hacer amigos asio y SSL. Todo va bien, pero una cosa está causando inconvenientes: ¿cómo detectar si un compañero está cercano a la conexión y distinguirlo de la situación cuando está solo tomando un breve descanso en el envío de datos, con el objetivo de continuar unos pocos segundos después?
- impulso 1.48
- OpenSSL 1.0.0e
- Compilado a código de 32 bits utilizando VS10
- Trabajando en W7 x64.
Mi confusión proviene del hecho de que el comportamiento de asio es diferente para el socket ordinario y el flujo SSL. Si utilizo tcp :: socket, recibo un error EOF cuando la conexión cercana es similar. Pero para boost :: asio :: ssl :: stream - no es el caso. En su lugar, async_read_some devuelve 0 como bytes transferidos, y si intento continuar leyendo desde SSL stream - devuelve short_error ( http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/streams.html ).
Entonces, la pregunta es: ¿es el comportamiento esperado o configuro mal algo?
Fragmento de código de cliente:
class client
{
public:
// bla-bla-bla-bla-bla ....
//
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(boost::asio::buffer(reply_, max_length),
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "Write failed: " << error.message() << "/n";
}
}
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
std::cout << "Bytes transfered: " << bytes_transferred << "/n";
if (!error)
{
std::cout << "Reply: ";
std::cout.write(reply_, bytes_transferred);
std::cout << "/n";
std::cout << "Reading.../n";
socket_.async_read_some(boost::asio::buffer(reply_, max_length),
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else if (0 != bytes_transferred)
{
std::cout << "Read failed: " << error.message() << ":"
<< error.value() << "/n";
}
}
private:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
boost::asio::streambuf request_;
char reply_[max_length];
};
Si eliminamos if (0! = Bytes_transferred), obtendremos una "lectura corta" :(.
Si usaremos el código as-ai, la salida será algo como esto:
La solicitud es:
GET / HTTP / 1.0
Galleta: Nama-nama = Vala-vala
Bytes transferidos: 1024
Respuesta: HTTP / 1.0 200 ok Tipo de contenido: texto / html
..... bla bla bla ....
Leyendo ... Bytes transferidos: 1024
..... bla-bla-bla .... ..... bla-bla-bla ....
Leyendo ... Bytes transferidos: 482
..... bla bla bla ....
Leyendo...
Bytes transferidos: 0
Al mismo tiempo, si en lugar de async_read_some escribimos código, lo que para un socket ordinario devolverá EOF:
boost::asio::async_read(socket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&client::handle_read_content, this,
boost::asio::placeholders::error));
luego para SSL-socket obtendremos 0 como bytes transferidos, y luego short_read.
Sé que no hay forma de detectar la desconexión en caso de que, por ejemplo, un par simplemente haya sido desconectado de la red. Pero, ¿cómo detectar la desconexión explícita entre pares de la situación cuando los pares simplemente no envían datos por un tiempo, pero pueden hacerlo un poco más tarde?
O bien, puede ser que no entiendo algo?
WBR, Andrey
Algún addentum: SSL / TLS tiene una notación para informar a la otra parte sobre el cierre de la conexión. Es close_notify alerta. También se puede cerrar el socket TCP subyacente.
Entonces, básicamente, mi pregunta es: por qué, en las mismas condiciones (TCP socket se cerró claramente) Recibo EOF en caso de tcp :: socket, y no recibo nada por boost :: asio :: ssl :: stream.
¿Es bug o asio característica?
Otro addentum: por algunos motivos, asio no me dio un EOF ni si SSL recibe close_notify ni se cierra el socket TCP subyacente.
Sí, puedo detectar conexiones muertas por tiempo de espera. Pero, ¿cómo puedo detectar conexiones SSL cerradas correctamente? ¿Recibiendo short_read?
Usted puede estar interesado en estas discusiones:
- cómo detectar una desconexión del socket TCP (con el conector c berkeley)
- Cierre correctamente SSLSocket
Esencialmente, el hecho de que obtengas un EOF a veces (incluso la mayoría de las veces) cuando la parte remota desconecta un simple socket TCP es solo suerte. No puede confiar en ello en el caso general, ya que no es posible distinguir entre un socket inactivo y un socket cerrado de forma abrupta sin escribir en él.
Debe definir algunos delimitadores, en el nivel de protocolo de la aplicación, para saber cuándo dejar de leer. En HTTP, esto se hace a través de la línea en blanco que termina el encabezado (para el encabezado), el encabezado Content-Length
que define la longitud del cuerpo, o los delimitadores de codificación de transferencia fragmentada cuando la longitud del cuerpo no se conoce de antemano.