Mono 上的 SslStream 未完全关闭
SslStream on Mono not fully closing
我目前正在使用我们设计用于与 Xamarin 移动应用程序通信的服务器应用程序。我们正在使用一个旧的消息传递库,它与 TcpClient
建立连接并保持连接打开(每 3 秒发送一次心跳消息)。我们通过用 SslStream
包装 TcpClient
流来将 SSL 添加到库中。我们在 Windows 上有 运行 服务器应用程序并且运行良好,但我们的最终目标是 Mono
在 BeagleBoneBlack 上。
但是,当我们在移动应用端关闭流和客户端,然后尝试重新发起新连接时,SslStream.AuthenticateAsServer(...)
将不会在服务器端完成。但是,如果我完全关闭移动应用程序,服务器将抛出异常。那时,我重新打开应用程序,并且可以毫无问题地重新连接。
所以似乎在应用程序或服务器端都没有关闭一些低级别的东西。奇怪的是,当服务器在 windows 上 运行 并且我没有问题时,我 运行 两者上的代码完全相同。
这是我的代码,closes/disposes 流
public async Task Disconnect()
{
if (!UseAsync)
{
semaphore.Wait();
}
try
{
if (UseSSL)
{
SslStream?.Close();
}
Client?.GetStream()?.Close();
Client?.Close();
}
catch (Exception ex) // Assuming we had an exception from trying to close the sslstream
{
logger.Error(ex, "Did not close/dispose correctly: {0}", ex.ToString());
}
finally
{
SslStream = null;
Client = null;
if (!UseAsync)
{
semaphore.Release();
}
}
}
编辑: 这应该不是什么大问题,因为问题似乎出在服务器的某个地方,而且客户端和服务器的 ssl 代码几乎相同,但万一有人问, 这是客户端断开代码
public async Task Disconnect()
{
try
{
if (UseSSL)
{
_sslStream?.Close();
}
Client?.GetStream()?.Close();
Client?.Close();
}
catch // Assuming we had an exception from trying to close the sslstream
{
// Ignore exceptions since we've already closed them
}
finally
{
_sslStream = null;
Client = null;
}
}
编辑 2
还应注意,我发现至少一个 bug report 看起来与我正在处理的问题相同。从这个错误报告来看,它似乎没有得到解决,但我发现其他报告似乎反映了 mono 框架中的类似问题,并且已解决。此外,我添加了代码以在似乎没有影响的连接蚂蚁之后从客户端发送一些 "dummy" 数据。
编辑 3: 我最终在客户端收到此异常
System.IO.IOException: The authentication or decryption has failed. ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: The authentication or decryption has failed.
at Mono.Security.Protocol.Tls.RecordProtocol.EndReceiveRecord (System.IAsyncResult asyncResult) [0x0003a] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:430
at Mono.Security.Protocol.Tls.SslClientStream.SafeEndReceiveRecord (System.IAsyncResult ar, System.Boolean ignoreEmpty) [0x00000] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:256
at Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker (System.IAsyncResult result) [0x00360] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:533
好吧......我几乎觉得回答这个问题很愚蠢,但我觉得其他人可能会因为同样的无知而陷入我的境地,所以希望这可以帮助具有类似架构的人。
发生的事情是我创建了一个自签名证书并将其放在我的项目文件夹中,因此我的所有 "server" 实例都使用了相同的证书。发生的事情是,由于 SSL 会话缓存的一些内部缓存,在连接到一个设备后,它将缓存其信息,然后 re-use 下次连接时该信息。结果是,由于 self-signed 证书对所有设备使用相同的主机名,一旦它在连接到设备 A 后尝试重新连接到设备 B,它将尝试 re-use 设备 A 的缓存信息(据我所知)这最初没有意义的原因是我可以一遍又一遍地连接和断开连接到多个不同的 Windows 服务器,但只有在连接到 Mono 服务器时我才看到这个问题。结果,它似乎仍然是 Windows 或 Mono 的 SSLStream 实现中的一个错误(因为在完美的世界中,它们是相同的),但不幸的是我没有时间深入研究 de-compiled源码找吧。坦率地说,这可能并不重要,因为 我所做的无论如何都打破了 SSL 连接的整个概念。
最终,我创建了一个函数,使用 Mono.Security 以编程方式为每个设备生成唯一证书,然后提供一种机制为客户端提供唯一主机名(即使客户端直接连接到 IP地址)。
我目前正在使用我们设计用于与 Xamarin 移动应用程序通信的服务器应用程序。我们正在使用一个旧的消息传递库,它与 TcpClient
建立连接并保持连接打开(每 3 秒发送一次心跳消息)。我们通过用 SslStream
包装 TcpClient
流来将 SSL 添加到库中。我们在 Windows 上有 运行 服务器应用程序并且运行良好,但我们的最终目标是 Mono
在 BeagleBoneBlack 上。
但是,当我们在移动应用端关闭流和客户端,然后尝试重新发起新连接时,SslStream.AuthenticateAsServer(...)
将不会在服务器端完成。但是,如果我完全关闭移动应用程序,服务器将抛出异常。那时,我重新打开应用程序,并且可以毫无问题地重新连接。
所以似乎在应用程序或服务器端都没有关闭一些低级别的东西。奇怪的是,当服务器在 windows 上 运行 并且我没有问题时,我 运行 两者上的代码完全相同。
这是我的代码,closes/disposes 流
public async Task Disconnect()
{
if (!UseAsync)
{
semaphore.Wait();
}
try
{
if (UseSSL)
{
SslStream?.Close();
}
Client?.GetStream()?.Close();
Client?.Close();
}
catch (Exception ex) // Assuming we had an exception from trying to close the sslstream
{
logger.Error(ex, "Did not close/dispose correctly: {0}", ex.ToString());
}
finally
{
SslStream = null;
Client = null;
if (!UseAsync)
{
semaphore.Release();
}
}
}
编辑: 这应该不是什么大问题,因为问题似乎出在服务器的某个地方,而且客户端和服务器的 ssl 代码几乎相同,但万一有人问, 这是客户端断开代码
public async Task Disconnect()
{
try
{
if (UseSSL)
{
_sslStream?.Close();
}
Client?.GetStream()?.Close();
Client?.Close();
}
catch // Assuming we had an exception from trying to close the sslstream
{
// Ignore exceptions since we've already closed them
}
finally
{
_sslStream = null;
Client = null;
}
}
编辑 2
还应注意,我发现至少一个 bug report 看起来与我正在处理的问题相同。从这个错误报告来看,它似乎没有得到解决,但我发现其他报告似乎反映了 mono 框架中的类似问题,并且已解决。此外,我添加了代码以在似乎没有影响的连接蚂蚁之后从客户端发送一些 "dummy" 数据。
编辑 3: 我最终在客户端收到此异常
System.IO.IOException: The authentication or decryption has failed. ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: The authentication or decryption has failed.
at Mono.Security.Protocol.Tls.RecordProtocol.EndReceiveRecord (System.IAsyncResult asyncResult) [0x0003a] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:430
at Mono.Security.Protocol.Tls.SslClientStream.SafeEndReceiveRecord (System.IAsyncResult ar, System.Boolean ignoreEmpty) [0x00000] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:256
at Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker (System.IAsyncResult result) [0x00360] in /Users/builder/data/lanes/3511/501e63ce/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:533
好吧......我几乎觉得回答这个问题很愚蠢,但我觉得其他人可能会因为同样的无知而陷入我的境地,所以希望这可以帮助具有类似架构的人。
发生的事情是我创建了一个自签名证书并将其放在我的项目文件夹中,因此我的所有 "server" 实例都使用了相同的证书。发生的事情是,由于 SSL 会话缓存的一些内部缓存,在连接到一个设备后,它将缓存其信息,然后 re-use 下次连接时该信息。结果是,由于 self-signed 证书对所有设备使用相同的主机名,一旦它在连接到设备 A 后尝试重新连接到设备 B,它将尝试 re-use 设备 A 的缓存信息(据我所知)这最初没有意义的原因是我可以一遍又一遍地连接和断开连接到多个不同的 Windows 服务器,但只有在连接到 Mono 服务器时我才看到这个问题。结果,它似乎仍然是 Windows 或 Mono 的 SSLStream 实现中的一个错误(因为在完美的世界中,它们是相同的),但不幸的是我没有时间深入研究 de-compiled源码找吧。坦率地说,这可能并不重要,因为 我所做的无论如何都打破了 SSL 连接的整个概念。
最终,我创建了一个函数,使用 Mono.Security 以编程方式为每个设备生成唯一证书,然后提供一种机制为客户端提供唯一主机名(即使客户端直接连接到 IP地址)。