ApiListener#NewClientHandlerInternal(): on basic_socket#cancel() (due to timeout) don't ssl::stream#async_shutdown()

If a connection hangs for too long in ApiListener#NewClientHandler(),
ApiListener#AddConnection()'s Timeout calls boost::asio::basic_socket#cancel()
on that connection to trigger an exception which unwinds
ApiListener#NewClientHandler(). Previously that unwind could trigger a Defer
which called boost::asio::ssl::stream#async_shutdown() which extended the hang.
This commit is contained in:
Alexander A. Klimov 2023-03-21 10:57:40 +01:00
parent cf517050bc
commit 4c154f93dc
1 changed files with 49 additions and 41 deletions

View File

@ -734,46 +734,8 @@ void ApiListener::NewClientHandlerInternal(
ClientType ctype; ClientType ctype;
if (role == RoleClient) { try {
JsonRpc::SendMessage(client, new Dictionary({ if (role == RoleClient) {
{ "jsonrpc", "2.0" },
{ "method", "icinga::Hello" },
{ "params", new Dictionary({
{ "version", (double)l_AppVersionInt },
{ "capabilities", (double)l_MyCapabilities }
}) }
}), yc);
client->async_flush(yc);
ctype = ClientJsonRpc;
} else {
{
boost::system::error_code ec;
if (client->async_fill(yc[ec]) == 0u) {
if (identity.IsEmpty()) {
Log(LogInformation, "ApiListener")
<< "No data received on new API connection " << conninfo << ". "
<< "Ensure that the remote endpoints are properly configured in a cluster setup.";
} else {
Log(LogWarning, "ApiListener")
<< "No data received on new API connection " << conninfo << " for identity '" << identity << "'. "
<< "Ensure that the remote endpoints are properly configured in a cluster setup.";
}
return;
}
}
char firstByte = 0;
{
asio::mutable_buffer firstByteBuf (&firstByte, 1);
client->peek(firstByteBuf);
}
if (firstByte >= '0' && firstByte <= '9') {
JsonRpc::SendMessage(client, new Dictionary({ JsonRpc::SendMessage(client, new Dictionary({
{ "jsonrpc", "2.0" }, { "jsonrpc", "2.0" },
{ "method", "icinga::Hello" }, { "method", "icinga::Hello" },
@ -787,8 +749,54 @@ void ApiListener::NewClientHandlerInternal(
ctype = ClientJsonRpc; ctype = ClientJsonRpc;
} else { } else {
ctype = ClientHttp; {
boost::system::error_code ec;
if (client->async_fill(yc[ec]) == 0u) {
if (identity.IsEmpty()) {
Log(LogInformation, "ApiListener")
<< "No data received on new API connection " << conninfo << ". "
<< "Ensure that the remote endpoints are properly configured in a cluster setup.";
} else {
Log(LogWarning, "ApiListener")
<< "No data received on new API connection " << conninfo << " for identity '" << identity << "'. "
<< "Ensure that the remote endpoints are properly configured in a cluster setup.";
}
return;
}
}
char firstByte = 0;
{
asio::mutable_buffer firstByteBuf (&firstByte, 1);
client->peek(firstByteBuf);
}
if (firstByte >= '0' && firstByte <= '9') {
JsonRpc::SendMessage(client, new Dictionary({
{ "jsonrpc", "2.0" },
{ "method", "icinga::Hello" },
{ "params", new Dictionary({
{ "version", (double)l_AppVersionInt },
{ "capabilities", (double)l_MyCapabilities }
}) }
}), yc);
client->async_flush(yc);
ctype = ClientJsonRpc;
} else {
ctype = ClientHttp;
}
} }
} catch (const boost::system::system_error& systemError) {
if (systemError.code() == boost::asio::error::operation_aborted) {
shutDownIfNeeded.Cancel();
}
throw;
} }
if (ctype == ClientJsonRpc) { if (ctype == ClientJsonRpc) {