Close connection on IOExceptions.

The idea behind this is that if we receive a response which does not conform to the underlying protocol specification (with all the TCP checks in place!), we are in a weird/corrupt state and it is better to just close the connection.
This commit is contained in:
Serge Camille
2020-11-11 19:10:46 +01:00
parent 0b4c79cb08
commit 53045c5952
2 changed files with 35 additions and 10 deletions

View File

@@ -162,6 +162,7 @@ namespace S7.Net
if (tcpClient != null)
{
if (tcpClient.Connected) tcpClient.Close();
tcpClient = null; // Can not reuse TcpClient once connection gets closed.
}
}

View File

@@ -37,7 +37,7 @@ namespace S7.Net
return default(object);
}).ConfigureAwait(false);
}
catch(Exception)
catch (Exception)
{
stream.Dispose();
throw;
@@ -438,7 +438,7 @@ namespace S7.Net
private async Task ReadBytesWithSingleRequestAsync(DataType dataType, int db, int startByteAdr, byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
var dataToSend = BuildReadRequestPackage(new [] { new DataItemAddress(dataType, db, startByteAdr, count)});
var dataToSend = BuildReadRequestPackage(new[] { new DataItemAddress(dataType, db, startByteAdr, count) });
var s7data = await RequestTsduAsync(dataToSend, cancellationToken);
AssertReadResponse(s7data, count);
@@ -521,22 +521,46 @@ namespace S7.Net
NoLockRequestTsduAsync(stream, requestData, offset, length, cancellationToken));
}
private static async Task<COTP.TPDU> NoLockRequestTpduAsync(Stream stream, byte[] requestData,
private async Task<COTP.TPDU> NoLockRequestTpduAsync(Stream stream, byte[] requestData,
CancellationToken cancellationToken = default)
{
await stream.WriteAsync(requestData, 0, requestData.Length, cancellationToken).ConfigureAwait(false);
var response = await COTP.TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
try
{
using var closeOnCancellation = cancellationToken.Register(Close);
await stream.WriteAsync(requestData, 0, requestData.Length, cancellationToken).ConfigureAwait(false);
return await COTP.TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
}
catch (Exception exc)
{
if (exc is TPDUInvalidException || exc is TPKTInvalidException)
{
Close();
}
return response;
throw;
}
}
private static async Task<byte[]> NoLockRequestTsduAsync(Stream stream, byte[] requestData, int offset, int length,
private async Task<byte[]> NoLockRequestTsduAsync(Stream stream, byte[] requestData, int offset, int length,
CancellationToken cancellationToken = default)
{
await stream.WriteAsync(requestData, offset, length, cancellationToken).ConfigureAwait(false);
var response = await COTP.TSDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
try
{
using var closeOnCancellation = cancellationToken.Register(Close);
await stream.WriteAsync(requestData, offset, length, cancellationToken).ConfigureAwait(false);
return await COTP.TSDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
}
catch (Exception exc)
{
if (exc is TPDUInvalidException || exc is TPKTInvalidException)
{
Close();
}
return response;
throw;
}
}
}
}