客户端会执行一些ssl::stream<tcp_socket>::async_read_some()
/ ssl::stream<tcp_socket>::async_write()
次呼叫,并且在某些时候需要退出,即需要关闭连接。
调用ssl::stream<tcp_socket>::lowest_layer().close()
有效,但(正如预期的那样)服务器(openssl s_server -state ...
命令)报告关闭连接时出错。
以正确的方式查看API似乎是致电ssl::stream<tcp_socket>::async_shutdown()
。
现在基本上有两种情况需要关机:
1)客户端处于async_read_some()
回调状态,并对“退出”做出反应。来自服务器的命令。从async_shutdown()
拨打电话会产生“短暂阅读”。关机回调中的错误。
这是令人惊讶的,但在谷歌搜索后似乎是正常的行为 - 似乎必须检查它是否是一个真正的错误或不是这样:
// const boost::system::error_code &ec
if (ec.category() == asio::error::get_ssl_category() &&
ec.value() == ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ)) {
// -> not a real error, just a normal TLS shutdown
}
TLS服务器似乎很高兴 - 它报告:
DONE
shutting down SSL
CONNECTION CLOSED
2)async_read_some()
处于活动状态 - 但用户决定退出客户端(例如,通过stdin命令)。以下情况从该上下文调用async_shutdown()
后:
async_read_some()
回调是通过&#39;短读取来执行的。错误代码 - 现在有点预期async_shutdown()
回调 - 这是意外的服务器端不报告错误。
因此,我的问题是如何使用boost asio正确关闭TLS客户端。
答案 0 :(得分:6)
解决“解密失败”或“错误记录mac”的一种方法是&#39;第二个上下文的错误代码是:
a)从stdin处理程序调用内部:
ssl::stream<tcp_socket>::lowest_layer()::shutdown(tcp::socket::shutdown_receive)
b)这导致async_read_some()
回调通过“短读”来执行。 &#39;错误&#39;代码
async_shutdown()
被称为:
// const boost::system::error_code &ec
if (ec.category() == asio::error::get_ssl_category() &&
ec.value() == ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ)) {
// -> not a real error:
do_ssl_async_shutdown();
}
d)async_shutdown()
回调是通过&#39;短读取来执行的。错误代码,我们最终调用的地方:
ssl::stream::lowest_layer()::close()
这些步骤导致连接关闭,而客户端或服务器端没有任何奇怪的错误消息。
例如,当使用openssl s_server -state ...
作为服务器时,它会报告sutdown:
SSL3 alert read:warning:close notify DONE shutting down SSL CONNECTION CLOSED ACCEPT
(最后一行是因为命令接受新连接)
我们也可以调用
代替lowest_layer()::shutdown(tcp::socket::shutdown_receive)
ssl::stream<tcp_socket>::lowest_layer()::cancel()
启动正常关机。它具有相同的效果,即它产生预定的async_read_some()
回调的执行(但具有operation_aborted
错误代码)。因此,可以从那里调用async_shutdown()
:
if (ec.value() == asio::error::operation_aborted) {
cout << "(not really an error)\n";
do_async_ssl_shutdown();
}